src: simple Connection header multi-value parsing

Reviewed-By: Fedor Indutny <fedor@indutny.com>
PR-URL: https://github.com/joyent/http-parser/pull/100
make-http-max-header-size-gyp-configurable
Jon Kolb 13 years ago committed by Fedor Indutny
parent 959f4cb127
commit 091ebb8778

@ -369,12 +369,16 @@ enum header_states
, h_upgrade
, h_matching_transfer_encoding_chunked
, h_matching_connection_token_start
, h_matching_connection_keep_alive
, h_matching_connection_close
, h_matching_connection_upgrade
, h_matching_connection_token
, h_transfer_encoding_chunked
, h_connection_keep_alive
, h_connection_close
, h_connection_upgrade
};
enum http_host_state
@ -406,6 +410,8 @@ enum http_host_state
(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
(c) == '$' || (c) == ',')
#define STRICT_TOKEN(c) (tokens[(unsigned char)c])
#if HTTP_PARSER_STRICT
#define TOKEN(c) (tokens[(unsigned char)c])
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
@ -1481,11 +1487,17 @@ size_t http_parser_execute (http_parser *parser,
/* looking for 'Connection: close' */
} else if (c == 'c') {
parser->header_state = h_matching_connection_close;
} else if (c == 'u') {
parser->header_state = h_matching_connection_upgrade;
} else {
parser->header_state = h_general;
parser->header_state = h_matching_connection_token;
}
break;
/* Multi-value `Connection` header */
case h_matching_connection_token_start:
break;
default:
parser->header_state = h_general;
break;
@ -1585,12 +1597,28 @@ size_t http_parser_execute (http_parser *parser,
}
break;
case h_matching_connection_token_start:
/* looking for 'Connection: keep-alive' */
if (c == 'k') {
h_state = h_matching_connection_keep_alive;
/* looking for 'Connection: close' */
} else if (c == 'c') {
h_state = h_matching_connection_close;
} else if (c == 'u') {
h_state = h_matching_connection_upgrade;
} else if (STRICT_TOKEN(c)) {
h_state = h_matching_connection_token;
} else {
h_state = h_general;
}
break;
/* looking for 'Connection: keep-alive' */
case h_matching_connection_keep_alive:
parser->index++;
if (parser->index > sizeof(KEEP_ALIVE)-1
|| c != KEEP_ALIVE[parser->index]) {
h_state = h_general;
h_state = h_matching_connection_token;
} else if (parser->index == sizeof(KEEP_ALIVE)-2) {
h_state = h_connection_keep_alive;
}
@ -1600,16 +1628,50 @@ size_t http_parser_execute (http_parser *parser,
case h_matching_connection_close:
parser->index++;
if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
h_state = h_general;
h_state = h_matching_connection_token;
} else if (parser->index == sizeof(CLOSE)-2) {
h_state = h_connection_close;
}
break;
/* looking for 'Connection: upgrade' */
case h_matching_connection_upgrade:
parser->index++;
if (parser->index > sizeof(UPGRADE) - 1 ||
c != UPGRADE[parser->index]) {
h_state = h_matching_connection_token;
} else if (parser->index == sizeof(UPGRADE)-2) {
h_state = h_connection_upgrade;
}
break;
case h_matching_connection_token:
if (ch == ',') {
h_state = h_matching_connection_token_start;
parser->index = 0;
}
break;
case h_transfer_encoding_chunked:
if (ch != ' ') h_state = h_general;
break;
case h_connection_keep_alive:
case h_connection_close:
if (ch != ' ') h_state = h_general;
case h_connection_upgrade:
if (ch == ',') {
if (h_state == h_connection_keep_alive) {
parser->flags |= F_CONNECTION_KEEP_ALIVE;
} else if (h_state == h_connection_close) {
parser->flags |= F_CONNECTION_CLOSE;
} else if (h_state == h_connection_upgrade) {
parser->flags |= F_CONNECTION_UPGRADE;
}
h_state = h_matching_connection_token_start;
parser->index = 0;
} else if (ch != ' ') {
h_state = h_matching_connection_token;
}
break;
default:
@ -1653,6 +1715,9 @@ size_t http_parser_execute (http_parser *parser,
case h_transfer_encoding_chunked:
parser->flags |= F_CHUNKED;
break;
case h_connection_upgrade:
parser->flags |= F_CONNECTION_UPGRADE;
break;
default:
break;
}
@ -1674,6 +1739,23 @@ size_t http_parser_execute (http_parser *parser,
UPDATE_STATE(s_header_value_discard_ws);
break;
} else {
switch (parser->header_state) {
case h_connection_keep_alive:
parser->flags |= F_CONNECTION_KEEP_ALIVE;
break;
case h_connection_close:
parser->flags |= F_CONNECTION_CLOSE;
break;
case h_connection_upgrade:
parser->flags |= F_CONNECTION_UPGRADE;
break;
case h_transfer_encoding_chunked:
parser->flags |= F_CHUNKED;
break;
default:
break;
}
/* header value was empty */
MARK(header_value);
UPDATE_STATE(s_header_field_start);
@ -1697,7 +1779,9 @@ size_t http_parser_execute (http_parser *parser,
/* Set this here so that on_headers_complete() callbacks can see it */
parser->upgrade =
(parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT);
((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) ==
(F_UPGRADE | F_CONNECTION_UPGRADE) ||
parser->method == HTTP_CONNECT);
/* Here we call the headers_complete callback. This is somewhat
* different than other callbacks because if the user returns 1, we

@ -136,9 +136,10 @@ enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_TRAILING = 1 << 3
, F_UPGRADE = 1 << 4
, F_SKIPBODY = 1 << 5
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
};

@ -950,6 +950,42 @@ const struct message requests[] =
,.body= ""
}
#define CONNECTION_MULTI 35
, {.name = "multiple connection header values with folding"
,.type= HTTP_REQUEST
,.raw= "GET /demo HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: Something,\r\n"
" Upgrade, ,Keep-Alive\r\n"
"Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
"Sec-WebSocket-Protocol: sample\r\n"
"Upgrade: WebSocket\r\n"
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
"Origin: http://example.com\r\n"
"\r\n"
"Hot diggity dogg"
,.should_keep_alive= TRUE
,.message_complete_on_eof= FALSE
,.http_major= 1
,.http_minor= 1
,.method= HTTP_GET
,.query_string= ""
,.fragment= ""
,.request_path= "/demo"
,.request_url= "/demo"
,.num_headers= 7
,.upgrade="Hot diggity dogg"
,.headers= { { "Host", "example.com" }
, { "Connection", "Something, Upgrade, ,Keep-Alive" }
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
, { "Sec-WebSocket-Protocol", "sample" }
, { "Upgrade", "WebSocket" }
, { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
, { "Origin", "http://example.com" }
}
,.body= ""
}
, {.name= NULL } /* sentinel */
};

Loading…
Cancel
Save