From 54d4efd44b6a6d9ac4430012377a4c5064fec6c6 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 22 Mar 2010 09:00:24 -0700 Subject: [PATCH] Upgrade http-parser Now at version 6f72c780f0a237a775150a9963bcdf5299685cde --- deps/http_parser/.gitignore | 3 + deps/http_parser/README.md | 32 +++--- deps/http_parser/http_parser.c | 173 +++++++++++++++++---------------- deps/http_parser/http_parser.h | 43 +++++--- deps/http_parser/test.c | 49 +++++----- src/node_http.cc | 16 ++- src/node_http.h | 10 -- src/node_http_parser.cc | 30 +++--- 8 files changed, 196 insertions(+), 160 deletions(-) create mode 100644 deps/http_parser/.gitignore diff --git a/deps/http_parser/.gitignore b/deps/http_parser/.gitignore new file mode 100644 index 0000000000..be21bae3ac --- /dev/null +++ b/deps/http_parser/.gitignore @@ -0,0 +1,3 @@ +tags +*.o +test diff --git a/deps/http_parser/README.md b/deps/http_parser/README.md index 6684cfeff2..3b1d422c66 100644 --- a/deps/http_parser/README.md +++ b/deps/http_parser/README.md @@ -4,8 +4,9 @@ HTTP Parser This is a parser for HTTP messages written in C. It parses both requests and responses. The parser is designed to be used in performance HTTP applications. It does not make any allocations, it does not buffer data, and -it can be interrupted at anytime. It only requires about 136 bytes of data -per message stream (in a web server that is per connection). +it can be interrupted at anytime. Depending on your architecture, it only +requires between 100 and 200 bytes of data per message stream (in a web +server that is per connection). Features: @@ -31,12 +32,14 @@ One `http_parser` object is used per TCP connection. Initialize the struct using `http_parser_init()` and set the callbacks. That might look something like this for a request parser: + http_parser_settings settings; + settings.on_path = my_path_callback; + settings.on_header_field = my_header_field_callback; + /* ... */ + settings.data = my_socket; + http_parser *parser = malloc(sizeof(http_parser)); http_parser_init(parser, HTTP_REQUEST); - parser->on_path = my_path_callback; - parser->on_header_field = my_header_field_callback; - /* ... */ - parser->data = my_socket; When data is received on the socket execute the parser and check for errors. @@ -54,7 +57,7 @@ When data is received on the socket execute the parser and check for errors. * Note we pass the recved==0 to http_parse_requests to signal * that EOF has been recieved. */ - nparsed = http_parser_execute(parser, buf, recved); + nparsed = http_parser_execute(parser, settings, buf, recved); if (nparsed != recved) { /* Handle error. Usually just close the connection. */ @@ -63,13 +66,13 @@ When data is received on the socket execute the parser and check for errors. HTTP needs to know where the end of the stream is. For example, sometimes servers send responses without Content-Length and expect the client to consume input (for the body) until EOF. To tell http_parser about EOF, give -`0` as the third parameter to `http_parser_execute()`. Callbacks and errors +`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors can still be encountered during an EOF, so one must still be prepared to receive them. Scalar valued message information such as `status_code`, `method`, and the HTTP version are stored in the parser structure. This data is only -temporarlly stored in `http_parser` and gets reset on each new message. If +temporally stored in `http_parser` and gets reset on each new message. If this information is needed later, copy it out of the structure during the `headers_complete` callback. @@ -85,10 +88,10 @@ parser, for example, would not want such a feature. Callbacks --------- -During the `http_parser_execute()` call, the callbacks set in `http_parser` -will be executed. The parser maintains state and never looks behind, so -buffering the data is not necessary. If you need to save certain data for -later usage, you can do that from the callbacks. +During the `http_parser_execute()` call, the callbacks set in +`http_parser_settings` will be executed. The parser maintains state and +never looks behind, so buffering the data is not necessary. If you need to +save certain data for later usage, you can do that from the callbacks. There are two types of callbacks: @@ -98,6 +101,9 @@ There are two types of callbacks: Callbacks: (requests only) on_path, on_query_string, on_uri, on_fragment, (common) on_header_field, on_header_value, on_body; +Callbacks must return 0 on success. Returning a non-zero value indicates +error to the parser, making it exit immediately. + In case you parse HTTP message in chunks (i.e. `read()` request line from socket, parse, read half headers, parse, etc) your data callbacks may be called more than once. Http-parser guarantees that data pointer is only diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c index 36257fd013..7e79290a34 100644 --- a/deps/http_parser/http_parser.c +++ b/deps/http_parser/http_parser.c @@ -24,88 +24,65 @@ #include #include #include -#include /* strncmp */ +#include -#ifndef NULL -# define NULL ((void*)0) -#endif #ifndef MIN # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif + #define MAX_FIELD_SIZE (80*1024) +#define CALLBACK2(FOR) \ +do { \ + if (settings.on_##FOR) { \ + if (0 != settings.on_##FOR(parser)) return (p - data); \ + } \ +} while (0) + + #define MARK(FOR) \ do { \ parser->FOR##_mark = p; \ parser->FOR##_size = 0; \ } while (0) -#define CALLBACK(FOR) \ -do { \ - if (0 != FOR##_callback(parser, p)) return (p - data); \ - parser->FOR##_mark = NULL; \ -} while (0) #define CALLBACK_NOCLEAR(FOR) \ do { \ - if (0 != FOR##_callback(parser, p)) return (p - data); \ + if (parser->FOR##_mark) { \ + parser->FOR##_size += p - parser->FOR##_mark; \ + if (parser->FOR##_size > MAX_FIELD_SIZE) return (p - data); \ + if (settings.on_##FOR) { \ + if (0 != settings.on_##FOR(parser, \ + parser->FOR##_mark, \ + p - parser->FOR##_mark)) \ + { \ + return (p - data); \ + } \ + } \ + } \ } while (0) -#define CALLBACK2(FOR) \ + +#define CALLBACK(FOR) \ do { \ - if (0 != FOR##_callback(parser)) return (p - data); \ + CALLBACK_NOCLEAR(FOR); \ + parser->FOR##_mark = NULL; \ } while (0) -#define DEFINE_CALLBACK(FOR) \ -static inline int FOR##_callback (http_parser *parser, const char *p) \ -{ \ - if (!parser->FOR##_mark) return 0; \ - assert(parser->FOR##_mark); \ - const char *mark = parser->FOR##_mark; \ - parser->FOR##_size += p - mark; \ - if (parser->FOR##_size > MAX_FIELD_SIZE) return -1; \ - int r = 0; \ - if (parser->on_##FOR) r = parser->on_##FOR(parser, mark, p - mark); \ - return r; \ -} - -DEFINE_CALLBACK(url) -DEFINE_CALLBACK(path) -DEFINE_CALLBACK(query_string) -DEFINE_CALLBACK(fragment) -DEFINE_CALLBACK(header_field) -DEFINE_CALLBACK(header_value) - -static inline int headers_complete_callback (http_parser *parser) -{ - if (parser->on_headers_complete == NULL) return 0; - return parser->on_headers_complete(parser); -} - -static inline int message_begin_callback (http_parser *parser) -{ - if (parser->on_message_begin == NULL) return 0; - return parser->on_message_begin(parser); -} - -static inline int message_complete_callback (http_parser *parser) -{ - if (parser->on_message_complete == NULL) return 0; - return parser->on_message_complete(parser); -} #define PROXY_CONNECTION "proxy-connection" #define CONNECTION "connection" #define CONTENT_LENGTH "content-length" #define TRANSFER_ENCODING "transfer-encoding" - #define CHUNKED "chunked" #define KEEP_ALIVE "keep-alive" #define CLOSE "close" + static const unsigned char lowcase[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" @@ -116,6 +93,7 @@ static const unsigned char lowcase[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + static const int unhex[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 @@ -128,6 +106,7 @@ static const int unhex[] = }; + static const uint32_t usual[] = { 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */ @@ -148,6 +127,7 @@ static const uint32_t usual[] = { #define USUAL(c) (usual[c >> 5] & (1 << (c & 0x1f))) + enum state { s_dead = 1 /* important that this is > 0 */ @@ -216,6 +196,7 @@ enum state #define PARSING_HEADER(state) (state <= s_headers_almost_done) + enum header_states { h_general = 0 , h_C @@ -240,6 +221,7 @@ enum header_states , h_connection_close }; + enum flags { F_CHUNKED = 1 << 0 , F_CONNECTION_KEEP_ALIVE = 1 << 1 @@ -247,12 +229,15 @@ enum flags , F_TRAILING = 1 << 3 }; + #define CR '\r' #define LF '\n' #define LOWER(c) (unsigned char)(c | 0x20) + #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) + #if HTTP_PARSER_STRICT # define STRICT_CHECK(cond) if (cond) goto error # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) @@ -261,7 +246,38 @@ enum flags # define NEW_MESSAGE() start_state #endif + +#define ngx_str3_cmp(m, c0, c1, c2) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 + +#define ngx_str3Ocmp(m, c0, c1, c2, c3) \ + m[0] == c0 && m[2] == c2 && m[3] == c3 + +#define ngx_str4cmp(m, c0, c1, c2, c3) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 + +#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4 + +#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 + +#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 && m[6] == c6 + +#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 + +#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ + m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \ + && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8 + + size_t http_parser_execute (http_parser *parser, + http_parser_settings settings, const char *data, size_t len) { @@ -269,8 +285,8 @@ size_t http_parser_execute (http_parser *parser, const char *p = data, *pe; ssize_t to_read; - enum state state = parser->state; - enum header_states header_state = parser->header_state; + enum state state = (enum state) parser->state; + enum header_states header_state = (enum header_states) parser->header_state; size_t index = parser->index; size_t nread = parser->nread; @@ -462,7 +478,7 @@ size_t http_parser_execute (http_parser *parser, if (ch < 'A' || 'Z' < ch) goto error; - parser->method = 0; + parser->method = (enum http_method) 0; index = 0; parser->buffer[0] = ch; state = s_req_method; @@ -474,16 +490,14 @@ size_t http_parser_execute (http_parser *parser, assert(index+1 < HTTP_PARSER_MAX_METHOD_LEN); parser->buffer[index+1] = '\0'; - /* TODO Instead of using strncmp() use NGINX's ngx_str3Ocmp() */ - switch (index+1) { case 3: - if (strncmp(parser->buffer, "GET", 3) == 0) { + if (ngx_str3_cmp(parser->buffer, 'G', 'E', 'T')) { parser->method = HTTP_GET; break; } - if (strncmp(parser->buffer, "PUT", 3) == 0) { + if (ngx_str3_cmp(parser->buffer, 'P', 'U', 'T')) { parser->method = HTTP_PUT; break; } @@ -491,22 +505,22 @@ size_t http_parser_execute (http_parser *parser, break; case 4: - if (strncmp(parser->buffer, "POST", 4) == 0) { + if (ngx_str4cmp(parser->buffer, 'P', 'O', 'S', 'T')) { parser->method = HTTP_POST; break; } - if (strncmp(parser->buffer, "HEAD", 4) == 0) { + if (ngx_str4cmp(parser->buffer, 'H', 'E', 'A', 'D')) { parser->method = HTTP_HEAD; break; } - if (strncmp(parser->buffer, "COPY", 4) == 0) { + if (ngx_str4cmp(parser->buffer, 'C', 'O', 'P', 'Y')) { parser->method = HTTP_COPY; break; } - if (strncmp(parser->buffer, "MOVE", 4) == 0) { + if (ngx_str4cmp(parser->buffer, 'M', 'O', 'V', 'E')) { parser->method = HTTP_MOVE; break; } @@ -514,12 +528,12 @@ size_t http_parser_execute (http_parser *parser, break; case 5: - if (strncmp(parser->buffer, "MKCOL", 5) == 0) { + if (ngx_str5cmp(parser->buffer, 'M', 'K', 'C', 'O', 'L')) { parser->method = HTTP_MKCOL; break; } - if (strncmp(parser->buffer, "TRACE", 5) == 0) { + if (ngx_str5cmp(parser->buffer, 'T', 'R', 'A', 'C', 'E')) { parser->method = HTTP_TRACE; break; } @@ -527,12 +541,12 @@ size_t http_parser_execute (http_parser *parser, break; case 6: - if (strncmp(parser->buffer, "DELETE", 6) == 0) { + if (ngx_str6cmp(parser->buffer, 'D', 'E', 'L', 'E', 'T', 'E')) { parser->method = HTTP_DELETE; break; } - if (strncmp(parser->buffer, "UNLOCK", 6) == 0) { + if (ngx_str6cmp(parser->buffer, 'U', 'N', 'L', 'O', 'C', 'K')) { parser->method = HTTP_UNLOCK; break; } @@ -540,12 +554,14 @@ size_t http_parser_execute (http_parser *parser, break; case 7: - if (strncmp(parser->buffer, "OPTIONS", 7) == 0) { + if (ngx_str7_cmp(parser->buffer, + 'O', 'P', 'T', 'I', 'O', 'N', 'S', '\0')) { parser->method = HTTP_OPTIONS; break; } - if (strncmp(parser->buffer, "CONNECT", 7) == 0) { + if (ngx_str7_cmp(parser->buffer, + 'C', 'O', 'N', 'N', 'E', 'C', 'T', '\0')) { parser->method = HTTP_CONNECT; break; } @@ -553,7 +569,8 @@ size_t http_parser_execute (http_parser *parser, break; case 8: - if (strncmp(parser->buffer, "PROPFIND", 8) == 0) { + if (ngx_str8cmp(parser->buffer, + 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) { parser->method = HTTP_PROPFIND; break; } @@ -561,7 +578,8 @@ size_t http_parser_execute (http_parser *parser, break; case 9: - if (strncmp(parser->buffer, "PROPPATCH", 9) == 0) { + if (ngx_str9cmp(parser->buffer, + 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) { parser->method = HTTP_PROPPATCH; break; } @@ -1311,7 +1329,7 @@ size_t http_parser_execute (http_parser *parser, case s_body_identity: to_read = MIN(pe - p, (ssize_t)(parser->content_length - parser->body_read)); if (to_read > 0) { - if (parser->on_body) parser->on_body(parser, p, to_read); + if (settings.on_body) settings.on_body(parser, p, to_read); p += to_read - 1; parser->body_read += to_read; if (parser->body_read == parser->content_length) { @@ -1325,7 +1343,7 @@ size_t http_parser_execute (http_parser *parser, case s_body_identity_eof: to_read = pe - p; if (to_read > 0) { - if (parser->on_body) parser->on_body(parser, p, to_read); + if (settings.on_body) settings.on_body(parser, p, to_read); p += to_read - 1; parser->body_read += to_read; } @@ -1398,7 +1416,7 @@ size_t http_parser_execute (http_parser *parser, to_read = MIN(pe - p, (ssize_t)(parser->content_length)); if (to_read > 0) { - if (parser->on_body) parser->on_body(parser, p, to_read); + if (settings.on_body) settings.on_body(parser, p, to_read); p += to_read - 1; } @@ -1475,17 +1493,6 @@ http_parser_init (http_parser *parser, enum http_parser_type t) parser->state = (t == HTTP_REQUEST ? s_start_req : s_start_res); parser->nread = 0; - parser->on_message_begin = NULL; - parser->on_path = NULL; - parser->on_query_string = NULL; - parser->on_url = NULL; - parser->on_fragment = NULL; - parser->on_header_field = NULL; - parser->on_header_value = NULL; - parser->on_headers_complete = NULL; - parser->on_body = NULL; - parser->on_message_complete = NULL; - parser->header_field_mark = NULL; parser->header_value_mark = NULL; parser->query_string_mark = NULL; diff --git a/deps/http_parser/http_parser.h b/deps/http_parser/http_parser.h index 7fb00840fe..5b648fa9f6 100644 --- a/deps/http_parser/http_parser.h +++ b/deps/http_parser/http_parser.h @@ -24,11 +24,10 @@ extern "C" { #endif -#ifdef _MSC_VER -# include -#endif + #include + /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run * faster */ @@ -38,12 +37,16 @@ extern "C" { # define HTTP_PARSER_STRICT 0 #endif + /* Maximium header size allowed */ #define HTTP_MAX_HEADER_SIZE (80*1024) -typedef struct http_parser http_parser; -/* Callbacks should return non-zero to indicate an error. The parse will +typedef struct http_parser http_parser; +typedef struct http_parser_settings http_parser_settings; + + +/* Callbacks should return non-zero to indicate an error. The parser will * then halt execution. * * http_data_cb does not return data chunks. It will be call arbitrarally @@ -53,9 +56,11 @@ typedef struct http_parser http_parser; typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); typedef int (*http_cb) (http_parser*); + /* Should be at least one longer than the longest request method */ #define HTTP_PARSER_MAX_METHOD_LEN 10 + /* Request Methods */ enum http_method { HTTP_DELETE = 0x0001 @@ -77,8 +82,10 @@ enum http_method , HTTP_UNLOCK = 0x4000 }; + enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE }; + struct http_parser { /** PRIVATE **/ enum http_parser_type type; @@ -114,17 +121,15 @@ struct http_parser { /** PUBLIC **/ void *data; /* A pointer to get hook to the "connection" or "socket" object */ +}; - /* an ordered list of callbacks */ +struct http_parser_settings { http_cb on_message_begin; - - /* requests only */ http_data_cb on_path; http_data_cb on_query_string; http_data_cb on_url; http_data_cb on_fragment; - http_data_cb on_header_field; http_data_cb on_header_value; http_cb on_headers_complete; @@ -132,15 +137,25 @@ struct http_parser { http_cb on_message_complete; }; + void http_parser_init(http_parser *parser, enum http_parser_type type); -size_t http_parser_execute(http_parser *parser, const char *data, size_t len); -/* Call this in the on_headers_complete or on_message_complete callback to - * determine if this will be the last message on the connection. - * If you are the server, respond with the "Connection: close" header - * if you are the client, close the connection. + + +size_t http_parser_execute(http_parser *parser, + http_parser_settings settings, + const char *data, + size_t len); + + +/* If http_should_keep_alive() in the on_headers_complete or + * on_message_complete callback returns true, then this will be should be + * the last message on the connection. + * If you are the server, respond with the "Connection: close" header. + * If you are the client, close the connection. */ int http_should_keep_alive(http_parser *parser); + #ifdef __cplusplus } #endif diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c index 63d4800186..ed08854e3f 100644 --- a/deps/http_parser/test.c +++ b/deps/http_parser/test.c @@ -63,14 +63,6 @@ struct message { static int currently_parsing_eof; -inline size_t parse (const char *buf, size_t len) -{ - size_t nparsed; - currently_parsing_eof = (len == 0); - nparsed = http_parser_execute(parser, buf, len); - return nparsed; -} - static struct message messages[5]; static int num_messages; @@ -802,6 +794,19 @@ message_complete_cb (http_parser *p) return 0; } +static http_parser_settings settings = + {.on_message_begin = message_begin_cb + ,.on_header_field = header_field_cb + ,.on_header_value = header_value_cb + ,.on_path = request_path_cb + ,.on_url = request_url_cb + ,.on_fragment = fragment_cb + ,.on_query_string = query_string_cb + ,.on_body = body_cb + ,.on_headers_complete = headers_complete_cb + ,.on_message_complete = message_complete_cb + }; + void parser_init (enum http_parser_type type) { @@ -815,16 +820,6 @@ parser_init (enum http_parser_type type) memset(&messages, 0, sizeof messages); - parser->on_message_begin = message_begin_cb; - parser->on_header_field = header_field_cb; - parser->on_header_value = header_value_cb; - parser->on_path = request_path_cb; - parser->on_url = request_url_cb; - parser->on_fragment = fragment_cb; - parser->on_query_string = query_string_cb; - parser->on_body = body_cb; - parser->on_headers_complete = headers_complete_cb; - parser->on_message_complete = message_complete_cb; } void @@ -835,6 +830,14 @@ parser_free () parser = NULL; } +inline size_t parse (const char *buf, size_t len) +{ + size_t nparsed; + currently_parsing_eof = (len == 0); + nparsed = http_parser_execute(parser, settings, buf, len); + return nparsed; +} + static inline int check_str_eq (const struct message *m, const char *prop, @@ -950,7 +953,7 @@ print_error (const char *raw, size_t error_location) for (j = 0; j < error_location_line; j++) { fputc(' ', stderr); } - fprintf(stderr, "^\n\nerror location: %d\n", error_location); + fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location); } @@ -1142,9 +1145,9 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess error: fprintf(stderr, "i=%d j=%d\n", i, j); - fprintf(stderr, "buf1 (%d) %s\n\n", buf1_len, buf1); - fprintf(stderr, "buf2 (%d) %s\n\n", buf2_len , buf2); - fprintf(stderr, "buf3 (%d) %s\n", buf3_len, buf3); + fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1); + fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2); + fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3); exit(1); } @@ -1156,7 +1159,7 @@ main (void) int request_count; int response_count; - printf("sizeof(http_parser) = %d\n", sizeof(http_parser)); + printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser)); for (request_count = 0; requests[request_count].name; request_count++); for (response_count = 0; responses[response_count].name; response_count++); diff --git a/src/node_http.cc b/src/node_http.cc index 4f49967322..30cc93bd29 100644 --- a/src/node_http.cc +++ b/src/node_http.cc @@ -46,6 +46,8 @@ static Persistent proppatch_sym; static Persistent unlock_sym; static Persistent unknown_method_sym; +static struct http_parser_settings settings; + void HTTPConnection::Initialize (Handle target) { @@ -68,6 +70,16 @@ HTTPConnection::Initialize (Handle target) end_symbol = NODE_PSYMBOL("end"); + settings.on_message_begin = on_message_begin; + settings.on_path = on_path; + settings.on_query_string = on_query_string; + settings.on_url = on_url; + settings.on_fragment = on_fragment; + settings.on_header_field = on_header_field; + settings.on_header_value = on_header_value; + settings.on_headers_complete = on_headers_complete; + settings.on_body = on_body; + settings.on_message_complete = on_message_complete; } Handle @@ -109,7 +121,7 @@ HTTPConnection::OnReceive (const void *buf, size_t len) assert(refs_); size_t nparsed; - nparsed = http_parser_execute(&parser_, static_cast(buf), len); + nparsed = http_parser_execute(&parser_, settings, static_cast(buf), len); if (nparsed != len) { ForceClose(); @@ -122,7 +134,7 @@ HTTPConnection::OnEOF () HandleScope scope; assert(refs_); size_t nparsed; - nparsed = http_parser_execute(&parser_, NULL, 0); + nparsed = http_parser_execute(&parser_, settings, NULL, 0); Emit(end_symbol, 0, NULL); } diff --git a/src/node_http.h b/src/node_http.h index ad368b3a1f..0b1b6ac07b 100644 --- a/src/node_http.h +++ b/src/node_http.h @@ -28,16 +28,6 @@ protected: void ResetParser() { http_parser_init (&parser_, type_); - parser_.on_message_begin = on_message_begin; - parser_.on_url = on_url; - parser_.on_path = on_path; - parser_.on_fragment = on_fragment; - parser_.on_query_string = on_query_string; - parser_.on_header_field = on_header_field; - parser_.on_header_value = on_header_value; - parser_.on_headers_complete = on_headers_complete; - parser_.on_body = on_body; - parser_.on_message_complete = on_message_complete; parser_.data = this; } diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 083f496dea..e5dbed38f1 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -27,8 +27,6 @@ namespace node { using namespace v8; - static int deep = 0; - static Persistent on_message_begin_sym; static Persistent on_path_sym; static Persistent on_query_string_sym; @@ -64,6 +62,8 @@ static Persistent version_major_sym; static Persistent version_minor_sym; static Persistent should_keep_alive_sym; +static struct http_parser_settings settings; + // Callback prototype for http_cb #define DEFINE_HTTP_CB(name) \ static int name(http_parser *p) { \ @@ -231,7 +231,7 @@ class Parser : public ObjectWrap { parser->buffer_ = buffer; size_t nparsed = - http_parser_execute(&parser->parser_, buffer->data()+off, len); + http_parser_execute(&parser->parser_, settings, buffer->data()+off, len); // Unassign the 'buffer_' variable assert(parser->buffer_); @@ -261,7 +261,7 @@ class Parser : public ObjectWrap { assert(!parser->buffer_); - http_parser_execute(&(parser->parser_), NULL, 0); + http_parser_execute(&(parser->parser_), settings, NULL, 0); return Undefined(); } @@ -290,17 +290,6 @@ class Parser : public ObjectWrap { assert(buffer_ == NULL); // don't call this during Execute() http_parser_init(&parser_, type); - parser_.on_message_begin = on_message_begin; - parser_.on_path = on_path; - parser_.on_query_string = on_query_string; - parser_.on_url = on_url; - parser_.on_fragment = on_fragment; - parser_.on_header_field = on_header_field; - parser_.on_header_value = on_header_value; - parser_.on_headers_complete = on_headers_complete; - parser_.on_body = on_body; - parser_.on_message_complete = on_message_complete; - parser_.data = this; } @@ -356,6 +345,17 @@ void InitHttpParser(Handle target) { version_major_sym = NODE_PSYMBOL("versionMajor"); version_minor_sym = NODE_PSYMBOL("versionMinor"); should_keep_alive_sym = NODE_PSYMBOL("shouldKeepAlive"); + + settings.on_message_begin = Parser::on_message_begin; + settings.on_path = Parser::on_path; + settings.on_query_string = Parser::on_query_string; + settings.on_url = Parser::on_url; + settings.on_fragment = Parser::on_fragment; + settings.on_header_field = Parser::on_header_field; + settings.on_header_value = Parser::on_header_value; + settings.on_headers_complete = Parser::on_headers_complete; + settings.on_body = Parser::on_body; + settings.on_message_complete = Parser::on_message_complete; } } // namespace node