parser: returning 2 from on_headers_complete

Returning `2` from on_headers_complete will tell parser that it
should not expect neither a body nor any futher responses on
this connection. This is useful for handling responses to a
CONNECT request which may not contain `Upgrade` or
`Connection: upgrade` headers.

See: https://github.com/nodejs/node/pull/6198
PR-URL: https://github.com/nodejs/http-parser/pull/299
Reviewed-By: Brian White <mscdex@mscdex.net>
make-http-max-header-size-gyp-configurable
Fedor Indutny 9 years ago
parent 5651aea804
commit 04d28a7377

@ -1812,6 +1812,9 @@ reexecute:
case 0: case 0:
break; break;
case 2:
parser->upgrade = 1;
case 1: case 1:
parser->flags |= F_SKIPBODY; parser->flags |= F_SKIPBODY;
break; break;

@ -77,6 +77,11 @@ typedef struct http_parser_settings http_parser_settings;
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body. * chunked' headers that indicate the presence of a body.
* *
* Returning `2` from on_headers_complete will tell parser that it should not
* expect neither a body nor any futher responses on this connection. This is
* useful for handling responses to a CONNECT request which may not contain
* `Upgrade` or `Connection: upgrade` headers.
*
* http_data_cb does not return data chunks. It will be called arbitrarily * http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url" * many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data. * each providing just a few characters more data.

103
test.c

@ -2173,6 +2173,20 @@ pause_chunk_complete_cb (http_parser *p)
return chunk_complete_cb(p); return chunk_complete_cb(p);
} }
int
connect_headers_complete_cb (http_parser *p)
{
headers_complete_cb(p);
return 1;
}
int
connect_message_complete_cb (http_parser *p)
{
messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
return message_complete_cb(p);
}
static http_parser_settings settings_pause = static http_parser_settings settings_pause =
{.on_message_begin = pause_message_begin_cb {.on_message_begin = pause_message_begin_cb
,.on_header_field = pause_header_field_cb ,.on_header_field = pause_header_field_cb
@ -2212,6 +2226,19 @@ static http_parser_settings settings_count_body =
,.on_chunk_complete = chunk_complete_cb ,.on_chunk_complete = chunk_complete_cb
}; };
static http_parser_settings settings_connect =
{.on_message_begin = message_begin_cb
,.on_header_field = header_field_cb
,.on_header_value = header_value_cb
,.on_url = request_url_cb
,.on_status = response_status_cb
,.on_body = dontcall_body_cb
,.on_headers_complete = connect_headers_complete_cb
,.on_message_complete = connect_message_complete_cb
,.on_chunk_header = chunk_header_cb
,.on_chunk_complete = chunk_complete_cb
};
static http_parser_settings settings_null = static http_parser_settings settings_null =
{.on_message_begin = 0 {.on_message_begin = 0
,.on_header_field = 0 ,.on_header_field = 0
@ -2275,6 +2302,14 @@ size_t parse_pause (const char *buf, size_t len)
return nparsed; return nparsed;
} }
size_t parse_connect (const char *buf, size_t len)
{
size_t nparsed;
currently_parsing_eof = (len == 0);
nparsed = http_parser_execute(parser, &settings_connect, buf, len);
return nparsed;
}
static inline int static inline int
check_str_eq (const struct message *m, check_str_eq (const struct message *m,
const char *prop, const char *prop,
@ -2331,7 +2366,7 @@ do { \
} while(0) } while(0)
int int
message_eq (int index, const struct message *expected) message_eq (int index, int connect, const struct message *expected)
{ {
int i; int i;
struct message *m = &messages[index]; struct message *m = &messages[index];
@ -2346,8 +2381,10 @@ message_eq (int index, const struct message *expected)
MESSAGE_CHECK_STR_EQ(expected, m, response_status); MESSAGE_CHECK_STR_EQ(expected, m, response_status);
} }
MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); if (!connect) {
MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
}
assert(m->message_begin_cb_called); assert(m->message_begin_cb_called);
assert(m->headers_complete_cb_called); assert(m->headers_complete_cb_called);
@ -2385,16 +2422,22 @@ message_eq (int index, const struct message *expected)
MESSAGE_CHECK_NUM_EQ(expected, m, port); MESSAGE_CHECK_NUM_EQ(expected, m, port);
} }
if (expected->body_size) { if (connect) {
check_num_eq(m, "body_size", 0, m->body_size);
} else if (expected->body_size) {
MESSAGE_CHECK_NUM_EQ(expected, m, body_size); MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
} else { } else {
MESSAGE_CHECK_STR_EQ(expected, m, body); MESSAGE_CHECK_STR_EQ(expected, m, body);
} }
assert(m->num_chunks == m->num_chunks_complete); if (connect) {
MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete); check_num_eq(m, "num_chunks_complete", 0, m->num_chunks_complete);
for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) { } else {
MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]); assert(m->num_chunks == m->num_chunks_complete);
MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete);
for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) {
MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]);
}
} }
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
@ -3201,7 +3244,7 @@ test_message (const struct message *message)
abort(); abort();
} }
if(!message_eq(0, message)) abort(); if(!message_eq(0, 0, message)) abort();
parser_free(); parser_free();
} }
@ -3238,7 +3281,7 @@ test_message_count_body (const struct message *message)
abort(); abort();
} }
if(!message_eq(0, message)) abort(); if(!message_eq(0, 0, message)) abort();
parser_free(); parser_free();
} }
@ -3589,9 +3632,9 @@ test:
abort(); abort();
} }
if (!message_eq(0, r1)) abort(); if (!message_eq(0, 0, r1)) abort();
if (message_count > 1 && !message_eq(1, r2)) abort(); if (message_count > 1 && !message_eq(1, 0, r2)) abort();
if (message_count > 2 && !message_eq(2, r3)) abort(); if (message_count > 2 && !message_eq(2, 0, r3)) abort();
parser_free(); parser_free();
} }
@ -3687,17 +3730,17 @@ test:
goto error; goto error;
} }
if (!message_eq(0, r1)) { if (!message_eq(0, 0, r1)) {
fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
goto error; goto error;
} }
if (message_count > 1 && !message_eq(1, r2)) { if (message_count > 1 && !message_eq(1, 0, r2)) {
fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
goto error; goto error;
} }
if (message_count > 2 && !message_eq(2, r3)) { if (message_count > 2 && !message_eq(2, 0, r3)) {
fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
goto error; goto error;
} }
@ -3796,7 +3839,29 @@ test:
abort(); abort();
} }
if(!message_eq(0, msg)) abort(); if(!message_eq(0, 0, msg)) abort();
parser_free();
}
/* Verify that body and next message won't be parsed in responses to CONNECT */
void
test_message_connect (const struct message *msg)
{
char *buf = (char*) msg->raw;
size_t buflen = strlen(msg->raw);
size_t nread;
parser_init(msg->type);
nread = parse_connect(buf, buflen);
if (num_messages != 1) {
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
abort();
}
if(!message_eq(0, 1, msg)) abort();
parser_free(); parser_free();
} }
@ -3867,6 +3932,10 @@ main (void)
test_message_pause(&responses[i]); test_message_pause(&responses[i]);
} }
for (i = 0; i < response_count; i++) {
test_message_connect(&responses[i]);
}
for (i = 0; i < response_count; i++) { for (i = 0; i < response_count; i++) {
if (!responses[i].should_keep_alive) continue; if (!responses[i].should_keep_alive) continue;
for (j = 0; j < response_count; j++) { for (j = 0; j < response_count; j++) {

Loading…
Cancel
Save