Skip to content

Commit f919216

Browse files
committed
Upgrade http-parser, fixes issue 77
https://github.com/ry/node/issues#issue/77
1 parent a63ce5c commit f919216

4 files changed

Lines changed: 172 additions & 12 deletions

File tree

deps/http_parser/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
tags
22
*.o
33
test
4+
test_g

deps/http_parser/Makefile

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ OPT_DEBUG=-O0 -g -Wall -Wextra -Werror -I.
22
OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 -I.
33

44

5-
test: test_debug
6-
./test_debug
5+
test: test_g
6+
./test_g
77

8-
test_debug: http_parser_debug.o test.c
9-
gcc $(OPT_DEBUG) http_parser.o test.c -o $@
8+
test_g: http_parser_g.o test_g.o
9+
gcc $(OPT_DEBUG) http_parser_g.o test_g.o -o $@
1010

11-
http_parser_debug.o: http_parser.c http_parser.h Makefile
12-
gcc $(OPT_DEBUG) -c http_parser.c
11+
test_g.o: test.c Makefile
12+
gcc $(OPT_DEBUG) -c test.c -o $@
1313

14-
test-valgrind: test_debug
15-
valgrind ./test_debug
14+
test.o: test.c Makefile
15+
gcc $(OPT_FAST) -c test.c -o $@
16+
17+
http_parser_g.o: http_parser.c http_parser.h Makefile
18+
gcc $(OPT_DEBUG) -c http_parser.c -o $@
19+
20+
test-valgrind: test_g
21+
valgrind ./test_g
1622

1723
http_parser.o: http_parser.c http_parser.h Makefile
1824
gcc $(OPT_FAST) -c http_parser.c
@@ -28,6 +34,6 @@ tags: http_parser.c http_parser.h test.c
2834
ctags $^
2935

3036
clean:
31-
rm -f *.o test test_fast test_debug http_parser.tar tags
37+
rm -f *.o test test_fast test_g http_parser.tar tags
3238

3339
.PHONY: clean package test-run test-run-timed test-valgrind

deps/http_parser/http_parser.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ enum state
195195
, s_body_identity_eof
196196
};
197197

198-
#define PARSING_HEADER(state) (state <= s_headers_almost_done)
198+
199+
#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
199200

200201

201202
enum header_states

deps/http_parser/test.c

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define MAX_HEADERS 10
3535
#define MAX_ELEMENT_SIZE 500
3636

37+
#define MIN(a,b) ((a) < (b) ? (a) : (b))
38+
3739
static http_parser *parser;
3840

