reduce size of http_parser object from 104 to 84 bytes by only tracking one field size

This does have some slight functional changes in cases where
MAX_FIELD_SIZE is hit, specficially if a URL is made up of many
components, each of which is smaller than MAX_FIELD_SIZE, but the
total together is greater than MAX_FIELD_SIZE, then we now might not
call callbacks for any of the components (even the ones that are
smaller than 80kb).  With the old code, it was possible to get a
callback for query_string and never get a callback for the URL (or at
least the end of the URL that is past 80kb), if the callback for the
URL would have been larger than 80kb.

(to be honest, I'm surprised that the MAX_FIELD_SIZE is implemented in
http_parser at all, instead of requiring that callers pay attention to
it, as it feels like it should be the caller's responsibility)
event_stream
Cliff Frey 15 years ago committed by Ryan Dahl
parent d95b484e41
commit 0e8ad4e003

@ -46,15 +46,20 @@ do { \
#define MARK(FOR) \ #define MARK(FOR) \
do { \ do { \
parser->FOR##_mark = p; \ parser->FOR##_mark = p; \
parser->FOR##_size = 0; \ parser->current_mark_size = 0; \
} while (0)
#define MARK_NOSIZECLEAR(FOR) \
do { \
parser->FOR##_mark = p; \
} while (0) } while (0)
#define CALLBACK_NOCLEAR(FOR) \ #define CALLBACK_NOCLEAR(FOR) \
do { \ do { \
if (parser->FOR##_mark) { \ if (parser->FOR##_mark) { \
parser->FOR##_size += p - parser->FOR##_mark; \ parser->current_mark_size += p - parser->FOR##_mark; \
if (parser->FOR##_size > MAX_FIELD_SIZE) return (p - data); \ if (parser->current_mark_size > MAX_FIELD_SIZE) return (p - data); \
if (settings->on_##FOR) { \ if (settings->on_##FOR) { \
if (0 != settings->on_##FOR(parser, \ if (0 != settings->on_##FOR(parser, \
parser->FOR##_mark, \ parser->FOR##_mark, \
@ -650,7 +655,7 @@ size_t http_parser_execute (http_parser *parser,
if (ch == '/') { if (ch == '/') {
MARK(url); MARK(url);
MARK(path); MARK_NOSIZECLEAR(path);
state = s_req_path; state = s_req_path;
break; break;
} }
@ -700,7 +705,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_req_port; state = s_req_port;
break; break;
case '/': case '/':
MARK(path); MARK_NOSIZECLEAR(path);
state = s_req_path; state = s_req_path;
break; break;
case ' ': case ' ':
@ -722,7 +727,7 @@ size_t http_parser_execute (http_parser *parser,
if (ch >= '0' && ch <= '9') break; if (ch >= '0' && ch <= '9') break;
switch (ch) { switch (ch) {
case '/': case '/':
MARK(path); MARK_NOSIZECLEAR(path);
state = s_req_path; state = s_req_path;
break; break;
case ' ': case ' ':
@ -778,7 +783,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_query_string_start: case s_req_query_string_start:
{ {
if (USUAL(ch)) { if (USUAL(ch)) {
MARK(query_string); MARK_NOSIZECLEAR(query_string);
state = s_req_query_string; state = s_req_query_string;
break; break;
} }
@ -847,7 +852,7 @@ size_t http_parser_execute (http_parser *parser,
case s_req_fragment_start: case s_req_fragment_start:
{ {
if (USUAL(ch)) { if (USUAL(ch)) {
MARK(fragment); MARK_NOSIZECLEAR(fragment);
state = s_req_fragment; state = s_req_fragment;
break; break;
} }
@ -868,7 +873,7 @@ size_t http_parser_execute (http_parser *parser,
state = s_header_field_start; state = s_header_field_start;
break; break;
case '?': case '?':
MARK(fragment); MARK_NOSIZECLEAR(fragment);
state = s_req_fragment; state = s_req_fragment;
break; break;
case '#': case '#':

@ -112,18 +112,13 @@ struct http_parser {
ssize_t body_read; ssize_t body_read;
ssize_t content_length; ssize_t content_length;
size_t current_mark_size;
const char *header_field_mark; const char *header_field_mark;
size_t header_field_size;
const char *header_value_mark; const char *header_value_mark;
size_t header_value_size;
const char *query_string_mark; const char *query_string_mark;
size_t query_string_size;
const char *path_mark; const char *path_mark;
size_t path_size;
const char *url_mark; const char *url_mark;
size_t url_size;
const char *fragment_mark; const char *fragment_mark;
size_t fragment_size;
/** READ-ONLY **/ /** READ-ONLY **/
unsigned short status_code; /* responses only */ unsigned short status_code; /* responses only */

Loading…
Cancel
Save