Skip to content

Commit b6a742d

Browse files
committed
Merge branch 'v0.4'
2 parents 8971b59 + 37d529f commit b6a742d

18 files changed

Lines changed: 406 additions & 99 deletions

deps/http_parser/.gitignore

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

deps/http_parser/LICENSE-MIT

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
1+
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
2+
Igor Sysoev.
3+
4+
Additional changes are licensed under the same terms as NGINX and
5+
copyright Joyent, Inc. and other Node contributors. All rights reserved.
26

37
Permission is hereby granted, free of charge, to any person obtaining a copy
48
of this software and associated documentation files (the "Software"), to

deps/http_parser/Makefile

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
OPT_DEBUG=-O0 -g -Wall -Wextra -Werror -I.
2-
OPT_FAST=-O3 -DHTTP_PARSER_STRICT=0 -I.
1+
CPPFLAGS?=-Wall -Wextra -Werror -I.
2+
OPT_DEBUG=$(CPPFLAGS) -O0 -g -DHTTP_PARSER_STRICT=1
3+
OPT_FAST=$(CPPFLAGS) -O3 -DHTTP_PARSER_STRICT=0
34

45
CC?=gcc
6+
AR?=ar
57

68

7-
test: test_g
9+
test: test_g test_fast
810
./test_g
11+
./test_fast
912

1013
test_g: http_parser_g.o test_g.o
1114
$(CC) $(OPT_DEBUG) http_parser_g.o test_g.o -o $@
@@ -31,11 +34,13 @@ test_fast: http_parser.o test.c http_parser.h
3134
test-run-timed: test_fast
3235
while(true) do time ./test_fast > /dev/null; done
3336

37+
package: http_parser.o
38+
$(AR) rcs libhttp_parser.a http_parser.o
3439

3540
tags: http_parser.c http_parser.h test.c
3641
ctags $^
3742

3843
clean:
39-
rm -f *.o test test_fast test_g http_parser.tar tags
44+
rm -f *.o *.a test test_fast test_g http_parser.tar tags
4045

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

deps/http_parser/http_parser.c

Lines changed: 69 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
/* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
1+
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2+
*
3+
* Additional changes are licensed under the same terms as NGINX and
4+
* copyright Joyent, Inc. and other Node contributors. All rights reserved.
25
*
36
* Permission is hereby granted, free of charge, to any person obtaining a copy
47
* of this software and associated documentation files (the "Software"), to
@@ -97,6 +100,7 @@ static const char *method_strings[] =
97100
, "NOTIFY"
98101
, "SUBSCRIBE"
99102
, "UNSUBSCRIBE"
103+
, "PATCH"
100104
};
101105

102106

@@ -186,7 +190,7 @@ static const uint8_t normal_url_char[256] = {
186190
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
187191
1, 1, 1, 1, 1, 1, 1, 1,
188192
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
189-
1, 1, 1, 1, 1, 1, 1, 0 };
193+
1, 1, 1, 1, 1, 1, 1, 0, };
190194

191195

192196
enum state
@@ -240,15 +244,17 @@ enum state
240244

241245
, s_header_almost_done
242246

247+
, s_chunk_size_start
248+
, s_chunk_size
249+
, s_chunk_parameters
250+
, s_chunk_size_almost_done
251+
243252
, s_headers_almost_done
244253
/* Important: 's_headers_almost_done' must be the last 'header' state. All
245254
* states beyond this must be 'body' states. It is used for overflow
246255
* checking. See the PARSING_HEADER() macro.
247256
*/
248-
, s_chunk_size_start
249-
, s_chunk_size
250-
, s_chunk_size_almost_done
251-
, s_chunk_parameters
257+
252258
, s_chunk_data
253259
, s_chunk_data_almost_done
254260
, s_chunk_data_done
@@ -258,7 +264,7 @@ enum state
258264
};
259265

260266

261-
#define PARSING_HEADER(state) (state <= s_headers_almost_done && 0 == (parser->flags & F_TRAILING))
267+
#define PARSING_HEADER(state) (state <= s_headers_almost_done)
262268

263269

264270
enum header_states
@@ -288,20 +294,24 @@ enum header_states
288294
};
289295

290296

291-
enum flags
292-
{ F_CHUNKED = 1 << 0
293-
, F_CONNECTION_KEEP_ALIVE = 1 << 1
294-
, F_CONNECTION_CLOSE = 1 << 2
295-
, F_TRAILING = 1 << 3
296-
, F_UPGRADE = 1 << 4
297-
, F_SKIPBODY = 1 << 5
298-
};
297+
/* Macros for character classes; depends on strict-mode */
298+
#define CR '\r'
299+
#define LF '\n'
300+
#define LOWER(c) (unsigned char)(c | 0x20)
301+
#define TOKEN(c) (tokens[(unsigned char)c])
302+
#define IS_ALPHA(c) ((c) >= 'a' && (c) <= 'z')
303+
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
304+
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
299305