3941
struct message {
@@ -47,6 +49,7 @@ struct message {
4749
char fragment[MAX_ELEMENT_SIZE];
4850
char query_string[MAX_ELEMENT_SIZE];
4951
char body[MAX_ELEMENT_SIZE];
52+
size_t body_size;
5053
int num_headers;
5154
enum { NONE=0, FIELD, VALUE } last_header_element;
5255
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
@@ -597,6 +600,7 @@ const struct message responses[] =
597600
,.status_code= 404
598601
,.num_headers= 0
599602
,.headers= {}
603+
,.body_size= 0
600604
,.body= ""
601605
}
602606

@@ -639,6 +643,7 @@ const struct message responses[] =
639643
{ {"Content-Type", "text/plain" }
640644
, {"Transfer-Encoding", "chunked" }
641645
}
646+
,.body_size = 37+28
642647
,.body =
643648
"This is the data in the first chunk\r\n"
644649
"and this is the second one\r\n"
@@ -785,10 +790,20 @@ body_cb (http_parser *p, const char *buf, size_t len)
785790
{
786791
assert(p == parser);
787792
strncat(messages[num_messages].body, buf, len);
793+
messages[num_messages].body_size += len;
788794
// printf("body_cb: '%s'\n", requests[num_messages].body);
789795
return 0;
790796
}
791797

798+
int
799+
count_body_cb (http_parser *p, const char *buf, size_t len)
800+
{
801+
assert(p == parser);
802+
assert(buf);
803+
messages[num_messages].body_size += len;
804+
return 0;
805+
}
806+
792807
int
793808
message_begin_cb (http_parser *p)
794809
{
@@ -830,7 +845,7 @@ message_complete_cb (http_parser *p)
830845
return 0;
831846
}
832847

833-
static http_parser_settings settings =
848+
static http_parser_settings settings =
834849
{.on_message_begin = message_begin_cb
835850
,.on_header_field = header_field_cb
836851
,.on_header_value = header_value_cb
@@ -843,6 +858,19 @@ static http_parser_settings settings =
843858
,.on_message_complete = message_complete_cb
844859
};
845860

861+
static http_parser_settings settings_count_body =
862+
{.on_message_begin = message_begin_cb
863+
,.on_header_field = header_field_cb
864+
,.on_header_value = header_value_cb
865+
,.on_path = request_path_cb
866+
,.on_url = request_url_cb
867+
,.on_fragment = fragment_cb
868+
,.on_query_string = query_string_cb
869+
,.on_body = count_body_cb
870+
,.on_headers_complete = headers_complete_cb
871+
,.on_message_complete = message_complete_cb
872+
};
873+
846874
void
847875
parser_init (enum http_parser_type type)
848876
{
@@ -874,6 +902,14 @@ inline size_t parse (const char *buf, size_t len)
874902
return nparsed;
875903
}
876904

905+
inline size_t parse_count_body (const char *buf, size_t len)
906+
{
907+
size_t nparsed;
908+
currently_parsing_eof = (len == 0);
909+
nparsed = http_parser_execute(parser, settings_count_body, buf, len);
910+
return nparsed;
911+
}
912+
877913
static inline int
878914
check_str_eq (const struct message *m,
879915
const char *prop,
@@ -936,7 +972,11 @@ message_eq (int index, const struct message *expected)
936972
MESSAGE_CHECK_STR_EQ(expected, m, query_string);
937973
MESSAGE_CHECK_STR_EQ(expected, m, fragment);
938974
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
939-
MESSAGE_CHECK_STR_EQ(expected, m, body);
975+
if (expected->body_size) {
976+
MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
977+
} else {
978+
MESSAGE_CHECK_STR_EQ(expected, m, body);
979+
}
940980

941981
MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
942982

@@ -1030,6 +1070,42 @@ test_message (const struct message *message)
10301070
parser_free();
10311071
}
10321072

1073+
void
1074+
test_message_count_body (const struct message *message)
1075+
{
1076+
parser_init(message->type);
1077+
1078+
size_t read;
1079+
size_t l = strlen(message->raw);
1080+
size_t i, toread;
1081+
size_t chunk = 4024;
1082+
1083+
for (i = 0; i < l; i+= chunk) {
1084+
toread = MIN(l-i, chunk);
1085+
read = parse_count_body(message->raw + i, toread);
1086+
if (read != toread) {
1087+
print_error(message->raw, read);
1088+
exit(1);
1089+
}
1090+
}
1091+
1092+
1093+
read = parse_count_body(NULL, 0);
1094+
if (read != 0) {
1095+
print_error(message->raw, read);
1096+
exit(1);
1097+
}
1098+
1099+
if (num_messages != 1) {
1100+
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
1101+
exit(1);
1102+
}
1103+
1104+
if(!message_eq(0, message)) exit(1);
1105+
1106+
parser_free();
1107+
}
1108+
10331109
void
10341110
test_error (const char *buf)
10351111
{
@@ -1214,6 +1290,50 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
12141290
exit(1);
12151291
}
12161292

1293+
// user required to free the result
1294+
// string terminated by \0
1295+
char *
1296+
create_large_chunked_message (int body_size_in_kb, const char* headers)
1297+
{
1298+
int i;
1299+
size_t needed, wrote = 0;
1300+
size_t headers_len = strlen(headers);
1301+
size_t bufsize = headers_len + 10;
1302+
char * buf = malloc(bufsize);
1303+
1304+
strncpy(buf, headers, headers_len);
1305+
wrote += headers_len;
1306+
1307+
for (i = 0; i < body_size_in_kb; i++) {
1308+
// write 1kb chunk into the body.
1309+
needed = 5 + 1024 + 2; // "400\r\nCCCC...CCCC\r\n"
1310+
if (bufsize - wrote < needed) {
1311+
buf = realloc(buf, bufsize + needed);
1312+
bufsize += needed;
1313+
}
1314+
1315+
strcpy(buf + wrote, "400\r\n");
1316+
wrote += 5;
1317+
memset(buf + wrote, 'C', 1024);
1318+
wrote += 1024;
1319+
strcpy(buf + wrote, "\r\n");
1320+
wrote += 2;
1321+
}
1322+
1323+
needed = 5; // "0\r\n\r\n"
1324+
if (bufsize - wrote < needed) {
1325+
buf = realloc(buf, bufsize + needed);
1326+
bufsize += needed;
1327+
}
1328+
strcpy(buf + wrote, "0\r\n\r\n");
1329+
wrote += 5;
1330+
1331+
assert(buf[wrote] == 0);
1332+
1333+
return buf;
1334+
}
1335+
1336+
12171337
int
12181338
main (void)
12191339
{
@@ -1243,6 +1363,38 @@ main (void)
12431363
}
12441364
}
12451365

1366+
test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]);
1367+
test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]);
1368+
1369+
// test very large chunked response
1370+
{
1371+
char * msg = create_large_chunked_message(31337,
1372+
"HTTP/1.0 200 OK\r\n"
1373+
"Transfer-Encoding: chunked\r\n"
1374+
"Content-Type: text/plain\r\n"
1375+
"\r\n");
1376+
struct message large_chunked =
1377+
{.name= "large chunked"
1378+
,.type= HTTP_RESPONSE
1379+
,.raw= msg
1380+
,.should_keep_alive= FALSE
1381+
,.message_complete_on_eof= FALSE
1382+
,.http_major= 1
1383+
,.http_minor= 0
1384+
,.status_code= 200
1385+
,.num_headers= 2
1386+
,.headers=
1387+
{ { "Transfer-Encoding", "chunked" }
1388+
, { "Content-Type", "text/plain" }
1389+
}
1390+
,.body_size= 31337*1024
1391+
};
1392+
test_message_count_body(&large_chunked);
1393+
free(msg);
1394+
}
1395+
1396+
1397+
12461398
printf("response scan 1/1 ");
12471399
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
12481400
, &responses[NO_HEADERS_NO_BODY_404]

0 commit comments

Comments
 (0)