HTTP Parser and message builder / objects in plain C Snapshot
http.h
Go to the documentation of this file.
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