300-
301-
#define CR '\r'
302-
#define LF '\n'
303-
#define LOWER(c) (unsigned char)(c | 0x20)
304-
#define TOKEN(c) tokens[(unsigned char)c]
306+
#if HTTP_PARSER_STRICT
307+
#define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
308+
#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
309+
#else
310+
#define IS_URL_CHAR(c) \
311+
(normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
312+
#define IS_HOST_CHAR(c) \
313+
(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
314+
#endif
305315

306316

307317
#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
@@ -478,7 +488,7 @@ size_t http_parser_execute (http_parser *parser,
478488
break;
479489
}
480490

481-
if (ch < '0' || ch > '9') goto error;
491+
if (!IS_NUM(ch)) goto error;
482492

483493
parser->http_major *= 10;
484494
parser->http_major += ch - '0';
@@ -489,7 +499,7 @@ size_t http_parser_execute (http_parser *parser,
489499

490500
/* first digit of minor HTTP version */
491501
case s_res_first_http_minor:
492-
if (ch < '0' || ch > '9') goto error;
502+
if (!IS_NUM(ch)) goto error;
493503
parser->http_minor = ch - '0';
494504
state = s_res_http_minor;
495505
break;
@@ -502,7 +512,7 @@ size_t http_parser_execute (http_parser *parser,
502512
break;
503513
}
504514

505-
if (ch < '0' || ch > '9') goto error;
515+
if (!IS_NUM(ch)) goto error;
506516

507517
parser->http_minor *= 10;
508518
parser->http_minor += ch - '0';
@@ -513,7 +523,7 @@ size_t http_parser_execute (http_parser *parser,
513523

514524
case s_res_first_status_code:
515525
{
516-
if (ch < '0' || ch > '9') {
526+
if (!IS_NUM(ch)) {
517527
if (ch == ' ') {
518528
break;
519529
}
@@ -526,7 +536,7 @@ size_t http_parser_execute (http_parser *parser,
526536

527537
case s_res_status_code:
528538
{
529-
if (ch < '0' || ch > '9') {
539+
if (!IS_NUM(ch)) {
530540
switch (ch) {
531541
case ' ':
532542
state = s_res_status;
@@ -578,7 +588,7 @@ size_t http_parser_execute (http_parser *parser,
578588

579589
CALLBACK2(message_begin);
580590

581-
if (ch < 'A' || 'Z' < ch) goto error;
591+
if (!IS_ALPHA(LOWER(ch))) goto error;
582592

583593
start_req_method_assign:
584594
parser->method = (enum http_method) 0;
@@ -592,7 +602,9 @@ size_t http_parser_execute (http_parser *parser,
592602
case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
593603
case 'N': parser->method = HTTP_NOTIFY; break;
594604
case 'O': parser->method = HTTP_OPTIONS; break;
595-
case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
605+
case 'P': parser->method = HTTP_POST;
606+
/* or PROPFIND or PROPPATCH or PUT or PATCH */
607+
break;
596608
case 'R': parser->method = HTTP_REPORT; break;
597609
case 'S': parser->method = HTTP_SUBSCRIBE; break;
598610
case 'T': parser->method = HTTP_TRACE; break;
@@ -633,6 +645,8 @@ size_t http_parser_execute (http_parser *parser,
633645
parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
634646
} else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
635647
parser->method = HTTP_PUT;
648+
} else if (index == 1 && parser->method == HTTP_POST && ch == 'A') {
649+
parser->method = HTTP_PATCH;
636650
} else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
637651
parser->method = HTTP_UNSUBSCRIBE;
638652
} else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
@@ -657,9 +671,13 @@ size_t http_parser_execute (http_parser *parser,
657671

658672
c = LOWER(ch);
659673

660-
if (c >= 'a' && c <= 'z') {
674+
/* Proxied requests are followed by scheme of an absolute URI (alpha).
675+
* CONNECT is followed by a hostname, which begins with alphanum.
676+
* All other methods are followed by '/' or '*' (handled above).
677+
*/
678+
if (IS_ALPHA(ch) || (parser->method == HTTP_CONNECT && IS_NUM(ch))) {
661679
MARK(url);
662-
state = s_req_schema;
680+
state = (parser->method == HTTP_CONNECT) ? s_req_host : s_req_schema;
663681
break;
664682
}
665683

@@ -670,17 +688,11 @@ size_t http_parser_execute (http_parser *parser,
670688
{
671689
c = LOWER(ch);
672690

673-
if (c >= 'a' && c <= 'z') break;
691+
if (IS_ALPHA(c)) break;
674692

675693
if (ch == ':') {
676694
state = s_req_schema_slash;
677695
break;
678-
} else if (ch == '.') {
679-
state = s_req_host;
680-
break;
681-
} else if ('0' <= ch && ch <= '9') {
682-
state = s_req_host;
683-
break;
684696
}
685697

686698
goto error;
@@ -699,8 +711,7 @@ size_t http_parser_execute (http_parser *parser,
699711
case s_req_host:
700712
{
701713
c = LOWER(ch);
702-
if (c >= 'a' && c <= 'z') break;
703-
if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
714+
if (IS_HOST_CHAR(ch)) break;
704715
switch (ch) {
705716
case ':':
706717
state = s_req_port;
@@ -717,6 +728,9 @@ size_t http_parser_execute (http_parser *parser,
717728
CALLBACK(url);
718729
state = s_req_http_start;
719730
break;
731+
case '?':
732+
state = s_req_query_string_start;
733+
break;
720734
default:
721735
goto error;
722736
}
@@ -725,7 +739,7 @@ size_t http_parser_execute (http_parser *parser,
725739

726740
case s_req_port:
727741
{
728-
if (ch >= '0' && ch <= '9') break;
742+
if (IS_NUM(ch)) break;
729743
switch (ch) {
730744
case '/':
731745
MARK(path);
@@ -739,6 +753,9 @@ size_t http_parser_execute (http_parser *parser,
739753
CALLBACK(url);
740754
state = s_req_http_start;
741755
break;
756+
case '?':
757+
state = s_req_query_string_start;
758+
break;
742759
default:
743760
goto error;
744761
}
@@ -747,7 +764,7 @@ size_t http_parser_execute (http_parser *parser,
747764

748765
case s_req_path:
749766
{
750-
if (normal_url_char[(unsigned char)ch]) break;
767+
if (IS_URL_CHAR(ch)) break;
751768

752769
switch (ch) {
753770
case ' ':
@@ -785,7 +802,7 @@ size_t http_parser_execute (http_parser *parser,
785802

786803
case s_req_query_string_start:
787804
{
788-
if (normal_url_char[(unsigned char)ch]) {
805+
if (IS_URL_CHAR(ch)) {
789806
MARK(query_string);
790807
state = s_req_query_string;
791808
break;
@@ -821,7 +838,7 @@ size_t http_parser_execute (http_parser *parser,
821838

822839
case s_req_query_string:
823840
{
824-
if (normal_url_char[(unsigned char)ch]) break;
841+
if (IS_URL_CHAR(ch)) break;
825842

826843
switch (ch) {
827844
case '?':
@@ -858,7 +875,7 @@ size_t http_parser_execute (http_parser *parser,
858875

859876
case s_req_fragment_start:
860877
{
861-
if (normal_url_char[(unsigned char)ch]) {
878+
if (IS_URL_CHAR(ch)) {
862879
MARK(fragment);
863880
state = s_req_fragment;
864881
break;
@@ -895,7 +912,7 @@ size_t http_parser_execute (http_parser *parser,
895912

896913
case s_req_fragment:
897914
{
898-
if (normal_url_char[(unsigned char)ch]) break;
915+
if (IS_URL_CHAR(ch)) break;
899916

900917
switch (ch) {
901918
case ' ':
@@ -973,7 +990,7 @@ size_t http_parser_execute (http_parser *parser,
973990
break;
974991
}
975992

976-
if (ch < '0' || ch > '9') goto error;
993+
if (!IS_NUM(ch)) goto error;
977994

978995
parser->http_major *= 10;
979996
parser->http_major += ch - '0';
@@ -984,7 +1001,7 @@ size_t http_parser_execute (http_parser *parser,
9841001

9851002
/* first digit of minor HTTP version */
9861003
case s_req_first_http_minor:
987-
if (ch < '0' || ch > '9') goto error;
1004+
if (!IS_NUM(ch)) goto error;
9881005
parser->http_minor = ch - '0';
9891006
state = s_req_http_minor;
9901007
break;
@@ -1004,7 +1021,7 @@ size_t http_parser_execute (http_parser *parser,
10041021

10051022
/* XXX allow spaces after digit? */
10061023

1007-
if (ch < '0' || ch > '9') goto error;
1024+
if (!IS_NUM(ch)) goto error;
10081025

10091026
parser->http_minor *= 10;
10101027
parser->http_minor += ch - '0';
@@ -1237,7 +1254,7 @@ size_t http_parser_execute (http_parser *parser,
12371254
break;
12381255

12391256
case h_content_length:
1240-
if (ch < '0' || ch > '9') goto error;
1257+
if (!IS_NUM(ch)) goto error;
12411258
parser->content_length = ch - '0';
12421259
break;
12431260

@@ -1286,7 +1303,7 @@ size_t http_parser_execute (http_parser *parser,
12861303

12871304
case h_content_length:
12881305
if (ch == ' ') break;
1289-
if (ch < '0' || ch > '9') goto error;
1306+
if (!IS_NUM(ch)) goto error;
12901307
parser->content_length *= 10;
12911308
parser->content_length += ch - '0';
12921309
break;
@@ -1458,6 +1475,7 @@ size_t http_parser_execute (http_parser *parser,
14581475

14591476
case s_chunk_size_start:
14601477
{
1478+
assert(nread == 1);
14611479
assert(parser->flags & F_CHUNKED);
14621480

14631481
c = unhex[(unsigned char)ch];
@@ -1507,6 +1525,8 @@ size_t http_parser_execute (http_parser *parser,
15071525
assert(parser->flags & F_CHUNKED);
15081526
STRICT_CHECK(ch != LF);
15091527

1528+
nread = 0;
1529+
15101530
if (parser->content_length == 0) {
15111531
parser->flags |= F_TRAILING;
15121532
state = s_header_field_start;

0 commit comments

Comments
 (0)