Upgrade http-parser, fixes issue 77
http://github.com/ry/node/issues#issue/77
This commit is contained in:
parent
a63ce5cd72
commit
f919216446
1
deps/http_parser/.gitignore
vendored
1
deps/http_parser/.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
tags
|
tags
|
||||||
*.o
|
*.o
|
||||||
test
|
test
|
||||||
|
test_g
|
||||||
|
24
deps/http_parser/Makefile
vendored
24
deps/http_parser/Makefile
vendored
@ -2,17 +2,23 @@ OPT_DEBUG=-O0 -g -Wall -Wextra -Werror -I.
|
|||||||
OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 -I.
|
OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 -I.
|
||||||
|
|
||||||
|
|
||||||
test: test_debug
|
test: test_g
|
||||||
./test_debug
|
./test_g
|
||||||
|
|
||||||
test_debug: http_parser_debug.o test.c
|
test_g: http_parser_g.o test_g.o
|
||||||
gcc $(OPT_DEBUG) http_parser.o test.c -o $@
|
gcc $(OPT_DEBUG) http_parser_g.o test_g.o -o $@
|
||||||
|
|
||||||
http_parser_debug.o: http_parser.c http_parser.h Makefile
|
test_g.o: test.c Makefile
|
||||||
gcc $(OPT_DEBUG) -c http_parser.c
|
gcc $(OPT_DEBUG) -c test.c -o $@
|
||||||
|
|
||||||
test-valgrind: test_debug
|
test.o: test.c Makefile
|
||||||
valgrind ./test_debug
|
gcc $(OPT_FAST) -c test.c -o $@
|
||||||
|
|
||||||
|
http_parser_g.o: http_parser.c http_parser.h Makefile
|
||||||
|
gcc $(OPT_DEBUG) -c http_parser.c -o $@
|
||||||
|
|
||||||
|
test-valgrind: test_g
|
||||||
|
valgrind ./test_g
|
||||||
|
|
||||||
http_parser.o: http_parser.c http_parser.h Makefile
|
http_parser.o: http_parser.c http_parser.h Makefile
|
||||||
gcc $(OPT_FAST) -c http_parser.c
|
gcc $(OPT_FAST) -c http_parser.c
|
||||||
@ -28,6 +34,6 @@ tags: http_parser.c http_parser.h test.c
|
|||||||
ctags $^
|
ctags $^
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o test test_fast test_debug http_parser.tar tags
|
rm -f *.o test test_fast test_g http_parser.tar tags
|
||||||
|
|
||||||
.PHONY: clean package test-run test-run-timed test-valgrind
|
.PHONY: clean package test-run test-run-timed test-valgrind
|
||||||
|
3
deps/http_parser/http_parser.c
vendored
3
deps/http_parser/http_parser.c
vendored
@ -195,7 +195,8 @@ enum state
|
|||||||
, s_body_identity_eof
|
, s_body_identity_eof
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PARSING_HEADER(state) (state <= s_headers_almost_done)
|
|
||||||
|
#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
|
||||||
|
|
||||||
|
|
||||||
enum header_states
|
enum header_states
|
||||||
|
156
deps/http_parser/test.c
vendored
156
deps/http_parser/test.c
vendored
@ -34,6 +34,8 @@
|
|||||||
#define MAX_HEADERS 10
|
#define MAX_HEADERS 10
|
||||||
#define MAX_ELEMENT_SIZE 500
|
#define MAX_ELEMENT_SIZE 500
|
||||||
|
|
||||||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
static http_parser *parser;
|
static http_parser *parser;
|
||||||
|
|
||||||
struct message {
|
struct message {
|
||||||
@ -47,6 +49,7 @@ struct message {
|
|||||||
char fragment[MAX_ELEMENT_SIZE];
|
char fragment[MAX_ELEMENT_SIZE];
|
||||||
char query_string[MAX_ELEMENT_SIZE];
|
char query_string[MAX_ELEMENT_SIZE];
|
||||||
char body[MAX_ELEMENT_SIZE];
|
char body[MAX_ELEMENT_SIZE];
|
||||||
|
size_t body_size;
|
||||||
int num_headers;
|
int num_headers;
|
||||||
enum { NONE=0, FIELD, VALUE } last_header_element;
|
enum { NONE=0, FIELD, VALUE } last_header_element;
|
||||||
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
|
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
|
||||||
@ -597,6 +600,7 @@ const struct message responses[] =
|
|||||||
,.status_code= 404
|
,.status_code= 404
|
||||||
,.num_headers= 0
|
,.num_headers= 0
|
||||||
,.headers= {}
|
,.headers= {}
|
||||||
|
,.body_size= 0
|
||||||
,.body= ""
|
,.body= ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,6 +643,7 @@ const struct message responses[] =
|
|||||||
{ {"Content-Type", "text/plain" }
|
{ {"Content-Type", "text/plain" }
|
||||||
, {"Transfer-Encoding", "chunked" }
|
, {"Transfer-Encoding", "chunked" }
|
||||||
}
|
}
|
||||||
|
,.body_size = 37+28
|
||||||
,.body =
|
,.body =
|
||||||
"This is the data in the first chunk\r\n"
|
"This is the data in the first chunk\r\n"
|
||||||
"and this is the second one\r\n"
|
"and this is the second one\r\n"
|
||||||
@ -785,10 +790,20 @@ body_cb (http_parser *p, const char *buf, size_t len)
|
|||||||
{
|
{
|
||||||
assert(p == parser);
|
assert(p == parser);
|
||||||
strncat(messages[num_messages].body, buf, len);
|
strncat(messages[num_messages].body, buf, len);
|
||||||
|
messages[num_messages].body_size += len;
|
||||||
// printf("body_cb: '%s'\n", requests[num_messages].body);
|
// printf("body_cb: '%s'\n", requests[num_messages].body);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
count_body_cb (http_parser *p, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(p == parser);
|
||||||
|
assert(buf);
|
||||||
|
messages[num_messages].body_size += len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
message_begin_cb (http_parser *p)
|
message_begin_cb (http_parser *p)
|
||||||
{
|
{
|
||||||
@ -830,7 +845,7 @@ message_complete_cb (http_parser *p)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static http_parser_settings settings =
|
static http_parser_settings settings =
|
||||||
{.on_message_begin = message_begin_cb
|
{.on_message_begin = message_begin_cb
|
||||||
,.on_header_field = header_field_cb
|
,.on_header_field = header_field_cb
|
||||||
,.on_header_value = header_value_cb
|
,.on_header_value = header_value_cb
|
||||||
@ -843,6 +858,19 @@ static http_parser_settings settings =
|
|||||||
,.on_message_complete = message_complete_cb
|
,.on_message_complete = message_complete_cb
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static http_parser_settings settings_count_body =
|
||||||
|
{.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 = count_body_cb
|
||||||
|
,.on_headers_complete = headers_complete_cb
|
||||||
|
,.on_message_complete = message_complete_cb
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
parser_init (enum http_parser_type type)
|
parser_init (enum http_parser_type type)
|
||||||
{
|
{
|
||||||
@ -874,6 +902,14 @@ inline size_t parse (const char *buf, size_t len)
|
|||||||
return nparsed;
|
return nparsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline size_t parse_count_body (const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
size_t nparsed;
|
||||||
|
currently_parsing_eof = (len == 0);
|
||||||
|
nparsed = http_parser_execute(parser, settings_count_body, 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,
|
||||||
@ -936,7 +972,11 @@ message_eq (int index, const struct message *expected)
|
|||||||
MESSAGE_CHECK_STR_EQ(expected, m, query_string);
|
MESSAGE_CHECK_STR_EQ(expected, m, query_string);
|
||||||
MESSAGE_CHECK_STR_EQ(expected, m, fragment);
|
MESSAGE_CHECK_STR_EQ(expected, m, fragment);
|
||||||
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
|
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
|
||||||
MESSAGE_CHECK_STR_EQ(expected, m, body);
|
if (expected->body_size) {
|
||||||
|
MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
|
||||||
|
} else {
|
||||||
|
MESSAGE_CHECK_STR_EQ(expected, m, body);
|
||||||
|
}
|
||||||
|
|
||||||
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
|
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
|
||||||
|
|
||||||
@ -1030,6 +1070,42 @@ test:
|
|||||||
parser_free();
|
parser_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_message_count_body (const struct message *message)
|
||||||
|
{
|
||||||
|
parser_init(message->type);
|
||||||
|
|
||||||
|
size_t read;
|
||||||
|
size_t l = strlen(message->raw);
|
||||||
|
size_t i, toread;
|
||||||
|
size_t chunk = 4024;
|
||||||
|
|
||||||
|
for (i = 0; i < l; i+= chunk) {
|
||||||
|
toread = MIN(l-i, chunk);
|
||||||
|
read = parse_count_body(message->raw + i, toread);
|
||||||
|
if (read != toread) {
|
||||||
|
print_error(message->raw, read);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
read = parse_count_body(NULL, 0);
|
||||||
|
if (read != 0) {
|
||||||
|
print_error(message->raw, read);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_messages != 1) {
|
||||||
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!message_eq(0, message)) exit(1);
|
||||||
|
|
||||||
|
parser_free();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test_error (const char *buf)
|
test_error (const char *buf)
|
||||||
{
|
{
|
||||||
@ -1214,6 +1290,50 @@ error:
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user required to free the result
|
||||||
|
// string terminated by \0
|
||||||
|
char *
|
||||||
|
create_large_chunked_message (int body_size_in_kb, const char* headers)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t needed, wrote = 0;
|
||||||
|
size_t headers_len = strlen(headers);
|
||||||
|
size_t bufsize = headers_len + 10;
|
||||||
|
char * buf = malloc(bufsize);
|
||||||
|
|
||||||
|
strncpy(buf, headers, headers_len);
|
||||||
|
wrote += headers_len;
|
||||||
|
|
||||||
|
for (i = 0; i < body_size_in_kb; i++) {
|
||||||
|
// write 1kb chunk into the body.
|
||||||
|
needed = 5 + 1024 + 2; // "400\r\nCCCC...CCCC\r\n"
|
||||||
|
if (bufsize - wrote < needed) {
|
||||||
|
buf = realloc(buf, bufsize + needed);
|
||||||
|
bufsize += needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(buf + wrote, "400\r\n");
|
||||||
|
wrote += 5;
|
||||||
|
memset(buf + wrote, 'C', 1024);
|
||||||
|
wrote += 1024;
|
||||||
|
strcpy(buf + wrote, "\r\n");
|
||||||
|
wrote += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
needed = 5; // "0\r\n\r\n"
|
||||||
|
if (bufsize - wrote < needed) {
|
||||||
|
buf = realloc(buf, bufsize + needed);
|
||||||
|
bufsize += needed;
|
||||||
|
}
|
||||||
|
strcpy(buf + wrote, "0\r\n\r\n");
|
||||||
|
wrote += 5;
|
||||||
|
|
||||||
|
assert(buf[wrote] == 0);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (void)
|
main (void)
|
||||||
{
|
{
|
||||||
@ -1243,6 +1363,38 @@ main (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]);
|
||||||
|
test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]);
|
||||||
|
|
||||||
|
// test very large chunked response
|
||||||
|
{
|
||||||
|
char * msg = create_large_chunked_message(31337,
|
||||||
|
"HTTP/1.0 200 OK\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"\r\n");
|
||||||
|
struct message large_chunked =
|
||||||
|
{.name= "large chunked"
|
||||||
|
,.type= HTTP_RESPONSE
|
||||||
|
,.raw= msg
|
||||||
|
,.should_keep_alive= FALSE
|
||||||
|
,.message_complete_on_eof= FALSE
|
||||||
|
,.http_major= 1
|
||||||
|
,.http_minor= 0
|
||||||
|
,.status_code= 200
|
||||||
|
,.num_headers= 2
|
||||||
|
,.headers=
|
||||||
|
{ { "Transfer-Encoding", "chunked" }
|
||||||
|
, { "Content-Type", "text/plain" }
|
||||||
|
}
|
||||||
|
,.body_size= 31337*1024
|
||||||
|
};
|
||||||
|
test_message_count_body(&large_chunked);
|
||||||
|
free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
printf("response scan 1/1 ");
|
printf("response scan 1/1 ");
|
||||||
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
|
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
|
||||||
, &responses[NO_HEADERS_NO_BODY_404]
|
, &responses[NO_HEADERS_NO_BODY_404]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user