Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: xively-jumpstart-demo
http_layer_parser.c
00001 // Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved. 00002 // This is part of Xively C library, it is under the BSD 3-Clause license. 00003 00004 /** 00005 * \file http_layer_parser.c 00006 * \author Olgierd Humenczuk 00007 * \brief Our simple HTTP parser [see http_layer_parser.h] 00008 */ 00009 00010 #include <stdio.h> 00011 #include <string.h> 00012 #include <stdlib.h> 00013 00014 #include "xively.h" 00015 #include "xi_macros.h" 00016 #include "http_consts.h" 00017 #include "http_layer_parser.h" 00018 #include "xi_debug.h" 00019 #include "xi_err.h" 00020 00021 static const char XI_HTTP_STATUS_PATTERN[] = 00022 "HTTP/%d.%d %d %" XI_STR(XI_HTTP_STATUS_STRING_SIZE) "[^\r\n]\r\n"; //!< the match pattern 00023 00024 #define SET_HTTP_STATUS_PATTERN(a,b,c,d) XI_HTTP_STATUS_PATTERN, &a, &b, &c, d 00025 00026 static const char XI_HTTP_TOKEN_NAMES[ XI_HTTP_HEADERS_COUNT ][ XI_HTTP_HEADER_NAME_MAX_SIZE ] = 00027 { 00028 "date" // XI_HTTP_HEADER_DATE 00029 , "content-type" // XI_HTTP_HEADER_CONTENT_TYPE 00030 , "content-length" // XI_HTTP_HEADER_CONTENT_LENGTH 00031 , "connection" // XI_HTTP_HEADER_CONNECTION 00032 , "x-request-id" // XI_HTTP_HEADER_X_REQUEST_ID 00033 , "cache-control" // XI_HTTP_HEADER_CACHE_CONTROL 00034 , "age" // XI_HTTP_HEADER_AGE 00035 , "vary" // XI_HTTP_HEADER_VARY 00036 , "unknown" // XI_HTTP_HEADER_UNKNOWN, //!< !!!! this must be always on the last position 00037 }; 00038 00039 static inline http_header_type_t classify_header( const char* header ) 00040 { 00041 for( unsigned short i = 0; i < XI_HTTP_HEADER_COUNT - 1; ++i ) 00042 { 00043 if( strcasecmp( header, XI_HTTP_TOKEN_NAMES[ i ] ) == 0 ) 00044 return ( http_header_type_t ) i; 00045 } 00046 00047 return XI_HTTP_HEADER_UNKNOWN; 00048 } 00049 00050 const char* parse_http_status( http_response_t* response, const char* content ) 00051 { 00052 // variables 00053 int c = 0; 00054 00055 // find the first occurrence of CRLF 00056 const char* header_end_ptr = strstr( content, XI_HTTP_CRLF ); 00057 00058 // check continuation condition 00059 XI_CHECK_ZERO( header_end_ptr, XI_HTTP_STATUS_PARSE_ERROR ); 00060 00061 // update the pointer 00062 header_end_ptr += 2; 00063 00064 // parse 00065 c = sscanf( content 00066 , SET_HTTP_STATUS_PATTERN( 00067 response->http_version1 00068 , response->http_version2 00069 , response->http_status 00070 , response->http_status_string ) ); 00071 00072 // check if all arguments found 00073 XI_CHECK_CND( c != 4, XI_HTTP_STATUS_PARSE_ERROR ); 00074 00075 // return updated ptr 00076 return header_end_ptr; 00077 00078 err_handling: 00079 return 0; 00080 } 00081 00082 const char* parse_http_header( http_response_t* response 00083 , const char* content ) 00084 { 00085 // find the first occurrence of CRLF 00086 const char* header_end_ptr = strstr( content, XI_HTTP_CRLF ); 00087 const char* header_name_end_ptr = strstr( content, ":" ); 00088 00089 // check continuation condition 00090 XI_CHECK_ZERO( header_end_ptr, XI_HTTP_HEADER_PARSE_ERROR ); 00091 XI_CHECK_ZERO( header_name_end_ptr, XI_HTTP_HEADER_PARSE_ERROR ); 00092 XI_CHECK_CND( header_name_end_ptr > header_end_ptr, XI_HTTP_HEADER_PARSE_ERROR ); 00093 00094 { 00095 int size = sizeof( response->http_headers[ response->http_headers_size ].name ); 00096 00097 XI_CHECK_CND( header_name_end_ptr - content > size - 1, XI_HTTP_HEADER_PARSE_ERROR ); 00098 00099 memcpy( response->http_headers[ response->http_headers_size ].name 00100 , content, XI_MIN( size - 1, header_name_end_ptr - content ) ); 00101 00102 // set the guard 00103 XI_GUARD_EOS( response->http_headers[ response->http_headers_size ].name, size ); 00104 } 00105 00106 // update the pointer 00107 header_name_end_ptr += 2; 00108 00109 { 00110 int size = sizeof( response->http_headers[ response->http_headers_size ].value ); 00111 00112 XI_CHECK_CND( header_end_ptr - header_name_end_ptr > size - 1, XI_HTTP_HEADER_PARSE_ERROR ); 00113 00114 memcpy( response->http_headers[ response->http_headers_size ].value 00115 , header_name_end_ptr, XI_MIN( size - 1, header_end_ptr - header_name_end_ptr ) ); 00116 00117 // set the guard 00118 XI_GUARD_EOS( response->http_headers[ response->http_headers_size ].value, size ); 00119 } 00120 00121 // @TODO change the complexity of the classify header 00122 // implementation now it's O( n*m ) it can be done in O( n ) 00123 // using some sort of simple DFA 00124 // I'm working on a very simple Python DFA generator for C 00125 // but still this is a w.i.p. at the moment 00126 00127 // parse the header name 00128 { 00129 http_header_type_t ht = classify_header( 00130 response->http_headers[ response->http_headers_size ].name ); 00131 00132 // accept headers that differs from unknown 00133 if( ht != XI_HTTP_HEADER_UNKNOWN ) 00134 { 00135 response->http_headers_checklist[ ht ] = 00136 &response->http_headers[ response->http_headers_size ]; 00137 } 00138 00139 // set header type 00140 response->http_headers[ response->http_headers_size ].header_type = ht; 00141 00142 // increment headers size and check if it's okay 00143 response->http_headers_size += 1; 00144 00145 XI_CHECK_CND( response->http_headers_size >= XI_HTTP_MAX_HEADERS 00146 , XI_HTTP_HEADER_PARSE_ERROR ); 00147 00148 // update the pointer 00149 header_end_ptr += sizeof( XI_HTTP_CRLF ) - 1; 00150 } 00151 00152 return header_end_ptr; 00153 00154 err_handling: 00155 return 0; 00156 } 00157 00158 http_response_t* parse_http( http_response_t* response, const char* content ) 00159 { 00160 memset( response, 0, sizeof( http_response_t ) ); 00161 00162 // remember where is the end of header section 00163 const char* ptr_to_headers_end = strstr( content, XI_HTTP_CRLFX2 ); 00164 00165 // check the continuation condition 00166 XI_CHECK_ZERO( ptr_to_headers_end, XI_HTTP_PARSE_ERROR ); 00167 00168 // update the pointer 00169 ptr_to_headers_end += sizeof( XI_HTTP_CRLF ) - 1; 00170 00171 const char* payload_begin = ptr_to_headers_end + sizeof( XI_HTTP_CRLF ) - 1; 00172 00173 XI_CHECK_ZERO( payload_begin, XI_HTTP_PARSE_ERROR ); 00174 00175 // parse status 00176 const char* ptr = parse_http_status( response, content ); 00177 00178 // check the continuation condition 00179 XI_CHECK_ZERO( ptr, XI_HTTP_PARSE_ERROR ); 00180 00181 // read the headers 00182 while( ( ptr = parse_http_header( response, ptr ) ) != '\0' 00183 && ptr != ptr_to_headers_end ); 00184 00185 // if there was an error, forward it 00186 xi_err_t e = xi_get_last_error(); 00187 XI_CHECK_CND( e != XI_NO_ERR, e ); 00188 00189 // just copy the content 00190 strncpy( response->http_content, payload_begin, sizeof( response->http_content ) ); 00191 00192 return response; 00193 00194 err_handling: 00195 return 0; 00196 }
Generated on Wed Jul 13 2022 17:00:32 by
1.7.2