source/AccessorySDK/Support/HTTPUtils.c
OSStatus	HTTPHeader_Parse( HTTPHeader *ioHeader )
{
	OSStatus			err;
	const char *		src;
	const char *		end;
	const char *		ptr;
	size_t				len;
	char				c;
	const char *		value;
	int					x;
	
	require_action( ioHeader->len < sizeof( ioHeader->buf ), exit, err = kParamErr );
	
	// Reset fields up-front to good defaults to simplify handling of unused fields later.
	
	ioHeader->methodPtr			= "";
	ioHeader->methodLen			= 0;
	ioHeader->method			= kHTTPMethod_Unset;
	ioHeader->urlPtr			= "";
	ioHeader->urlLen			= 0;
	memset( &ioHeader->url, 0, sizeof( ioHeader->url ) );
	ioHeader->protocolPtr		= "";
	ioHeader->protocolLen		= 0;
	ioHeader->statusCode		= -1;
	ioHeader->reasonPhrasePtr	= "";
	ioHeader->reasonPhraseLen	= 0;
	ioHeader->channelID			= 0;
	ioHeader->contentLength		= 0;
	ioHeader->persistent		= false;
	
	src = ioHeader->buf;
	
	// Parse the start line. This will also determine if it's a request or response.
	// Requests are in the format <method> <url> <protocol>/<majorVersion>.<minorVersion>, for example:
	//
	//		GET /abc/xyz.html HTTP/1.1
	//		GET http://www.host.com/abc/xyz.html HTTP/1.1
	//		GET http://user:password@www.host.com/abc/xyz.html HTTP/1.1
	//
	// Responses are in the format <protocol>/<majorVersion>.<minorVersion> <statusCode> <reasonPhrase>, for example:
	//
	//		HTTP/1.1 404 Not Found
	
	ptr = src;
	end = src + ioHeader->len;
	for( c = 0; ( ptr < end ) && ( ( c = *ptr ) != ' ' ) && ( c != '/' ); ++ptr ) {}
	require_action( ptr < end, exit, err = kMalformedErr );
	
	if( c == ' ' ) // Requests have a space after the method. Responses have '/' after the protocol.
	{
		ioHeader->methodPtr = src;
		ioHeader->methodLen = len = (size_t)( ptr - src );
		++ptr;
		if(      strnicmpx( src, len, "GET" )		== 0 ) ioHeader->method = kHTTPMethod_GET;
		else if( strnicmpx( src, len, "POST" )		== 0 ) ioHeader->method = kHTTPMethod_POST;
		else if( strnicmpx( src, len, "PUT" )		== 0 ) ioHeader->method = kHTTPMethod_PUT;
		else if( strnicmpx( src, len, "DELETE" )	== 0 ) ioHeader->method = kHTTPMethod_DELETE;
		
		// Parse the URL.
		
		ioHeader->urlPtr = ptr;
		while( ( ptr < end ) && ( *ptr != ' ' ) ) ++ptr;
		ioHeader->urlLen = (size_t)( ptr - ioHeader->urlPtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
		
		err = URLParseComponents( ioHeader->urlPtr, ioHeader->urlPtr + ioHeader->urlLen, &ioHeader->url, NULL );
		require_noerr( err, exit );
		
		// Parse the protocol and version.
		
		ioHeader->protocolPtr = ptr;
		while( ( ptr < end ) && ( ( c = *ptr ) != '\r' ) && ( c != '\n' ) ) ++ptr;
		ioHeader->protocolLen = (size_t)( ptr - ioHeader->protocolPtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
	}
	else // Response
	{
		// Parse the protocol version.
		
		ioHeader->protocolPtr = src;
		for( ++ptr; ( ptr < end ) && ( *ptr != ' ' ); ++ptr ) {}
		ioHeader->protocolLen = (size_t)( ptr - ioHeader->protocolPtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
		
		// Parse the status code.
		
		x = 0;
		for( c = 0; ( ptr < end ) && ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr ) x = ( x * 10 ) + ( c - '0' ); 
		ioHeader->statusCode = x;
		if( c == ' ' ) ++ptr;
		
		// Parse the reason phrase.
		
		ioHeader->reasonPhrasePtr = ptr;
		while( ( ptr < end ) && ( ( c = *ptr ) != '\r' ) && ( c != '\n' ) ) ++ptr;
		ioHeader->reasonPhraseLen = (size_t)( ptr - ioHeader->reasonPhrasePtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
	}
	
	// There should at least be a blank line after the start line so make sure there's more data.
	
	require_action( ptr < end, exit, err = kMalformedErr );
	
	// Determine persistence. Note: HTTP 1.0 defaults to non-persistent if a Connection header field is not present.
	
	err = HTTPGetHeaderField( ioHeader->buf, ioHeader->len, kHTTPHeader_Connection, NULL, NULL, &value, &len, NULL );
	if( err )	ioHeader->persistent = (Boolean)( strnicmpx( ioHeader->protocolPtr, ioHeader->protocolLen, "HTTP/1.0" ) != 0 );
	else		ioHeader->persistent = (Boolean)( strnicmpx( value, len, "close" ) != 0 );
	
	// Content-Length is such a common field that we get it here during general parsing.
	
	HTTPScanFHeaderValue( ioHeader->buf, ioHeader->len, "Content-Length", "%llu", &ioHeader->contentLength );
	err = kNoErr;
	
exit:
	return( err );
}
//===========================================================================================================================
//	HTTPHeader_Parse
//
//	Parses an HTTP header. This assumes the "buf" and "len" fields are set. The other fields are set by this function.
//===========================================================================================================================
HTTPHeader_Parse
Parses an HTTP header. This assumes the "buf" and "len" fields are set. The other fields are set by this function.
HTTPHeader_Parse Parses an HTTP header . This assumes the " buf " and " len " fields are set . The other fields are set by this function .
OSStatus	HTTPHeader_Parse( HTTPHeader *ioHeader )
{
	OSStatus			err;
	const char *		src;
	const char *		end;
	const char *		ptr;
	size_t				len;
	char				c;
	const char *		value;
	int					x;
	require_action( ioHeader->len < sizeof( ioHeader->buf ), exit, err = kParamErr );
	ioHeader->methodPtr			= "";
	ioHeader->methodLen			= 0;
	ioHeader->method			= kHTTPMethod_Unset;
	ioHeader->urlPtr			= "";
	ioHeader->urlLen			= 0;
	memset( &ioHeader->url, 0, sizeof( ioHeader->url ) );
	ioHeader->protocolPtr		= "";
	ioHeader->protocolLen		= 0;
	ioHeader->statusCode		= -1;
	ioHeader->reasonPhrasePtr	= "";
	ioHeader->reasonPhraseLen	= 0;
	ioHeader->channelID			= 0;
	ioHeader->contentLength		= 0;
	ioHeader->persistent		= false;
	src = ioHeader->buf;
			GET /abc/xyz.html HTTP/1.1
			GET http:www.host.com/abc/xyz.html HTTP/1.1
			GET http:user:password@www.host.com/abc/xyz.html HTTP/1.1
	 Responses are in the format <protocol>/<majorVersion>.<minorVersion> <statusCode> <reasonPhrase>, for example:
			HTTP/1.1 404 Not Found
	ptr = src;
	end = src + ioHeader->len;
	for( c = 0; ( ptr < end ) && ( ( c = *ptr ) != ' ' ) && ( c != '/' ); ++ptr ) {}
	require_action( ptr < end, exit, err = kMalformedErr );
	if( c == ' ' )  Requests have a space after the method. Responses have '/' after the protocol.
	{
		ioHeader->methodPtr = src;
		ioHeader->methodLen = len = (size_t)( ptr - src );
		++ptr;
		if(      strnicmpx( src, len, "GET" )		== 0 ) ioHeader->method = kHTTPMethod_GET;
		else if( strnicmpx( src, len, "POST" )		== 0 ) ioHeader->method = kHTTPMethod_POST;
		else if( strnicmpx( src, len, "PUT" )		== 0 ) ioHeader->method = kHTTPMethod_PUT;
		else if( strnicmpx( src, len, "DELETE" )	== 0 ) ioHeader->method = kHTTPMethod_DELETE;
		 Parse the URL.
		ioHeader->urlPtr = ptr;
		while( ( ptr < end ) && ( *ptr != ' ' ) ) ++ptr;
		ioHeader->urlLen = (size_t)( ptr - ioHeader->urlPtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
		err = URLParseComponents( ioHeader->urlPtr, ioHeader->urlPtr + ioHeader->urlLen, &ioHeader->url, NULL );
		require_noerr( err, exit );
		 Parse the protocol and version.
		ioHeader->protocolPtr = ptr;
		while( ( ptr < end ) && ( ( c = *ptr ) != '\r' ) && ( c != '\n' ) ) ++ptr;
		ioHeader->protocolLen = (size_t)( ptr - ioHeader->protocolPtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
	}
	else  Response
	{
		 Parse the protocol version.
		ioHeader->protocolPtr = src;
		for( ++ptr; ( ptr < end ) && ( *ptr != ' ' ); ++ptr ) {}
		ioHeader->protocolLen = (size_t)( ptr - ioHeader->protocolPtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
		 Parse the status code.
		x = 0;
		for( c = 0; ( ptr < end ) && ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr ) x = ( x * 10 ) + ( c - '0' ); 
		ioHeader->statusCode = x;
		if( c == ' ' ) ++ptr;
		 Parse the reason phrase.
		ioHeader->reasonPhrasePtr = ptr;
		while( ( ptr < end ) && ( ( c = *ptr ) != '\r' ) && ( c != '\n' ) ) ++ptr;
		ioHeader->reasonPhraseLen = (size_t)( ptr - ioHeader->reasonPhrasePtr );
		require_action( ptr < end, exit, err = kMalformedErr );
		++ptr;
	}
	 There should at least be a blank line after the start line so make sure there's more data.
	require_action( ptr < end, exit, err = kMalformedErr );
	 Determine persistence. Note: HTTP 1.0 defaults to non-persistent if a Connection header field is not present.
	err = HTTPGetHeaderField( ioHeader->buf, ioHeader->len, kHTTPHeader_Connection, NULL, NULL, &value, &len, NULL );
	if( err )	ioHeader->persistent = (Boolean)( strnicmpx( ioHeader->protocolPtr, ioHeader->protocolLen, "HTTP/1.0" ) != 0 );
	else		ioHeader->persistent = (Boolean)( strnicmpx( value, len, "close" ) != 0 );
	 Content-Length is such a common field that we get it here during general parsing.
	HTTPScanFHeaderValue( ioHeader->buf, ioHeader->len, "Content-Length", "%llu", &ioHeader->contentLength );
	err = kNoErr;
exit:
	return( err );
}
OSStatus HTTPHeader_Parse ( HTTPHeader * ioHeader ) { OSStatus err ; const char * src ; const char * end ; const char * ptr ; size_t len ; char c ; const char * value ; int x ; require_action ( ioHeader -> len < sizeof ( ioHeader -> buf ) , exit , err = kParamErr ) ; ioHeader -> methodPtr = " " ; ioHeader -> methodLen = 0 ; ioHeader -> method = kHTTPMethod_Unset ; ioHeader -> urlPtr = " " ; ioHeader -> urlLen = 0 ; memset ( & ioHeader -> url , 0 , sizeof ( ioHeader -> url ) ) ; ioHeader -> protocolPtr = " " ; ioHeader -> protocolLen = 0 ; ioHeader -> statusCode = -1 ; ioHeader -> reasonPhrasePtr = " " ; ioHeader -> reasonPhraseLen = 0 ; ioHeader -> channelID = 0 ; ioHeader -> contentLength = 0 ; ioHeader -> persistent = false ; src = ioHeader -> buf ; ptr = src ; end = src + ioHeader -> len ; for ( c = 0 ; ( ptr < end ) && ( ( c = * ptr ) != ' ' ) && ( c != ' ' ) ; ++ ptr ) { } require_action ( ptr < end , exit , err = kMalformedErr ) ; if ( c == ' ' ) { ioHeader -> methodPtr = src ; ioHeader -> methodLen = len = ( size_t ) ( ptr - src ) ; ++ ptr ; if ( strnicmpx ( src , len , " " ) == 0 ) ioHeader -> method = kHTTPMethod_GET ; else if ( strnicmpx ( src , len , " " ) == 0 ) ioHeader -> method = kHTTPMethod_POST ; else if ( strnicmpx ( src , len , " " ) == 0 ) ioHeader -> method = kHTTPMethod_PUT ; else if ( strnicmpx ( src , len , " " ) == 0 ) ioHeader -> method = kHTTPMethod_DELETE ; ioHeader -> urlPtr = ptr ; while ( ( ptr < end ) && ( * ptr != ' ' ) ) ++ ptr ; ioHeader -> urlLen = ( size_t ) ( ptr - ioHeader -> urlPtr ) ; require_action ( ptr < end , exit , err = kMalformedErr ) ; ++ ptr ; err = URLParseComponents ( ioHeader -> urlPtr , ioHeader -> urlPtr + ioHeader -> urlLen , & ioHeader -> url , NULL ) ; require_noerr ( err , exit ) ; ioHeader -> protocolPtr = ptr ; while ( ( ptr < end ) && ( ( c = * ptr ) != ' \r ' ) && ( c != ' \n ' ) ) ++ ptr ; ioHeader -> protocolLen = ( size_t ) ( ptr - ioHeader -> protocolPtr ) ; require_action ( ptr < end , exit , err = kMalformedErr ) ; ++ ptr ; } else { ioHeader -> protocolPtr = src ; for ( ++ ptr ; ( ptr < end ) && ( * ptr != ' ' ) ; ++ ptr ) { } ioHeader -> protocolLen = ( size_t ) ( ptr - ioHeader -> protocolPtr ) ; require_action ( ptr < end , exit , err = kMalformedErr ) ; ++ ptr ; x = 0 ; for ( c = 0 ; ( ptr < end ) && ( ( c = * ptr ) >= ' ' ) && ( c <= ' ' ) ; ++ ptr ) x = ( x * 10 ) + ( c - ' ' ) ; ioHeader -> statusCode = x ; if ( c == ' ' ) ++ ptr ; ioHeader -> reasonPhrasePtr = ptr ; while ( ( ptr < end ) && ( ( c = * ptr ) != ' \r ' ) && ( c != ' \n ' ) ) ++ ptr ; ioHeader -> reasonPhraseLen = ( size_t ) ( ptr - ioHeader -> reasonPhrasePtr ) ; require_action ( ptr < end , exit , err = kMalformedErr ) ; ++ ptr ; } require_action ( ptr < end , exit , err = kMalformedErr ) ; err = HTTPGetHeaderField ( ioHeader -> buf , ioHeader -> len , kHTTPHeader_Connection , NULL , NULL , & value , & len , NULL ) ; if ( err ) ioHeader -> persistent = ( Boolean ) ( strnicmpx ( ioHeader -> protocolPtr , ioHeader -> protocolLen , " " ) != 0 ) ; else ioHeader -> persistent = ( Boolean ) ( strnicmpx ( value , len , " " ) != 0 ) ; HTTPScanFHeaderValue ( ioHeader -> buf , ioHeader -> len , " " , " " , & ioHeader -> contentLength ) ; err = kNoErr ; exit : return ( err ) ; }
HTTPHeader_Parse
Parses an HTTP header.
HTTPHeader_Parse Parses an HTTP header .
// Reset fields up-front to good defaults to simplify handling of unused fields later. // Parse the start line. This will also determine if it's a request or response. // Requests are in the format <method> <url> <protocol>/<majorVersion>.<minorVersion>, for example: // //		GET /abc/xyz.html HTTP/1.1 //		GET http://www.host.com/abc/xyz.html HTTP/1.1 //		GET http://user:password@www.host.com/abc/xyz.html HTTP/1.1 // // Responses are in the format <protocol>/<majorVersion>.<minorVersion> <statusCode> <reasonPhrase>, for example: // //		HTTP/1.1 404 Not Found // Requests have a space after the method. Responses have '/' after the protocol. // Parse the URL. // Parse the protocol and version. // Response // Parse the protocol version. // Parse the status code. // Parse the reason phrase. // There should at least be a blank line after the start line so make sure there's more data. // Determine persistence. Note: HTTP 1.0 defaults to non-persistent if a Connection header field is not present. // Content-Length is such a common field that we get it here during general parsing.