HTTP Parser and message builder / objects in plain C Snapshot
|
00001 #ifndef _HTTP_PARSER_H_ 00002 #define _HTTP_PARSER_H_ 00003 00004 #include <stdlib.h> 00005 #include <nutils/bf.h> 00006 #include <hutils/uri.h> 00007 #include <cutils/dlistunr.h> 00008 #include <cutils/bhash.h> 00009 00010 00011 // =============================================================== 00012 00013 #define HTTP_MESSAGE_FLAG_CONNECTION_CLOSE 1 00014 #define HTTP_MESSAGE_FLAG_TRANSFER_CHUNKED 2 00015 #define HTTP_MESSAGE_FLAG_HAS_CONTENT_LENGTH 4 00016 #define HTTP_MESSAGE_FLAG_KEEPALIVE 8 00017 00018 /** 00019 * @defgroup HTTP_MESSAGE 00020 * @brief Holds common data of both HTTP request and response objects. 00021 * 00022 * @{ 00023 */ 00024 00025 typedef struct tagSTRINGPAIR { 00026 char *key; 00027 char *value; 00028 } STRINGPAIR; 00029 00030 00031 typedef struct tagHTTP_MESSAGE { 00032 00033 int flags; 00034 int content_length; 00035 DLISTUNR header_values; 00036 } HTTP_MESSAGE; 00037 00038 int HTTP_MESSAGE_init( HTTP_MESSAGE *message ); 00039 00040 void HTTP_MESSAGE_free( HTTP_MESSAGE *message ); 00041 00042 int HTTP_MESSAGE_add_header( HTTP_MESSAGE *message, const char *name , const char *value ); 00043 00044 M_INLINE void HTTP_MESSAGE_set_content_length( HTTP_MESSAGE *message, int content_length ) 00045 { 00046 message->flags |= HTTP_MESSAGE_FLAG_HAS_CONTENT_LENGTH; 00047 message->content_length = content_length; 00048 } 00049 00050 const char * HTTP_MESSAGE_find_header( HTTP_MESSAGE *message, const char *name ); 00051 00052 STRINGPAIR * HTTP_MESSAGE_first_header( HTTP_MESSAGE *message, DLISTUNR_position *pos ); 00053 00054 STRINGPAIR * HTTP_MESSAGE_next_header( HTTP_MESSAGE *message, DLISTUNR_position *pos ); 00055 00056 00057 00058 /** 00059 * @} 00060 */ 00061 00062 //=============================================================== 00063 00064 /** 00065 * @defgroup HTTP_REQUEST 00066 * @brief http request object. 00067 * 00068 * @{ 00069 */ 00070 00071 struct tagHTTP_PARSER; 00072 struct tagHTTP_REQUEST_PARSER; 00073 00074 /** 00075 * @brief callback that is invoked in order to parse contents of a specific http header 00076 * 00077 */ 00078 typedef int (*HEADER_ACTION) ( struct tagHTTP_MESSAGE *request, struct tagHTTP_PARSER *parser ); 00079 00080 // =============================================================== 00081 00082 typedef enum tagHttp_method_type { 00083 HTTP_METHOD_GET, 00084 HTTP_METHOD_POST, 00085 HTTP_METHOD_PUT, 00086 HTTP_METHOD_HEAD, 00087 HTTP_METHOD_OPTIONS, 00088 HTTP_METHOD_DELETE, 00089 HTTP_METHOD_TRACE, 00090 HTTP_METHOD_CONNECT 00091 00092 } Http_method_type; 00093 00094 typedef enum tagHttp_version_type { 00095 HTTP_VERSION_1_0, 00096 HTTP_VERSION_1_1, 00097 00098 } Http_version_type; 00099 00100 typedef struct tagHTTP_REQUEST { 00101 HTTP_MESSAGE base; 00102 00103 // request line 00104 Http_method_type method; 00105 URI url; 00106 char *raw_url; 00107 Http_version_type version; 00108 00109 // does the request expect 100 continue response? 00110 int expect_100_continue; 00111 00112 // host headera 00113 int has_host_header; 00114 char *host_header; 00115 int host_header_port; 00116 00117 } HTTP_REQUEST; 00118 00119 int HTTP_REQUEST_is_persistent( HTTP_REQUEST *message ); 00120 00121 M_INLINE int HTTP_REQUEST_init( HTTP_REQUEST *message ) 00122 { 00123 if (HTTP_MESSAGE_init( &message->base )) { 00124 return -1; 00125 } 00126 00127 URI_init( & message->url ); 00128 00129 message->expect_100_continue = message->has_host_header = 0; 00130 message->raw_url = message->host_header = 0; 00131 message->has_host_header = 0; 00132 message->host_header_port = -1; 00133 00134 return 0; 00135 } 00136 00137 M_INLINE void HTTP_REQUEST_free( HTTP_REQUEST *message ) 00138 { 00139 URI_free( &message->url ); 00140 00141 if (message->host_header) { 00142 free( message->host_header); 00143 } 00144 if (message->raw_url) { 00145 free( message->raw_url ); 00146 } 00147 00148 message->expect_100_continue = message->has_host_header = 0; 00149 message->raw_url = message->host_header = 0; 00150 message->has_host_header = 0; 00151 message->host_header_port = -1; 00152 00153 HTTP_MESSAGE_free( &message->base ); 00154 } 00155 00156 /** 00157 * @} 00158 */ 00159 00160 // =============================================================== 00161 00162 00163 /** 00164 * @defgroup HTTP_RESPONSE 00165 * @brief - holds information of an http response. 00166 * 00167 * @{ 00168 */ 00169 typedef struct tagHTTP_RESPONSE { 00170 HTTP_MESSAGE base; 00171 00172 int status_code; 00173 Http_version_type version; 00174 00175 00176 } HTTP_RESPONSE; 00177 00178 M_INLINE int HTTP_RESPONSE_init( HTTP_RESPONSE *message, Http_version_type version, int status_code ) 00179 { 00180 if (HTTP_MESSAGE_init( &message->base ) ) { 00181 return -1; 00182 } 00183 message->status_code = status_code; 00184 message->version = version; 00185 return 0; 00186 } 00187 00188 00189 M_INLINE void HTTP_RESPONSE_free( HTTP_RESPONSE *message ) 00190 { 00191 HTTP_MESSAGE_free( &message->base ); 00192 } 00193 00194 typedef int (*HTTP_RESP_HEADER_PARSED) (HTTP_RESPONSE *request, void *ctx); 00195 typedef int (*HTTP_RESP_MESSAGE_BODY_DATA) (HTTP_RESPONSE *request, void *data, size_t data_size, void *ctx); 00196 typedef int (*HTTP_RESP_FINISHED) (HTTP_RESPONSE *request, void *ctx); 00197 00198 /** 00199 * @} 00200 */ 00201 00202 00203 00204 // =============================================================== 00205 00206 /** 00207 * @defgroup HTTP_PARSER 00208 * @brief base class of both http request and http response parsers 00209 * 00210 * @{ 00211 */ 00212 00213 typedef enum tagHTTP_STATE_PARSING { 00214 00215 HTTP_STATE_PARSING_REQUEST_LINE, 00216 HTTP_STATE_PARSING_HEADERS, 00217 HTTP_STATE_PARSING_BODY_CONTENT_LENGTH, 00218 HTTP_STATE_PARSING_BODY_CHUNK_HEADER, 00219 HTTP_STATE_PARSING_BODY_CHUNK_DATA, 00220 HTTP_STATE_PARSING_BODY_CHUNK_EOF_AFTER_DATA, 00221 HTTP_STATE_PARSING_BODY_CHUNK_TRAILER, 00222 00223 } HTTP_STATE_PARSING; 00224 00225 typedef struct tagHTTP_PARSER { 00226 HTTP_STATE_PARSING state; 00227 HASH header_action; 00228 char *token; // the current parsed header token. 00229 size_t token_length; // length of token buffer 00230 00231 char *tokpos; // current position in http header data - during parsing of header. 00232 00233 size_t content_left; // how many bytes will make up the following chunk or Content-length data. 00234 00235 } HTTP_PARSER; 00236 00237 typedef enum { 00238 PARSER_STATUS_ERROR = -1, 00239 PARSER_STATUS_COMPLETED = 0, 00240 PARSER_STATUS_NEED_MORE_DATA = 1, 00241 } 00242 PARSER_STATUS; 00243 00244 typedef enum { 00245 HTTP_TK_QUOTED_STRING, 00246 HTTP_TK_TEXT, 00247 HTTP_TK_SEPARATOR, 00248 HTTP_TK_EOF, 00249 } HTTP_TK_TYPE; 00250 00251 typedef int (*HTTP_PROCESS_MSG_DATA) ( HTTP_MESSAGE *msg, void *data, size_t data_size, void *ctx); 00252 typedef int (*HTTP_REQ_HEADER_PARSED) (HTTP_REQUEST *request, void *ctx); 00253 typedef int (*HTTP_REQ_MESSAGE_BODY_DATA) (HTTP_REQUEST *request, void *data, size_t data_size, void *ctx); 00254 typedef int (*HTTP_REQ_FINISHED) (HTTP_REQUEST *request, void *ctx); 00255 00256 00257 00258 int HTTP_PARSER_init( HTTP_PARSER *parser ); 00259 int HTTP_PARSER_free( HTTP_PARSER *parser ); 00260 00261 00262 /** 00263 * @brief add a parser for a specific http header type 00264 */ 00265 int HTTP_add_header_parser( HTTP_PARSER *parser, const char *header_name, HEADER_ACTION action ); 00266 00267 /** 00268 * @brief returns next raw line from http header, adjoins line continuations. 00269 */ 00270 PARSER_STATUS HTTP_get_line( BF *bf, char **start_line ); 00271 00272 /** 00273 * @brief return next token while parsing http header value. 00274 * @return -1 on error, otherwise type of token returns (value out of HTTP_TK_TYPE) 00275 */ 00276 int HTTP_get_header_token( HTTP_PARSER *parser ); 00277 00278 /** 00279 * @brief dispatch parsing of one http header 00280 * @return -1 error, 0 - http header finished, 1 - need more data, 2 - header line parsed ok. 00281 */ 00282 PARSER_STATUS HTTP_parse_header_line( HTTP_PARSER *parser, HTTP_MESSAGE *request, BF *bf, int *eof_header ); 00283 00284 /** 00285 * @brief start parsing content length message body 00286 */ 00287 int HTTP_PARSER_content_length_init( HTTP_PARSER *parser, HTTP_MESSAGE *msg ); 00288 00289 /** 00290 * @brief consume content length message body. 00291 */ 00292 PARSER_STATUS HTTP_PARSER_content_length_process( HTTP_PARSER *parser, BF *bf, HTTP_PROCESS_MSG_DATA cb, HTTP_MESSAGE *msg, void *ctx); 00293 00294 /** 00295 * @brief start parsing chunked data 00296 */ 00297 int HTTP_PARSER_chunked_data_init( HTTP_PARSER *parser ); 00298 00299 /** 00300 * @brief finish parsind chunked content data. 00301 */ 00302 PARSER_STATUS HTTP_PARSER_chunked_data_process( HTTP_PARSER *parser, BF *bf, HTTP_PROCESS_MSG_DATA cb, HTTP_MESSAGE *msg, void *ctx); 00303 00304 /** 00305 * @} 00306 */ 00307 00308 00309 // =============================================================== 00310 00311 00312 00313 /** 00314 * @defgroup HTTP_REQUEST_PARSER 00315 * @brief parser of http requests 00316 * 00317 * @{ 00318 */ 00319 00320 typedef struct tagHTTP_REQUEST_PARSER { 00321 00322 HTTP_PARSER base; 00323 void *ctx; 00324 00325 HTTP_REQ_HEADER_PARSED ev_header; 00326 HTTP_REQ_MESSAGE_BODY_DATA ev_body ; 00327 HTTP_REQ_FINISHED ev_finish; 00328 00329 } HTTP_REQUEST_PARSER; 00330 00331 00332 00333 /** 00334 * @brief initialise request parser object 00335 */ 00336 int HTTP_REQUEST_PARSER_init( HTTP_REQUEST_PARSER *parser, 00337 HTTP_REQ_HEADER_PARSED header_parsed, 00338 HTTP_REQ_MESSAGE_BODY_DATA on_message_body_data, 00339 HTTP_REQ_FINISHED on_request_finished, 00340 void *ctx); 00341 00342 00343 /** 00344 * @brief parse a http request 00345 * @return 0 - done parsing, 1 need more data, -1 error occured. 00346 */ 00347 PARSER_STATUS HTTP_REQUEST_PARSER_process( HTTP_REQUEST_PARSER *parser, HTTP_REQUEST *request, BF *data); 00348 00349 /** 00350 * @} 00351 */ 00352 00353 00354 // =============================================================== 00355 00356 00357 /** 00358 * @defgroup HTTP_RESPONSE_PARSER 00359 * @brief parser of http responses 00360 * 00361 * @{ 00362 */ 00363 00364 typedef struct tagHTTP_RESPONSE_PARSER { 00365 00366 HTTP_PARSER base; 00367 00368 HTTP_RESP_HEADER_PARSED ev_header; 00369 HTTP_RESP_MESSAGE_BODY_DATA ev_body ; 00370 HTTP_RESP_FINISHED ev_finish; 00371 00372 HTTP_STATE_PARSING state; 00373 void *ctx; 00374 00375 } HTTP_RESPONSE_PARSER; 00376 00377 00378 /** 00379 * @brief initialise request parser object 00380 */ 00381 int HTTP_RESPONSE_PARSER_init( HTTP_RESPONSE_PARSER *parser, 00382 HTTP_RESP_HEADER_PARSED header_parsed, 00383 HTTP_RESP_MESSAGE_BODY_DATA on_message_body_data, 00384 HTTP_RESP_FINISHED on_request_finished, 00385 void *ctx); 00386 00387 00388 00389 /** 00390 * @brief parse a http response 00391 * @return 0 - done parsing, 1 need more data, -1 error occured. 00392 */ 00393 PARSER_STATUS HTTP_RESPONSE_PARSER_process( HTTP_RESPONSE_PARSER *parser, HTTP_RESPONSE *response, BF *data ); 00394 00395 /** 00396 * @} 00397 */ 00398 00399 00400 // =============================================================== 00401 00402 00403 /** 00404 * @defgroup HTTP_RESPONSE_WRITER 00405 * @brief writer of http responss 00406 * @{ 00407 */ 00408 00409 typedef enum { 00410 HTTP_RESPONSE_WR_STATUS_LINE, 00411 HTTP_RESPONSE_WR_CONNECTION_CLOSE, 00412 HTTP_RESPONSE_WR_CHUNKED, 00413 HTTP_RESPONSE_WR_CONTENT_LENGTH, 00414 HTTP_RESPONSE_WR_HEADERS, 00415 HTTP_RESPONSE_WR_EOF, 00416 00417 } HTTP_RESPONSE_WR_STATE; 00418 00419 typedef struct tagHTTP_RESPONSE_WRITER 00420 { 00421 HTTP_RESPONSE *response; 00422 HTTP_RESPONSE_WR_STATE state; 00423 DLISTUNR_position header_position; 00424 int state_header; 00425 00426 } HTTP_RESPONSE_WRITER; 00427 00428 00429 M_INLINE void HTTP_RESPONSE_WRITER_init( HTTP_RESPONSE_WRITER *writer, HTTP_RESPONSE *response) 00430 { 00431 writer->response = response; 00432 writer->state = HTTP_RESPONSE_WR_STATUS_LINE; 00433 } 00434 00435 00436 PARSER_STATUS HTTP_RESPONSE_WRITER_write( HTTP_RESPONSE_WRITER *writer, BF *data ); 00437 00438 /** 00439 * @} 00440 */ 00441 00442 00443 #endif 00444