Files
zTC1/mico-os/libraries/utilities/URLUtils.c

231 lines
8.4 KiB
C

/**
******************************************************************************
* @file URLUtils.c
* @author William Xu
* @version V1.0.0
* @date 05-May-2014
* @brief This file contains function that aid in parsing URLs.
******************************************************************************
*
* The MIT License
* Copyright (c) 2014 MXCHIP Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
#include "common.h"
#include "debug.h"
#include "StringUtils.h"
#include "URLUtils.h"
#define url_utils_log(M, ...) custom_log("URLUtils", M, ##__VA_ARGS__)
//===========================================================================================================================
// URLParseComponents
//===========================================================================================================================
OSStatus URLParseComponents( const char *inSrc, const char *inEnd, URLComponents *outComponents, const char **outSrc )
{
const char * ptr;
const char * schemePtr;
const char * schemeEnd;
const char * userPtr;
const char * userEnd;
const char * passwordPtr;
const char * passwordEnd;
const char * hostPtr;
const char * hostEnd;
const char * pathPtr;
const char * pathEnd;
const char * queryPtr;
const char * queryEnd;
const char * fragmentPtr;
const char * fragmentEnd;
char c;
/*
URL breakdown from RFC 3986.
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
| _____________________|__
/ \ / \
urn:example:animal:ferret:nose
*/
if( inEnd == NULL ) inEnd = inSrc + strlen( inSrc );
// Parse an optional scheme (the "ftp" in "ftp://tom:secret@abc.com/test?x#y").
schemePtr = NULL;
schemeEnd = NULL;
c = '\0';
ptr = inSrc;
while( ( ptr < inEnd ) && ( ( c = *ptr ) != ':' ) && ( c != '/' ) && ( c != '?' ) && ( c != '#' ) ) ++ptr;
if( c == ':' )
{
schemePtr = inSrc;
schemeEnd = ptr;
inSrc = ptr + 1;
}
// Parse an optional authority (the "tom:secret@abc.com" in "ftp://tom:secret@abc.com/test?x#y").
userPtr = NULL;
userEnd = NULL;
passwordPtr = NULL;
passwordEnd = NULL;
hostPtr = NULL;
hostEnd = NULL;
if( ( ( inEnd - inSrc ) >= 2 ) && ( inSrc[ 0 ] == '/' ) && ( inSrc[ 1 ] == '/' ) )
{
const char * authorityPtr;
const char * authorityEnd;
const char * userInfoPtr;
const char * userInfoEnd;
inSrc += 2;
authorityPtr = inSrc;
while( ( inSrc < inEnd ) && ( ( c = *inSrc ) != '/' ) && ( c != '?' ) && ( c != '#' ) ) ++inSrc;
authorityEnd = inSrc;
// Parse an optional userinfo (the "tom:secret" in the above URL).
userInfoPtr = authorityPtr;
userInfoEnd = userInfoPtr;
while( ( userInfoEnd < authorityEnd ) && ( *userInfoEnd != '@' ) ) ++userInfoEnd;
if( userInfoEnd < authorityEnd )
{
// Parse the username (the "tom" in the above URL).
userPtr = userInfoPtr;
userEnd = userPtr;
while( ( userEnd < userInfoEnd ) && ( *userEnd != ':' ) ) ++userEnd;
if( userEnd < userInfoEnd )
{
// The rest is password/auth info. Note: passwords in URLs are deprecated (see RFC 3986 section 3.2.1).
passwordPtr = userEnd + 1;
passwordEnd = userInfoEnd;
}
// The host is the rest of the authority (the "abc.com" in "ftp://tom:secret@abc.com/test?x#y").
hostPtr = userInfoEnd + 1;
hostEnd = authorityEnd;
}
else
{
// The host is the entire authority (the "abc.com" in "ftp://tom:secret@abc.com/test?x#y").
hostPtr = authorityPtr;
hostEnd = authorityEnd;
}
}
// Parse the path (the "/test" in "ftp://tom:secret@abc.com/test?x#y").
c = '\0';
pathPtr = inSrc;
while( ( inSrc < inEnd ) && ( ( c = *inSrc ) != '?' ) && ( c != '#' ) ) ++inSrc;
pathEnd = inSrc;
// Parse an optional query (the "x" in "ftp://tom:secret@abc.com/test?x#y").
queryPtr = NULL;
queryEnd = NULL;
if( c == '?' )
{
queryPtr = ++inSrc;
while( ( inSrc < inEnd ) && ( ( c = *inSrc ) != '#' ) ) ++inSrc;
queryEnd = inSrc;
}
// Parse an optional fragment (the "y" in "ftp://tom:secret@abc.com/test?x#y").
fragmentPtr = NULL;
fragmentEnd = NULL;
if( c == '#' )
{
fragmentPtr = ++inSrc;
fragmentEnd = inEnd;
inSrc = inEnd;
}
outComponents->schemePtr = schemePtr;
outComponents->schemeLen = (size_t)( schemeEnd - schemePtr );
outComponents->userPtr = userPtr;
outComponents->userLen = (size_t)( userEnd - userPtr );
outComponents->passwordPtr = passwordPtr;
outComponents->passwordLen = (size_t)( passwordEnd - passwordPtr );
outComponents->hostPtr = hostPtr;
outComponents->hostLen = (size_t)( hostEnd - hostPtr );
outComponents->pathPtr = pathPtr;
outComponents->pathLen = (size_t)( pathEnd - pathPtr );
outComponents->queryPtr = queryPtr;
outComponents->queryLen = (size_t)( queryEnd - queryPtr );
outComponents->fragmentPtr = fragmentPtr;
outComponents->fragmentLen = (size_t)( fragmentEnd - fragmentPtr );
outComponents->segmentPtr = ( ( pathPtr < pathEnd ) && ( *pathPtr == '/' ) ) ? ( pathPtr + 1 ) : pathPtr;
outComponents->segmentEnd = ( ( pathPtr < pathEnd ) && ( pathEnd[ -1 ] == '/' ) ) ? ( pathEnd - 1 ) : pathEnd;
if( outSrc ) *outSrc = inSrc;
return kNoErr;
}
void PrintURL( URLComponents *inURL )
{
(void)inURL;
#if DEBUG
char *scheme = DataToCString( (uint8_t*)inURL->schemePtr, inURL->schemeLen );
char *user = DataToCString( (uint8_t*)inURL->userPtr, inURL->userLen );
char *password = DataToCString( (uint8_t*)inURL->passwordPtr, inURL->passwordLen );
char *host = DataToCString( (uint8_t*)inURL->hostPtr, inURL->hostLen );
char *path = DataToCString( (uint8_t*)inURL->pathPtr, inURL->pathLen );
char *query = DataToCString( (uint8_t*)inURL->queryPtr, inURL->queryLen );
char *fragment = DataToCString( (uint8_t*)inURL->fragmentPtr, inURL->fragmentLen );
char *segment = DataToCString( (uint8_t*)inURL->segmentPtr, inURL->segmentEnd - inURL->segmentPtr );
url_utils_log("scheme: %s", scheme);
url_utils_log("user: %s", user);
url_utils_log("password: %s", password);
url_utils_log("host: %s", host);
url_utils_log("path: %s", path);
url_utils_log("query: %s", query);
url_utils_log("fragment: %s", fragment);
url_utils_log("segment: %s", segment);
free( scheme );
free( user );
free( password );
free( host );
free( path );
free( query );
free( fragment );
free( segment );
#endif // DEBUG
}