http_parser.rb 0.5.3 → 0.6.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitmodules +3 -3
- data/Gemfile +1 -1
- data/Gemfile.lock +9 -2
- data/README.md +50 -45
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +1 -0
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +66 -58
- data/ext/ruby_http_parser/ruby_http_parser.c +10 -41
- data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1029 -615
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +177 -43
- data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPHeadersCompleteCallback.java +13 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +4 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +2 -2
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPHeadersCompleteCallback.java +12 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +715 -637
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +71 -21
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1141 -210
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1029 -615
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +145 -16
- data/ext/ruby_http_parser/vendor/http-parser/test.c +1065 -141
- data/http_parser.rb.gemspec +3 -1
- data/spec/parser_spec.rb +41 -17
- data/spec/support/requests.json +236 -24
- data/spec/support/responses.json +182 -36
- data/tasks/compile.rake +2 -2
- data/tasks/fixtures.rake +7 -1
- metadata +57 -19
- data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
@@ -41,6 +41,11 @@ public class Util {
|
|
41
41
|
throw new RuntimeException("!");
|
42
42
|
}
|
43
43
|
}
|
44
|
+
static void check (int should, int is) {
|
45
|
+
if (should != is) {
|
46
|
+
throw new RuntimeException("should be: "+should+" is:"+is);
|
47
|
+
}
|
48
|
+
}
|
44
49
|
|
45
50
|
static void test_message(Message mes) {
|
46
51
|
int raw_len = mes.raw.length;
|
@@ -51,11 +56,11 @@ public class Util {
|
|
51
56
|
|
52
57
|
HTTPParser parser = new HTTPParser(mes.type);
|
53
58
|
ParserSettings settings = mes.settings();
|
54
|
-
|
59
|
+
|
55
60
|
int read = 0;
|
56
61
|
if (msg1len !=0) {
|
57
62
|
read = parser.execute(settings, msg1);
|
58
|
-
if (mes.upgrade && parser.upgrade) {
|
63
|
+
if (mes.upgrade() && parser.upgrade) {
|
59
64
|
// Messages have a settings() that checks itself...
|
60
65
|
check(1 == mes.num_called);
|
61
66
|
continue;
|
@@ -64,17 +69,17 @@ public class Util {
|
|
64
69
|
}
|
65
70
|
|
66
71
|
read = parser.execute(settings, msg2);
|
67
|
-
if (mes.upgrade && parser.upgrade) {
|
72
|
+
if (mes.upgrade() && parser.upgrade) {
|
68
73
|
check(1 == mes.num_called);
|
69
74
|
continue;
|
70
75
|
}
|
71
76
|
|
72
|
-
check(
|
77
|
+
check( mes.raw.length - msg1len, read);
|
73
78
|
|
74
79
|
ByteBuffer empty = Util.empty();
|
75
80
|
read = parser.execute(settings, empty);
|
76
81
|
|
77
|
-
if (mes.upgrade && parser.upgrade) {
|
82
|
+
if (mes.upgrade() && parser.upgrade) {
|
78
83
|
check(1 == mes.num_called);
|
79
84
|
continue;
|
80
85
|
}
|
@@ -87,13 +92,13 @@ public class Util {
|
|
87
92
|
|
88
93
|
static void test_multiple3(Message r1, Message r2, Message r3) {
|
89
94
|
int message_count = 1;
|
90
|
-
if (!r1.upgrade) {
|
95
|
+
if (!r1.upgrade()) {
|
91
96
|
message_count++;
|
92
|
-
if (!r2.upgrade) {
|
97
|
+
if (!r2.upgrade()) {
|
93
98
|
message_count++;
|
94
99
|
}
|
95
100
|
}
|
96
|
-
boolean has_upgrade = (message_count < 3 || r3.upgrade);
|
101
|
+
boolean has_upgrade = (message_count < 3 || r3.upgrade());
|
97
102
|
|
98
103
|
ByteList blist = new ByteList();
|
99
104
|
blist.addAll(r1.raw);
|
@@ -108,6 +113,7 @@ public class Util {
|
|
108
113
|
|
109
114
|
int read = parser.execute(settings, buf);
|
110
115
|
if (has_upgrade && parser.upgrade) {
|
116
|
+
raw = upgrade_message_fix(raw, read, r1,r2,r3);
|
111
117
|
check(settings.numCalled == message_count);
|
112
118
|
return;
|
113
119
|
}
|
@@ -122,8 +128,73 @@ public class Util {
|
|
122
128
|
}
|
123
129
|
|
124
130
|
check(0 == read);
|
125
|
-
check(settings.numCalled == message_count);
|
131
|
+
check(settings.numCalled == message_count);
|
126
132
|
}
|
133
|
+
|
134
|
+
/* Given a sequence of bytes and the number of these that we were able to
|
135
|
+
* parse, verify that upgrade bodies are correct.
|
136
|
+
*/
|
137
|
+
static byte [] upgrade_message_fix(byte[] body, int nread, Message... msgs) {
|
138
|
+
int off = 0;
|
139
|
+
for (Message m : msgs) {
|
140
|
+
off += m.raw.length;
|
141
|
+
if (m.upgrade()) {
|
142
|
+
off -= m.upgrade.length;
|
143
|
+
// Original C:
|
144
|
+
// Check the portion of the response after its specified upgrade
|
145
|
+
// if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
|
146
|
+
// abort();
|
147
|
+
// }
|
148
|
+
// to me, this seems to be equivalent to comparing off and nread ...
|
149
|
+
check (off, nread);
|
150
|
+
|
151
|
+
// Original C:
|
152
|
+
// Fix up the response so that message_eq() will verify the beginning
|
153
|
+
// of the upgrade */
|
154
|
+
//
|
155
|
+
// *(body + nread + strlen(m->upgrade)) = '\0';
|
156
|
+
// This only shortens body so the strlen check passes.
|
157
|
+
return new byte[off];
|
158
|
+
|
159
|
+
}
|
160
|
+
}
|
161
|
+
return null;
|
162
|
+
}
|
163
|
+
//upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
|
164
|
+
// va_list ap;
|
165
|
+
// size_t i;
|
166
|
+
// size_t off = 0;
|
167
|
+
//
|
168
|
+
// va_start(ap, nmsgs);
|
169
|
+
//
|
170
|
+
// for (i = 0; i < nmsgs; i++) {
|
171
|
+
// struct message *m = va_arg(ap, struct message *);
|
172
|
+
//
|
173
|
+
// off += strlen(m->raw);
|
174
|
+
//
|
175
|
+
// if (m->upgrade) {
|
176
|
+
// off -= strlen(m->upgrade);
|
177
|
+
//
|
178
|
+
// /* Check the portion of the response after its specified upgrade */
|
179
|
+
// if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
|
180
|
+
// abort();
|
181
|
+
// }
|
182
|
+
//
|
183
|
+
// /* Fix up the response so that message_eq() will verify the beginning
|
184
|
+
// * of the upgrade */
|
185
|
+
// *(body + nread + strlen(m->upgrade)) = '\0';
|
186
|
+
// messages[num_messages -1 ].upgrade = body + nread;
|
187
|
+
//
|
188
|
+
// va_end(ap);
|
189
|
+
// return;
|
190
|
+
// }
|
191
|
+
// }
|
192
|
+
//
|
193
|
+
// va_end(ap);
|
194
|
+
// printf("\n\n*** Error: expected a message with upgrade ***\n");
|
195
|
+
//
|
196
|
+
// abort();
|
197
|
+
//}
|
127
198
|
static void p (Object o) {
|
128
199
|
System.out.println(o);
|
129
200
|
}
|
@@ -14,6 +14,7 @@ public class WrongContentLength {
|
|
14
14
|
"hello" +
|
15
15
|
"hello_again";
|
16
16
|
static void test () {
|
17
|
+
p(WrongContentLength.class);
|
17
18
|
HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST);
|
18
19
|
ByteBuffer buf = buffer(contentLength);
|
19
20
|
|
@@ -43,7 +44,7 @@ public class WrongContentLength {
|
|
43
44
|
this.on_body = new HTTPDataCallback() {
|
44
45
|
public int cb (HTTPParser p, ByteBuffer b, int pos, int len) {
|
45
46
|
bodyCount += len;
|
46
|
-
|
47
|
+
check ("hello".equals(str(b, pos, len)));
|
47
48
|
return 0;
|
48
49
|
}
|
49
50
|
};
|
@@ -50,12 +50,13 @@ struct message {
|
|
50
50
|
char query_string[MAX_ELEMENT_SIZE];
|
51
51
|
char body[MAX_ELEMENT_SIZE];
|
52
52
|
size_t body_size;
|
53
|
+
uint16_t port;
|
53
54
|
int num_headers;
|
54
55
|
enum { NONE=0, FIELD, VALUE } last_header_element;
|
55
56
|
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
|
56
57
|
int should_keep_alive;
|
57
58
|
|
58
|
-
|
59
|
+
const char *upgrade; // upgraded body
|
59
60
|
|
60
61
|
unsigned short http_major;
|
61
62
|
unsigned short http_minor;
|
@@ -70,6 +71,7 @@ static int currently_parsing_eof;
|
|
70
71
|
|
71
72
|
static struct message messages[5];
|
72
73
|
static int num_messages;
|
74
|
+
static http_parser_settings *current_pause_parser;
|
73
75
|
|
74
76
|
/* * R E Q U E S T S * */
|
75
77
|
const struct message requests[] =
|
@@ -473,6 +475,7 @@ const struct message requests[] =
|
|
473
475
|
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
|
474
476
|
"Origin: http://example.com\r\n"
|
475
477
|
"\r\n"
|
478
|
+
"Hot diggity dogg"
|
476
479
|
,.should_keep_alive= TRUE
|
477
480
|
,.message_complete_on_eof= FALSE
|
478
481
|
,.http_major= 1
|
@@ -483,7 +486,7 @@ const struct message requests[] =
|
|
483
486
|
,.request_path= "/demo"
|
484
487
|
,.request_url= "/demo"
|
485
488
|
,.num_headers= 7
|
486
|
-
,.upgrade=
|
489
|
+
,.upgrade="Hot diggity dogg"
|
487
490
|
,.headers= { { "Host", "example.com" }
|
488
491
|
, { "Connection", "Upgrade" }
|
489
492
|
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
|
@@ -498,10 +501,12 @@ const struct message requests[] =
|
|
498
501
|
#define CONNECT_REQUEST 17
|
499
502
|
, {.name = "connect request"
|
500
503
|
,.type= HTTP_REQUEST
|
501
|
-
,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n"
|
504
|
+
,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
|
502
505
|
"User-agent: Mozilla/1.1N\r\n"
|
503
506
|
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
504
507
|
"\r\n"
|
508
|
+
"some data\r\n"
|
509
|
+
"and yet even more data"
|
505
510
|
,.should_keep_alive= FALSE
|
506
511
|
,.message_complete_on_eof= FALSE
|
507
512
|
,.http_major= 1
|
@@ -510,9 +515,9 @@ const struct message requests[] =
|
|
510
515
|
,.query_string= ""
|
511
516
|
,.fragment= ""
|
512
517
|
,.request_path= ""
|
513
|
-
,.request_url= "home0.netscape.com:443"
|
518
|
+
,.request_url= "0-home0.netscape.com:443"
|
514
519
|
,.num_headers= 2
|
515
|
-
,.upgrade=
|
520
|
+
,.upgrade="some data\r\nand yet even more data"
|
516
521
|
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
517
522
|
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
518
523
|
}
|
@@ -582,28 +587,36 @@ const struct message requests[] =
|
|
582
587
|
,.body= ""
|
583
588
|
}
|
584
589
|
|
585
|
-
#define
|
586
|
-
, {.name= "
|
590
|
+
#define LINE_FOLDING_IN_HEADER 20
|
591
|
+
, {.name= "line folding in header value"
|
587
592
|
,.type= HTTP_REQUEST
|
588
|
-
,.raw= "GET
|
589
|
-
"
|
593
|
+
,.raw= "GET / HTTP/1.1\r\n"
|
594
|
+
"Line1: abc\r\n"
|
595
|
+
"\tdef\r\n"
|
596
|
+
" ghi\r\n"
|
597
|
+
"\t\tjkl\r\n"
|
598
|
+
" mno \r\n"
|
599
|
+
"\t \tqrs\r\n"
|
600
|
+
"Line2: \t line2\t\r\n"
|
590
601
|
"\r\n"
|
591
602
|
,.should_keep_alive= TRUE
|
592
603
|
,.message_complete_on_eof= FALSE
|
593
604
|
,.http_major= 1
|
594
605
|
,.http_minor= 1
|
595
606
|
,.method= HTTP_GET
|
596
|
-
,.query_string= "
|
597
|
-
,.fragment= "
|
598
|
-
,.request_path= "
|
599
|
-
,.request_url= "
|
600
|
-
,.num_headers=
|
601
|
-
,.headers= { {"
|
607
|
+
,.query_string= ""
|
608
|
+
,.fragment= ""
|
609
|
+
,.request_path= "/"
|
610
|
+
,.request_url= "/"
|
611
|
+
,.num_headers= 2
|
612
|
+
,.headers= { { "Line1", "abcdefghijklmno qrs" }
|
613
|
+
, { "Line2", "line2\t" }
|
602
614
|
}
|
603
615
|
,.body= ""
|
604
616
|
}
|
605
617
|
|
606
|
-
|
618
|
+
|
619
|
+
#define QUERY_TERMINATED_HOST 21
|
607
620
|
, {.name= "host terminated by a query string"
|
608
621
|
,.type= HTTP_REQUEST
|
609
622
|
,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
|
@@ -622,7 +635,7 @@ const struct message requests[] =
|
|
622
635
|
,.body= ""
|
623
636
|
}
|
624
637
|
|
625
|
-
#define QUERY_TERMINATED_HOSTPORT
|
638
|
+
#define QUERY_TERMINATED_HOSTPORT 22
|
626
639
|
, {.name= "host:port terminated by a query string"
|
627
640
|
,.type= HTTP_REQUEST
|
628
641
|
,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
|
@@ -636,12 +649,13 @@ const struct message requests[] =
|
|
636
649
|
,.fragment= ""
|
637
650
|
,.request_path= ""
|
638
651
|
,.request_url= "http://hypnotoad.org:1234?hail=all"
|
652
|
+
,.port= 1234
|
639
653
|
,.num_headers= 0
|
640
654
|
,.headers= { }
|
641
655
|
,.body= ""
|
642
656
|
}
|
643
657
|
|
644
|
-
#define SPACE_TERMINATED_HOSTPORT
|
658
|
+
#define SPACE_TERMINATED_HOSTPORT 23
|
645
659
|
, {.name= "host:port terminated by a space"
|
646
660
|
,.type= HTTP_REQUEST
|
647
661
|
,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
|
@@ -655,11 +669,187 @@ const struct message requests[] =
|
|
655
669
|
,.fragment= ""
|
656
670
|
,.request_path= ""
|
657
671
|
,.request_url= "http://hypnotoad.org:1234"
|
672
|
+
,.port= 1234
|
658
673
|
,.num_headers= 0
|
659
674
|
,.headers= { }
|
660
675
|
,.body= ""
|
661
676
|
}
|
662
677
|
|
678
|
+
#define PATCH_REQ 24
|
679
|
+
, {.name = "PATCH request"
|
680
|
+
,.type= HTTP_REQUEST
|
681
|
+
,.raw= "PATCH /file.txt HTTP/1.1\r\n"
|
682
|
+
"Host: www.example.com\r\n"
|
683
|
+
"Content-Type: application/example\r\n"
|
684
|
+
"If-Match: \"e0023aa4e\"\r\n"
|
685
|
+
"Content-Length: 10\r\n"
|
686
|
+
"\r\n"
|
687
|
+
"cccccccccc"
|
688
|
+
,.should_keep_alive= TRUE
|
689
|
+
,.message_complete_on_eof= FALSE
|
690
|
+
,.http_major= 1
|
691
|
+
,.http_minor= 1
|
692
|
+
,.method= HTTP_PATCH
|
693
|
+
,.query_string= ""
|
694
|
+
,.fragment= ""
|
695
|
+
,.request_path= "/file.txt"
|
696
|
+
,.request_url= "/file.txt"
|
697
|
+
,.num_headers= 4
|
698
|
+
,.headers= { { "Host", "www.example.com" }
|
699
|
+
, { "Content-Type", "application/example" }
|
700
|
+
, { "If-Match", "\"e0023aa4e\"" }
|
701
|
+
, { "Content-Length", "10" }
|
702
|
+
}
|
703
|
+
,.body= "cccccccccc"
|
704
|
+
}
|
705
|
+
|
706
|
+
#define CONNECT_CAPS_REQUEST 25
|
707
|
+
, {.name = "connect caps request"
|
708
|
+
,.type= HTTP_REQUEST
|
709
|
+
,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
|
710
|
+
"User-agent: Mozilla/1.1N\r\n"
|
711
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
712
|
+
"\r\n"
|
713
|
+
,.should_keep_alive= FALSE
|
714
|
+
,.message_complete_on_eof= FALSE
|
715
|
+
,.http_major= 1
|
716
|
+
,.http_minor= 0
|
717
|
+
,.method= HTTP_CONNECT
|
718
|
+
,.query_string= ""
|
719
|
+
,.fragment= ""
|
720
|
+
,.request_path= ""
|
721
|
+
,.request_url= "HOME0.NETSCAPE.COM:443"
|
722
|
+
,.num_headers= 2
|
723
|
+
,.upgrade=""
|
724
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
725
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
726
|
+
}
|
727
|
+
,.body= ""
|
728
|
+
}
|
729
|
+
|
730
|
+
#if !HTTP_PARSER_STRICT
|
731
|
+
#define UTF8_PATH_REQ 26
|
732
|
+
, {.name= "utf-8 path request"
|
733
|
+
,.type= HTTP_REQUEST
|
734
|
+
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
|
735
|
+
"Host: github.com\r\n"
|
736
|
+
"\r\n"
|
737
|
+
,.should_keep_alive= TRUE
|
738
|
+
,.message_complete_on_eof= FALSE
|
739
|
+
,.http_major= 1
|
740
|
+
,.http_minor= 1
|
741
|
+
,.method= HTTP_GET
|
742
|
+
,.query_string= "q=1"
|
743
|
+
,.fragment= "narf"
|
744
|
+
,.request_path= "/δ¶/δt/pope"
|
745
|
+
,.request_url= "/δ¶/δt/pope?q=1#narf"
|
746
|
+
,.num_headers= 1
|
747
|
+
,.headers= { {"Host", "github.com" }
|
748
|
+
}
|
749
|
+
,.body= ""
|
750
|
+
}
|
751
|
+
|
752
|
+
#define HOSTNAME_UNDERSCORE 27
|
753
|
+
, {.name = "hostname underscore"
|
754
|
+
,.type= HTTP_REQUEST
|
755
|
+
,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
|
756
|
+
"User-agent: Mozilla/1.1N\r\n"
|
757
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
758
|
+
"\r\n"
|
759
|
+
,.should_keep_alive= FALSE
|
760
|
+
,.message_complete_on_eof= FALSE
|
761
|
+
,.http_major= 1
|
762
|
+
,.http_minor= 0
|
763
|
+
,.method= HTTP_CONNECT
|
764
|
+
,.query_string= ""
|
765
|
+
,.fragment= ""
|
766
|
+
,.request_path= ""
|
767
|
+
,.request_url= "home_0.netscape.com:443"
|
768
|
+
,.num_headers= 2
|
769
|
+
,.upgrade=""
|
770
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
771
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
772
|
+
}
|
773
|
+
,.body= ""
|
774
|
+
}
|
775
|
+
#endif /* !HTTP_PARSER_STRICT */
|
776
|
+
|
777
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
778
|
+
#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 28
|
779
|
+
, {.name = "eat CRLF between requests, no \"Connection: close\" header"
|
780
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
781
|
+
"Host: www.example.com\r\n"
|
782
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
783
|
+
"Content-Length: 4\r\n"
|
784
|
+
"\r\n"
|
785
|
+
"q=42\r\n" /* note the trailing CRLF */
|
786
|
+
,.should_keep_alive= TRUE
|
787
|
+
,.message_complete_on_eof= FALSE
|
788
|
+
,.http_major= 1
|
789
|
+
,.http_minor= 1
|
790
|
+
,.method= HTTP_POST
|
791
|
+
,.query_string= ""
|
792
|
+
,.fragment= ""
|
793
|
+
,.request_path= "/"
|
794
|
+
,.request_url= "/"
|
795
|
+
,.num_headers= 3
|
796
|
+
,.upgrade= 0
|
797
|
+
,.headers= { { "Host", "www.example.com" }
|
798
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
799
|
+
, { "Content-Length", "4" }
|
800
|
+
}
|
801
|
+
,.body= "q=42"
|
802
|
+
}
|
803
|
+
|
804
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
805
|
+
#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 29
|
806
|
+
, {.name = "eat CRLF between requests even if \"Connection: close\" is set"
|
807
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
808
|
+
"Host: www.example.com\r\n"
|
809
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
810
|
+
"Content-Length: 4\r\n"
|
811
|
+
"Connection: close\r\n"
|
812
|
+
"\r\n"
|
813
|
+
"q=42\r\n" /* note the trailing CRLF */
|
814
|
+
,.should_keep_alive= FALSE
|
815
|
+
,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
|
816
|
+
,.http_major= 1
|
817
|
+
,.http_minor= 1
|
818
|
+
,.method= HTTP_POST
|
819
|
+
,.query_string= ""
|
820
|
+
,.fragment= ""
|
821
|
+
,.request_path= "/"
|
822
|
+
,.request_url= "/"
|
823
|
+
,.num_headers= 4
|
824
|
+
,.upgrade= 0
|
825
|
+
,.headers= { { "Host", "www.example.com" }
|
826
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
827
|
+
, { "Content-Length", "4" }
|
828
|
+
, { "Connection", "close" }
|
829
|
+
}
|
830
|
+
,.body= "q=42"
|
831
|
+
}
|
832
|
+
|
833
|
+
#define PURGE_REQ 30
|
834
|
+
, {.name = "PURGE request"
|
835
|
+
,.type= HTTP_REQUEST
|
836
|
+
,.raw= "PURGE /file.txt HTTP/1.1\r\n"
|
837
|
+
"Host: www.example.com\r\n"
|
838
|
+
"\r\n"
|
839
|
+
,.should_keep_alive= TRUE
|
840
|
+
,.message_complete_on_eof= FALSE
|
841
|
+
,.http_major= 1
|
842
|
+
,.http_minor= 1
|
843
|
+
,.method= HTTP_PURGE
|
844
|
+
,.query_string= ""
|
845
|
+
,.fragment= ""
|
846
|
+
,.request_path= "/file.txt"
|
847
|
+
,.request_url= "/file.txt"
|
848
|
+
,.num_headers= 1
|
849
|
+
,.headers= { { "Host", "www.example.com" } }
|
850
|
+
,.body= ""
|
851
|
+
}
|
852
|
+
|
663
853
|
, {.name= NULL } /* sentinel */
|
664
854
|
};
|
665
855
|
|
@@ -760,8 +950,8 @@ const struct message responses[] =
|
|
760
950
|
, {.name= "404 no headers no body"
|
761
951
|
,.type= HTTP_RESPONSE
|
762
952
|
,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
|
763
|
-
,.should_keep_alive=
|
764
|
-
,.message_complete_on_eof=
|
953
|
+
,.should_keep_alive= FALSE
|
954
|
+
,.message_complete_on_eof= TRUE
|
765
955
|
,.http_major= 1
|
766
956
|
,.http_minor= 1
|
767
957
|
,.status_code= 404
|
@@ -775,8 +965,8 @@ const struct message responses[] =
|
|
775
965
|
, {.name= "301 no response phrase"
|
776
966
|
,.type= HTTP_RESPONSE
|
777
967
|
,.raw= "HTTP/1.1 301\r\n\r\n"
|
778
|
-
,.should_keep_alive =
|
779
|
-
,.message_complete_on_eof=
|
968
|
+
,.should_keep_alive = FALSE
|
969
|
+
,.message_complete_on_eof= TRUE
|
780
970
|
,.http_major= 1
|
781
971
|
,.http_minor= 1
|
782
972
|
,.status_code= 301
|
@@ -925,40 +1115,7 @@ const struct message responses[] =
|
|
925
1115
|
,.body= ""
|
926
1116
|
}
|
927
1117
|
|
928
|
-
#define
|
929
|
-
/* Should handle spaces in header fields */
|
930
|
-
, {.name= "field space"
|
931
|
-
,.type= HTTP_RESPONSE
|
932
|
-
,.raw= "HTTP/1.1 200 OK\r\n"
|
933
|
-
"Server: Microsoft-IIS/6.0\r\n"
|
934
|
-
"X-Powered-By: ASP.NET\r\n"
|
935
|
-
"en-US Content-Type: text/xml\r\n" /* this is the problem */
|
936
|
-
"Content-Type: text/xml\r\n"
|
937
|
-
"Content-Length: 16\r\n"
|
938
|
-
"Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
|
939
|
-
"Connection: keep-alive\r\n"
|
940
|
-
"\r\n"
|
941
|
-
"<xml>hello</xml>" /* fake body */
|
942
|
-
,.should_keep_alive= TRUE
|
943
|
-
,.message_complete_on_eof= FALSE
|
944
|
-
,.http_major= 1
|
945
|
-
,.http_minor= 1
|
946
|
-
,.status_code= 200
|
947
|
-
,.num_headers= 7
|
948
|
-
,.headers=
|
949
|
-
{ { "Server", "Microsoft-IIS/6.0" }
|
950
|
-
, { "X-Powered-By", "ASP.NET" }
|
951
|
-
, { "en-US Content-Type", "text/xml" }
|
952
|
-
, { "Content-Type", "text/xml" }
|
953
|
-
, { "Content-Length", "16" }
|
954
|
-
, { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
|
955
|
-
, { "Connection", "keep-alive" }
|
956
|
-
}
|
957
|
-
,.body= "<xml>hello</xml>"
|
958
|
-
}
|
959
|
-
|
960
|
-
|
961
|
-
#define RES_FIELD_UNDERSCORE 10
|
1118
|
+
#define RES_FIELD_UNDERSCORE 9
|
962
1119
|
/* Should handle spaces in header fields */
|
963
1120
|
, {.name= "field underscore"
|
964
1121
|
,.type= HTTP_RESPONSE
|
@@ -998,7 +1155,7 @@ const struct message responses[] =
|
|
998
1155
|
,.body= ""
|
999
1156
|
}
|
1000
1157
|
|
1001
|
-
#define NON_ASCII_IN_STATUS_LINE
|
1158
|
+
#define NON_ASCII_IN_STATUS_LINE 10
|
1002
1159
|
/* Should handle non-ASCII in status line */
|
1003
1160
|
, {.name= "non-ASCII in status line"
|
1004
1161
|
,.type= HTTP_RESPONSE
|
@@ -1018,21 +1175,196 @@ const struct message responses[] =
|
|
1018
1175
|
, { "Content-Length", "0" }
|
1019
1176
|
, { "Connection", "close" }
|
1020
1177
|
}
|
1021
|
-
,.body= ""
|
1178
|
+
,.body= ""
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
#define HTTP_VERSION_0_9 11
|
1182
|
+
/* Should handle HTTP/0.9 */
|
1183
|
+
, {.name= "http version 0.9"
|
1184
|
+
,.type= HTTP_RESPONSE
|
1185
|
+
,.raw= "HTTP/0.9 200 OK\r\n"
|
1186
|
+
"\r\n"
|
1187
|
+
,.should_keep_alive= FALSE
|
1188
|
+
,.message_complete_on_eof= TRUE
|
1189
|
+
,.http_major= 0
|
1190
|
+
,.http_minor= 9
|
1191
|
+
,.status_code= 200
|
1192
|
+
,.num_headers= 0
|
1193
|
+
,.headers=
|
1194
|
+
{}
|
1195
|
+
,.body= ""
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
|
1199
|
+
/* The client should wait for the server's EOF. That is, when neither
|
1200
|
+
* content-length nor transfer-encoding is specified, the end of body
|
1201
|
+
* is specified by the EOF.
|
1202
|
+
*/
|
1203
|
+
, {.name= "neither content-length nor transfer-encoding response"
|
1204
|
+
,.type= HTTP_RESPONSE
|
1205
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1206
|
+
"Content-Type: text/plain\r\n"
|
1207
|
+
"\r\n"
|
1208
|
+
"hello world"
|
1209
|
+
,.should_keep_alive= FALSE
|
1210
|
+
,.message_complete_on_eof= TRUE
|
1211
|
+
,.http_major= 1
|
1212
|
+
,.http_minor= 1
|
1213
|
+
,.status_code= 200
|
1214
|
+
,.num_headers= 1
|
1215
|
+
,.headers=
|
1216
|
+
{ { "Content-Type", "text/plain" }
|
1217
|
+
}
|
1218
|
+
,.body= "hello world"
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
#define NO_BODY_HTTP10_KA_200 13
|
1222
|
+
, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
|
1223
|
+
,.type= HTTP_RESPONSE
|
1224
|
+
,.raw= "HTTP/1.0 200 OK\r\n"
|
1225
|
+
"Connection: keep-alive\r\n"
|
1226
|
+
"\r\n"
|
1227
|
+
,.should_keep_alive= FALSE
|
1228
|
+
,.message_complete_on_eof= TRUE
|
1229
|
+
,.http_major= 1
|
1230
|
+
,.http_minor= 0
|
1231
|
+
,.status_code= 200
|
1232
|
+
,.num_headers= 1
|
1233
|
+
,.headers=
|
1234
|
+
{ { "Connection", "keep-alive" }
|
1235
|
+
}
|
1236
|
+
,.body_size= 0
|
1237
|
+
,.body= ""
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
#define NO_BODY_HTTP10_KA_204 14
|
1241
|
+
, {.name= "HTTP/1.0 with keep-alive and a 204 status"
|
1242
|
+
,.type= HTTP_RESPONSE
|
1243
|
+
,.raw= "HTTP/1.0 204 No content\r\n"
|
1244
|
+
"Connection: keep-alive\r\n"
|
1245
|
+
"\r\n"
|
1246
|
+
,.should_keep_alive= TRUE
|
1247
|
+
,.message_complete_on_eof= FALSE
|
1248
|
+
,.http_major= 1
|
1249
|
+
,.http_minor= 0
|
1250
|
+
,.status_code= 204
|
1251
|
+
,.num_headers= 1
|
1252
|
+
,.headers=
|
1253
|
+
{ { "Connection", "keep-alive" }
|
1254
|
+
}
|
1255
|
+
,.body_size= 0
|
1256
|
+
,.body= ""
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
#define NO_BODY_HTTP11_KA_200 15
|
1260
|
+
, {.name= "HTTP/1.1 with an EOF-terminated 200 status"
|
1261
|
+
,.type= HTTP_RESPONSE
|
1262
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1263
|
+
"\r\n"
|
1264
|
+
,.should_keep_alive= FALSE
|
1265
|
+
,.message_complete_on_eof= TRUE
|
1266
|
+
,.http_major= 1
|
1267
|
+
,.http_minor= 1
|
1268
|
+
,.status_code= 200
|
1269
|
+
,.num_headers= 0
|
1270
|
+
,.headers={}
|
1271
|
+
,.body_size= 0
|
1272
|
+
,.body= ""
|
1273
|
+
}
|
1274
|
+
|
1275
|
+
#define NO_BODY_HTTP11_KA_204 16
|
1276
|
+
, {.name= "HTTP/1.1 with a 204 status"
|
1277
|
+
,.type= HTTP_RESPONSE
|
1278
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
1279
|
+
"\r\n"
|
1280
|
+
,.should_keep_alive= TRUE
|
1281
|
+
,.message_complete_on_eof= FALSE
|
1282
|
+
,.http_major= 1
|
1283
|
+
,.http_minor= 1
|
1284
|
+
,.status_code= 204
|
1285
|
+
,.num_headers= 0
|
1286
|
+
,.headers={}
|
1287
|
+
,.body_size= 0
|
1288
|
+
,.body= ""
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
#define NO_BODY_HTTP11_NOKA_204 17
|
1292
|
+
, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
|
1293
|
+
,.type= HTTP_RESPONSE
|
1294
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
1295
|
+
"Connection: close\r\n"
|
1296
|
+
"\r\n"
|
1297
|
+
,.should_keep_alive= FALSE
|
1298
|
+
,.message_complete_on_eof= FALSE
|
1299
|
+
,.http_major= 1
|
1300
|
+
,.http_minor= 1
|
1301
|
+
,.status_code= 204
|
1302
|
+
,.num_headers= 1
|
1303
|
+
,.headers=
|
1304
|
+
{ { "Connection", "close" }
|
1305
|
+
}
|
1306
|
+
,.body_size= 0
|
1307
|
+
,.body= ""
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
#define NO_BODY_HTTP11_KA_CHUNKED_200 18
|
1311
|
+
, {.name= "HTTP/1.1 with chunked endocing and a 200 response"
|
1312
|
+
,.type= HTTP_RESPONSE
|
1313
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1314
|
+
"Transfer-Encoding: chunked\r\n"
|
1315
|
+
"\r\n"
|
1316
|
+
"0\r\n"
|
1317
|
+
"\r\n"
|
1318
|
+
,.should_keep_alive= TRUE
|
1319
|
+
,.message_complete_on_eof= FALSE
|
1320
|
+
,.http_major= 1
|
1321
|
+
,.http_minor= 1
|
1322
|
+
,.status_code= 200
|
1323
|
+
,.num_headers= 1
|
1324
|
+
,.headers=
|
1325
|
+
{ { "Transfer-Encoding", "chunked" }
|
1326
|
+
}
|
1327
|
+
,.body_size= 0
|
1328
|
+
,.body= ""
|
1329
|
+
}
|
1330
|
+
|
1331
|
+
#if !HTTP_PARSER_STRICT
|
1332
|
+
#define SPACE_IN_FIELD_RES 19
|
1333
|
+
/* Should handle spaces in header fields */
|
1334
|
+
, {.name= "field space"
|
1335
|
+
,.type= HTTP_RESPONSE
|
1336
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1337
|
+
"Server: Microsoft-IIS/6.0\r\n"
|
1338
|
+
"X-Powered-By: ASP.NET\r\n"
|
1339
|
+
"en-US Content-Type: text/xml\r\n" /* this is the problem */
|
1340
|
+
"Content-Type: text/xml\r\n"
|
1341
|
+
"Content-Length: 16\r\n"
|
1342
|
+
"Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
|
1343
|
+
"Connection: keep-alive\r\n"
|
1344
|
+
"\r\n"
|
1345
|
+
"<xml>hello</xml>" /* fake body */
|
1346
|
+
,.should_keep_alive= TRUE
|
1347
|
+
,.message_complete_on_eof= FALSE
|
1348
|
+
,.http_major= 1
|
1349
|
+
,.http_minor= 1
|
1350
|
+
,.status_code= 200
|
1351
|
+
,.num_headers= 7
|
1352
|
+
,.headers=
|
1353
|
+
{ { "Server", "Microsoft-IIS/6.0" }
|
1354
|
+
, { "X-Powered-By", "ASP.NET" }
|
1355
|
+
, { "en-US Content-Type", "text/xml" }
|
1356
|
+
, { "Content-Type", "text/xml" }
|
1357
|
+
, { "Content-Length", "16" }
|
1358
|
+
, { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
|
1359
|
+
, { "Connection", "keep-alive" }
|
1360
|
+
}
|
1361
|
+
,.body= "<xml>hello</xml>"
|
1022
1362
|
}
|
1023
|
-
|
1363
|
+
#endif /* !HTTP_PARSER_STRICT */
|
1024
1364
|
|
1025
1365
|
, {.name= NULL } /* sentinel */
|
1026
1366
|
};
|
1027
1367
|
|
1028
|
-
int
|
1029
|
-
request_path_cb (http_parser *p, const char *buf, size_t len)
|
1030
|
-
{
|
1031
|
-
assert(p == parser);
|
1032
|
-
strncat(messages[num_messages].request_path, buf, len);
|
1033
|
-
return 0;
|
1034
|
-
}
|
1035
|
-
|
1036
1368
|
int
|
1037
1369
|
request_url_cb (http_parser *p, const char *buf, size_t len)
|
1038
1370
|
{
|
@@ -1041,22 +1373,6 @@ request_url_cb (http_parser *p, const char *buf, size_t len)
|
|
1041
1373
|
return 0;
|
1042
1374
|
}
|
1043
1375
|
|
1044
|
-
int
|
1045
|
-
query_string_cb (http_parser *p, const char *buf, size_t len)
|
1046
|
-
{
|
1047
|
-
assert(p == parser);
|
1048
|
-
strncat(messages[num_messages].query_string, buf, len);
|
1049
|
-
return 0;
|
1050
|
-
}
|
1051
|
-
|
1052
|
-
int
|
1053
|
-
fragment_cb (http_parser *p, const char *buf, size_t len)
|
1054
|
-
{
|
1055
|
-
assert(p == parser);
|
1056
|
-
strncat(messages[num_messages].fragment, buf, len);
|
1057
|
-
return 0;
|
1058
|
-
}
|
1059
|
-
|
1060
1376
|
int
|
1061
1377
|
header_field_cb (http_parser *p, const char *buf, size_t len)
|
1062
1378
|
{
|
@@ -1136,7 +1452,7 @@ message_complete_cb (http_parser *p)
|
|
1136
1452
|
"value in both on_message_complete and on_headers_complete "
|
1137
1453
|
"but it doesn't! ***\n\n");
|
1138
1454
|
assert(0);
|
1139
|
-
|
1455
|
+
abort();
|
1140
1456
|
}
|
1141
1457
|
messages[num_messages].message_complete_cb_called = TRUE;
|
1142
1458
|
|
@@ -1146,14 +1462,151 @@ message_complete_cb (http_parser *p)
|
|
1146
1462
|
return 0;
|
1147
1463
|
}
|
1148
1464
|
|
1465
|
+
/* These dontcall_* callbacks exist so that we can verify that when we're
|
1466
|
+
* paused, no additional callbacks are invoked */
|
1467
|
+
int
|
1468
|
+
dontcall_message_begin_cb (http_parser *p)
|
1469
|
+
{
|
1470
|
+
if (p) { } // gcc
|
1471
|
+
fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
|
1472
|
+
abort();
|
1473
|
+
}
|
1474
|
+
|
1475
|
+
int
|
1476
|
+
dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
|
1477
|
+
{
|
1478
|
+
if (p || buf || len) { } // gcc
|
1479
|
+
fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
|
1480
|
+
abort();
|
1481
|
+
}
|
1482
|
+
|
1483
|
+
int
|
1484
|
+
dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
|
1485
|
+
{
|
1486
|
+
if (p || buf || len) { } // gcc
|
1487
|
+
fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
|
1488
|
+
abort();
|
1489
|
+
}
|
1490
|
+
|
1491
|
+
int
|
1492
|
+
dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
|
1493
|
+
{
|
1494
|
+
if (p || buf || len) { } // gcc
|
1495
|
+
fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
|
1496
|
+
abort();
|
1497
|
+
}
|
1498
|
+
|
1499
|
+
int
|
1500
|
+
dontcall_body_cb (http_parser *p, const char *buf, size_t len)
|
1501
|
+
{
|
1502
|
+
if (p || buf || len) { } // gcc
|
1503
|
+
fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
|
1504
|
+
abort();
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
int
|
1508
|
+
dontcall_headers_complete_cb (http_parser *p)
|
1509
|
+
{
|
1510
|
+
if (p) { } // gcc
|
1511
|
+
fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
|
1512
|
+
"parser ***\n\n");
|
1513
|
+
abort();
|
1514
|
+
}
|
1515
|
+
|
1516
|
+
int
|
1517
|
+
dontcall_message_complete_cb (http_parser *p)
|
1518
|
+
{
|
1519
|
+
if (p) { } // gcc
|
1520
|
+
fprintf(stderr, "\n\n*** on_message_complete() called on paused "
|
1521
|
+
"parser ***\n\n");
|
1522
|
+
abort();
|
1523
|
+
}
|
1524
|
+
|
1525
|
+
static http_parser_settings settings_dontcall =
|
1526
|
+
{.on_message_begin = dontcall_message_begin_cb
|
1527
|
+
,.on_header_field = dontcall_header_field_cb
|
1528
|
+
,.on_header_value = dontcall_header_value_cb
|
1529
|
+
,.on_url = dontcall_request_url_cb
|
1530
|
+
,.on_body = dontcall_body_cb
|
1531
|
+
,.on_headers_complete = dontcall_headers_complete_cb
|
1532
|
+
,.on_message_complete = dontcall_message_complete_cb
|
1533
|
+
};
|
1534
|
+
|
1535
|
+
/* These pause_* callbacks always pause the parser and just invoke the regular
|
1536
|
+
* callback that tracks content. Before returning, we overwrite the parser
|
1537
|
+
* settings to point to the _dontcall variety so that we can verify that
|
1538
|
+
* the pause actually did, you know, pause. */
|
1539
|
+
int
|
1540
|
+
pause_message_begin_cb (http_parser *p)
|
1541
|
+
{
|
1542
|
+
http_parser_pause(p, 1);
|
1543
|
+
*current_pause_parser = settings_dontcall;
|
1544
|
+
return message_begin_cb(p);
|
1545
|
+
}
|
1546
|
+
|
1547
|
+
int
|
1548
|
+
pause_header_field_cb (http_parser *p, const char *buf, size_t len)
|
1549
|
+
{
|
1550
|
+
http_parser_pause(p, 1);
|
1551
|
+
*current_pause_parser = settings_dontcall;
|
1552
|
+
return header_field_cb(p, buf, len);
|
1553
|
+
}
|
1554
|
+
|
1555
|
+
int
|
1556
|
+
pause_header_value_cb (http_parser *p, const char *buf, size_t len)
|
1557
|
+
{
|
1558
|
+
http_parser_pause(p, 1);
|
1559
|
+
*current_pause_parser = settings_dontcall;
|
1560
|
+
return header_value_cb(p, buf, len);
|
1561
|
+
}
|
1562
|
+
|
1563
|
+
int
|
1564
|
+
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
1565
|
+
{
|
1566
|
+
http_parser_pause(p, 1);
|
1567
|
+
*current_pause_parser = settings_dontcall;
|
1568
|
+
return request_url_cb(p, buf, len);
|
1569
|
+
}
|
1570
|
+
|
1571
|
+
int
|
1572
|
+
pause_body_cb (http_parser *p, const char *buf, size_t len)
|
1573
|
+
{
|
1574
|
+
http_parser_pause(p, 1);
|
1575
|
+
*current_pause_parser = settings_dontcall;
|
1576
|
+
return body_cb(p, buf, len);
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
int
|
1580
|
+
pause_headers_complete_cb (http_parser *p)
|
1581
|
+
{
|
1582
|
+
http_parser_pause(p, 1);
|
1583
|
+
*current_pause_parser = settings_dontcall;
|
1584
|
+
return headers_complete_cb(p);
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
int
|
1588
|
+
pause_message_complete_cb (http_parser *p)
|
1589
|
+
{
|
1590
|
+
http_parser_pause(p, 1);
|
1591
|
+
*current_pause_parser = settings_dontcall;
|
1592
|
+
return message_complete_cb(p);
|
1593
|
+
}
|
1594
|
+
|
1595
|
+
static http_parser_settings settings_pause =
|
1596
|
+
{.on_message_begin = pause_message_begin_cb
|
1597
|
+
,.on_header_field = pause_header_field_cb
|
1598
|
+
,.on_header_value = pause_header_value_cb
|
1599
|
+
,.on_url = pause_request_url_cb
|
1600
|
+
,.on_body = pause_body_cb
|
1601
|
+
,.on_headers_complete = pause_headers_complete_cb
|
1602
|
+
,.on_message_complete = pause_message_complete_cb
|
1603
|
+
};
|
1604
|
+
|
1149
1605
|
static http_parser_settings settings =
|
1150
1606
|
{.on_message_begin = message_begin_cb
|
1151
1607
|
,.on_header_field = header_field_cb
|
1152
1608
|
,.on_header_value = header_value_cb
|
1153
|
-
,.on_path = request_path_cb
|
1154
1609
|
,.on_url = request_url_cb
|
1155
|
-
,.on_fragment = fragment_cb
|
1156
|
-
,.on_query_string = query_string_cb
|
1157
1610
|
,.on_body = body_cb
|
1158
1611
|
,.on_headers_complete = headers_complete_cb
|
1159
1612
|
,.on_message_complete = message_complete_cb
|
@@ -1163,10 +1616,7 @@ static http_parser_settings settings_count_body =
|
|
1163
1616
|
{.on_message_begin = message_begin_cb
|
1164
1617
|
,.on_header_field = header_field_cb
|
1165
1618
|
,.on_header_value = header_value_cb
|
1166
|
-
,.on_path = request_path_cb
|
1167
1619
|
,.on_url = request_url_cb
|
1168
|
-
,.on_fragment = fragment_cb
|
1169
|
-
,.on_query_string = query_string_cb
|
1170
1620
|
,.on_body = count_body_cb
|
1171
1621
|
,.on_headers_complete = headers_complete_cb
|
1172
1622
|
,.on_message_complete = message_complete_cb
|
@@ -1176,10 +1626,7 @@ static http_parser_settings settings_null =
|
|
1176
1626
|
{.on_message_begin = 0
|
1177
1627
|
,.on_header_field = 0
|
1178
1628
|
,.on_header_value = 0
|
1179
|
-
,.on_path = 0
|
1180
1629
|
,.on_url = 0
|
1181
|
-
,.on_fragment = 0
|
1182
|
-
,.on_query_string = 0
|
1183
1630
|
,.on_body = 0
|
1184
1631
|
,.on_headers_complete = 0
|
1185
1632
|
,.on_message_complete = 0
|
@@ -1224,12 +1671,29 @@ size_t parse_count_body (const char *buf, size_t len)
|
|
1224
1671
|
return nparsed;
|
1225
1672
|
}
|
1226
1673
|
|
1674
|
+
size_t parse_pause (const char *buf, size_t len)
|
1675
|
+
{
|
1676
|
+
size_t nparsed;
|
1677
|
+
http_parser_settings s = settings_pause;
|
1678
|
+
|
1679
|
+
currently_parsing_eof = (len == 0);
|
1680
|
+
current_pause_parser = &s;
|
1681
|
+
nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
|
1682
|
+
return nparsed;
|
1683
|
+
}
|
1684
|
+
|
1227
1685
|
static inline int
|
1228
1686
|
check_str_eq (const struct message *m,
|
1229
1687
|
const char *prop,
|
1230
1688
|
const char *expected,
|
1231
1689
|
const char *found) {
|
1232
|
-
if (
|
1690
|
+
if ((expected == NULL) != (found == NULL)) {
|
1691
|
+
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
1692
|
+
printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
|
1693
|
+
printf(" found %s\n", (found == NULL) ? "NULL" : found);
|
1694
|
+
return 0;
|
1695
|
+
}
|
1696
|
+
if (expected != NULL && 0 != strcmp(expected, found)) {
|
1233
1697
|
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
1234
1698
|
printf("expected '%s'\n", expected);
|
1235
1699
|
printf(" found '%s'\n", found);
|
@@ -1258,6 +1722,20 @@ check_num_eq (const struct message *m,
|
|
1258
1722
|
#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
|
1259
1723
|
if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
|
1260
1724
|
|
1725
|
+
#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
|
1726
|
+
do { \
|
1727
|
+
char ubuf[256]; \
|
1728
|
+
\
|
1729
|
+
if ((u)->field_set & (1 << (fn))) { \
|
1730
|
+
memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
|
1731
|
+
(u)->field_data[(fn)].len); \
|
1732
|
+
ubuf[(u)->field_data[(fn)].len] = '\0'; \
|
1733
|
+
} else { \
|
1734
|
+
ubuf[0] = '\0'; \
|
1735
|
+
} \
|
1736
|
+
\
|
1737
|
+
check_str_eq(expected, #prop, expected->prop, ubuf); \
|
1738
|
+
} while(0)
|
1261
1739
|
|
1262
1740
|
int
|
1263
1741
|
message_eq (int index, const struct message *expected)
|
@@ -1282,10 +1760,29 @@ message_eq (int index, const struct message *expected)
|
|
1282
1760
|
assert(m->message_complete_cb_called);
|
1283
1761
|
|
1284
1762
|
|
1285
|
-
MESSAGE_CHECK_STR_EQ(expected, m, request_path);
|
1286
|
-
MESSAGE_CHECK_STR_EQ(expected, m, query_string);
|
1287
|
-
MESSAGE_CHECK_STR_EQ(expected, m, fragment);
|
1288
1763
|
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
|
1764
|
+
|
1765
|
+
/* Check URL components; we can't do this w/ CONNECT since it doesn't
|
1766
|
+
* send us a well-formed URL.
|
1767
|
+
*/
|
1768
|
+
if (*m->request_url && m->method != HTTP_CONNECT) {
|
1769
|
+
struct http_parser_url u;
|
1770
|
+
|
1771
|
+
if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
|
1772
|
+
fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
|
1773
|
+
m->request_url);
|
1774
|
+
abort();
|
1775
|
+
}
|
1776
|
+
|
1777
|
+
m->port = (u.field_set & (1 << UF_PORT)) ?
|
1778
|
+
u.port : 0;
|
1779
|
+
|
1780
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
|
1781
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
|
1782
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
|
1783
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, port);
|
1784
|
+
}
|
1785
|
+
|
1289
1786
|
if (expected->body_size) {
|
1290
1787
|
MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
|
1291
1788
|
} else {
|
@@ -1302,13 +1799,81 @@ message_eq (int index, const struct message *expected)
|
|
1302
1799
|
if (!r) return 0;
|
1303
1800
|
}
|
1304
1801
|
|
1802
|
+
MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
|
1803
|
+
|
1305
1804
|
return 1;
|
1306
1805
|
}
|
1307
1806
|
|
1807
|
+
/* Given a sequence of varargs messages, return the number of them that the
|
1808
|
+
* parser should successfully parse, taking into account that upgraded
|
1809
|
+
* messages prevent all subsequent messages from being parsed.
|
1810
|
+
*/
|
1811
|
+
size_t
|
1812
|
+
count_parsed_messages(const size_t nmsgs, ...) {
|
1813
|
+
size_t i;
|
1814
|
+
va_list ap;
|
1815
|
+
|
1816
|
+
va_start(ap, nmsgs);
|
1817
|
+
|
1818
|
+
for (i = 0; i < nmsgs; i++) {
|
1819
|
+
struct message *m = va_arg(ap, struct message *);
|
1820
|
+
|
1821
|
+
if (m->upgrade) {
|
1822
|
+
va_end(ap);
|
1823
|
+
return i + 1;
|
1824
|
+
}
|
1825
|
+
}
|
1826
|
+
|
1827
|
+
va_end(ap);
|
1828
|
+
return nmsgs;
|
1829
|
+
}
|
1830
|
+
|
1831
|
+
/* Given a sequence of bytes and the number of these that we were able to
|
1832
|
+
* parse, verify that upgrade bodies are correct.
|
1833
|
+
*/
|
1834
|
+
void
|
1835
|
+
upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
|
1836
|
+
va_list ap;
|
1837
|
+
size_t i;
|
1838
|
+
size_t off = 0;
|
1839
|
+
|
1840
|
+
va_start(ap, nmsgs);
|
1841
|
+
|
1842
|
+
for (i = 0; i < nmsgs; i++) {
|
1843
|
+
struct message *m = va_arg(ap, struct message *);
|
1844
|
+
|
1845
|
+
off += strlen(m->raw);
|
1846
|
+
|
1847
|
+
if (m->upgrade) {
|
1848
|
+
off -= strlen(m->upgrade);
|
1849
|
+
|
1850
|
+
/* Check the portion of the response after its specified upgrade */
|
1851
|
+
if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
|
1852
|
+
abort();
|
1853
|
+
}
|
1854
|
+
|
1855
|
+
/* Fix up the response so that message_eq() will verify the beginning
|
1856
|
+
* of the upgrade */
|
1857
|
+
*(body + nread + strlen(m->upgrade)) = '\0';
|
1858
|
+
messages[num_messages -1 ].upgrade = body + nread;
|
1859
|
+
|
1860
|
+
va_end(ap);
|
1861
|
+
return;
|
1862
|
+
}
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
va_end(ap);
|
1866
|
+
printf("\n\n*** Error: expected a message with upgrade ***\n");
|
1867
|
+
|
1868
|
+
abort();
|
1869
|
+
}
|
1870
|
+
|
1308
1871
|
static void
|
1309
1872
|
print_error (const char *raw, size_t error_location)
|
1310
1873
|
{
|
1311
|
-
fprintf(stderr, "\n***
|
1874
|
+
fprintf(stderr, "\n*** %s:%d -- %s ***\n\n",
|
1875
|
+
"http_parser.c", HTTP_PARSER_ERRNO_LINE(parser),
|
1876
|
+
http_errno_description(HTTP_PARSER_ERRNO(parser)));
|
1312
1877
|
|
1313
1878
|
int this_line = 0, char_len = 0;
|
1314
1879
|
size_t i, j, len = strlen(raw), error_location_line = 0;
|
@@ -1346,6 +1911,218 @@ print_error (const char *raw, size_t error_location)
|
|
1346
1911
|
fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
|
1347
1912
|
}
|
1348
1913
|
|
1914
|
+
void
|
1915
|
+
test_preserve_data (void)
|
1916
|
+
{
|
1917
|
+
char my_data[] = "application-specific data";
|
1918
|
+
http_parser parser;
|
1919
|
+
parser.data = my_data;
|
1920
|
+
http_parser_init(&parser, HTTP_REQUEST);
|
1921
|
+
if (parser.data != my_data) {
|
1922
|
+
printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
|
1923
|
+
abort();
|
1924
|
+
}
|
1925
|
+
}
|
1926
|
+
|
1927
|
+
struct url_test {
|
1928
|
+
const char *name;
|
1929
|
+
const char *url;
|
1930
|
+
int is_connect;
|
1931
|
+
struct http_parser_url u;
|
1932
|
+
int rv;
|
1933
|
+
};
|
1934
|
+
|
1935
|
+
const struct url_test url_tests[] =
|
1936
|
+
{ {.name="proxy request"
|
1937
|
+
,.url="http://hostname/"
|
1938
|
+
,.is_connect=0
|
1939
|
+
,.u=
|
1940
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
1941
|
+
,.port=0
|
1942
|
+
,.field_data=
|
1943
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
1944
|
+
,{ 7, 8 } /* UF_HOST */
|
1945
|
+
,{ 0, 0 } /* UF_PORT */
|
1946
|
+
,{ 15, 1 } /* UF_PATH */
|
1947
|
+
,{ 0, 0 } /* UF_QUERY */
|
1948
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
1949
|
+
}
|
1950
|
+
}
|
1951
|
+
,.rv=0
|
1952
|
+
}
|
1953
|
+
|
1954
|
+
, {.name="CONNECT request"
|
1955
|
+
,.url="hostname:443"
|
1956
|
+
,.is_connect=1
|
1957
|
+
,.u=
|
1958
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
1959
|
+
,.port=443
|
1960
|
+
,.field_data=
|
1961
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
1962
|
+
,{ 0, 8 } /* UF_HOST */
|
1963
|
+
,{ 9, 3 } /* UF_PORT */
|
1964
|
+
,{ 0, 0 } /* UF_PATH */
|
1965
|
+
,{ 0, 0 } /* UF_QUERY */
|
1966
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
1967
|
+
}
|
1968
|
+
}
|
1969
|
+
,.rv=0
|
1970
|
+
}
|
1971
|
+
|
1972
|
+
, {.name="proxy ipv6 request"
|
1973
|
+
,.url="http://[1:2::3:4]/"
|
1974
|
+
,.is_connect=0
|
1975
|
+
,.u=
|
1976
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
1977
|
+
,.port=0
|
1978
|
+
,.field_data=
|
1979
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
1980
|
+
,{ 8, 8 } /* UF_HOST */
|
1981
|
+
,{ 0, 0 } /* UF_PORT */
|
1982
|
+
,{ 17, 1 } /* UF_PATH */
|
1983
|
+
,{ 0, 0 } /* UF_QUERY */
|
1984
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
1985
|
+
}
|
1986
|
+
}
|
1987
|
+
,.rv=0
|
1988
|
+
}
|
1989
|
+
|
1990
|
+
, {.name="CONNECT ipv6 address"
|
1991
|
+
,.url="[1:2::3:4]:443"
|
1992
|
+
,.is_connect=1
|
1993
|
+
,.u=
|
1994
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
1995
|
+
,.port=443
|
1996
|
+
,.field_data=
|
1997
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
1998
|
+
,{ 1, 8 } /* UF_HOST */
|
1999
|
+
,{ 11, 3 } /* UF_PORT */
|
2000
|
+
,{ 0, 0 } /* UF_PATH */
|
2001
|
+
,{ 0, 0 } /* UF_QUERY */
|
2002
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2003
|
+
}
|
2004
|
+
}
|
2005
|
+
,.rv=0
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
, {.name="extra ? in query string"
|
2009
|
+
,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
|
2010
|
+
,.is_connect=0
|
2011
|
+
,.u=
|
2012
|
+
{.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
|
2013
|
+
,.port=0
|
2014
|
+
,.field_data=
|
2015
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2016
|
+
,{ 7, 10 } /* UF_HOST */
|
2017
|
+
,{ 0, 0 } /* UF_PORT */
|
2018
|
+
,{ 17, 12 } /* UF_PATH */
|
2019
|
+
,{ 30,187 } /* UF_QUERY */
|
2020
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2021
|
+
}
|
2022
|
+
}
|
2023
|
+
,.rv=0
|
2024
|
+
}
|
2025
|
+
|
2026
|
+
, {.name="proxy empty host"
|
2027
|
+
,.url="http://:443/"
|
2028
|
+
,.is_connect=0
|
2029
|
+
,.rv=1
|
2030
|
+
}
|
2031
|
+
|
2032
|
+
, {.name="proxy empty port"
|
2033
|
+
,.url="http://hostname:/"
|
2034
|
+
,.is_connect=0
|
2035
|
+
,.rv=1
|
2036
|
+
}
|
2037
|
+
|
2038
|
+
, {.name="CONNECT empty host"
|
2039
|
+
,.url=":443"
|
2040
|
+
,.is_connect=1
|
2041
|
+
,.rv=1
|
2042
|
+
}
|
2043
|
+
|
2044
|
+
, {.name="CONNECT empty port"
|
2045
|
+
,.url="hostname:"
|
2046
|
+
,.is_connect=1
|
2047
|
+
,.rv=1
|
2048
|
+
}
|
2049
|
+
|
2050
|
+
, {.name="CONNECT with extra bits"
|
2051
|
+
,.url="hostname:443/"
|
2052
|
+
,.is_connect=1
|
2053
|
+
,.rv=1
|
2054
|
+
}
|
2055
|
+
};
|
2056
|
+
|
2057
|
+
void
|
2058
|
+
dump_url (const char *url, const struct http_parser_url *u)
|
2059
|
+
{
|
2060
|
+
char part[512];
|
2061
|
+
unsigned int i;
|
2062
|
+
|
2063
|
+
printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
|
2064
|
+
for (i = 0; i < UF_MAX; i++) {
|
2065
|
+
if ((u->field_set & (1 << i)) == 0) {
|
2066
|
+
printf("\tfield_data[%u]: unset\n", i);
|
2067
|
+
continue;
|
2068
|
+
}
|
2069
|
+
|
2070
|
+
memcpy(part, url + u->field_data[i].off, u->field_data[i].len);
|
2071
|
+
part[u->field_data[i].len] = '\0';
|
2072
|
+
|
2073
|
+
printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n",
|
2074
|
+
i,
|
2075
|
+
u->field_data[i].off,
|
2076
|
+
u->field_data[i].len,
|
2077
|
+
part);
|
2078
|
+
}
|
2079
|
+
}
|
2080
|
+
|
2081
|
+
void
|
2082
|
+
test_parse_url (void)
|
2083
|
+
{
|
2084
|
+
struct http_parser_url u;
|
2085
|
+
const struct url_test *test;
|
2086
|
+
unsigned int i;
|
2087
|
+
int rv;
|
2088
|
+
|
2089
|
+
for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
|
2090
|
+
test = &url_tests[i];
|
2091
|
+
memset(&u, 0, sizeof(u));
|
2092
|
+
|
2093
|
+
rv = http_parser_parse_url(test->url,
|
2094
|
+
strlen(test->url),
|
2095
|
+
test->is_connect,
|
2096
|
+
&u);
|
2097
|
+
|
2098
|
+
if (test->rv == 0) {
|
2099
|
+
if (rv != 0) {
|
2100
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
2101
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
2102
|
+
abort();
|
2103
|
+
}
|
2104
|
+
|
2105
|
+
if (memcmp(&u, &test->u, sizeof(u)) != 0) {
|
2106
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
|
2107
|
+
test->url, test->name);
|
2108
|
+
|
2109
|
+
printf("target http_parser_url:\n");
|
2110
|
+
dump_url(test->url, &test->u);
|
2111
|
+
printf("result http_parser_url:\n");
|
2112
|
+
dump_url(test->url, &u);
|
2113
|
+
|
2114
|
+
abort();
|
2115
|
+
}
|
2116
|
+
} else {
|
2117
|
+
/* test->rv != 0 */
|
2118
|
+
if (rv == 0) {
|
2119
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
2120
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
2121
|
+
abort();
|
2122
|
+
}
|
2123
|
+
}
|
2124
|
+
}
|
2125
|
+
}
|
1349
2126
|
|
1350
2127
|
void
|
1351
2128
|
test_message (const struct message *message)
|
@@ -1363,41 +2140,45 @@ test_message (const struct message *message)
|
|
1363
2140
|
if (msg1len) {
|
1364
2141
|
read = parse(msg1, msg1len);
|
1365
2142
|
|
1366
|
-
if (message->upgrade && parser->upgrade)
|
2143
|
+
if (message->upgrade && parser->upgrade) {
|
2144
|
+
messages[num_messages - 1].upgrade = msg1 + read;
|
2145
|
+
goto test;
|
2146
|
+
}
|
1367
2147
|
|
1368
2148
|
if (read != msg1len) {
|
1369
2149
|
print_error(msg1, read);
|
1370
|
-
|
2150
|
+
abort();
|
1371
2151
|
}
|
1372
2152
|
}
|
1373
2153
|
|
1374
2154
|
|
1375
2155
|
read = parse(msg2, msg2len);
|
1376
2156
|
|
1377
|
-
if (message->upgrade && parser->upgrade)
|
2157
|
+
if (message->upgrade && parser->upgrade) {
|
2158
|
+
messages[num_messages - 1].upgrade = msg2 + read;
|
2159
|
+
goto test;
|
2160
|
+
}
|
1378
2161
|
|
1379
2162
|
if (read != msg2len) {
|
1380
2163
|
print_error(msg2, read);
|
1381
|
-
|
2164
|
+
abort();
|
1382
2165
|
}
|
1383
2166
|
|
1384
2167
|
read = parse(NULL, 0);
|
1385
2168
|
|
1386
|
-
if (message->upgrade && parser->upgrade) goto test;
|
1387
|
-
|
1388
2169
|
if (read != 0) {
|
1389
2170
|
print_error(message->raw, read);
|
1390
|
-
|
2171
|
+
abort();
|
1391
2172
|
}
|
1392
2173
|
|
1393
2174
|
test:
|
1394
2175
|
|
1395
2176
|
if (num_messages != 1) {
|
1396
2177
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
1397
|
-
|
2178
|
+
abort();
|
1398
2179
|
}
|
1399
2180
|
|
1400
|
-
if(!message_eq(0, message))
|
2181
|
+
if(!message_eq(0, message)) abort();
|
1401
2182
|
|
1402
2183
|
parser_free();
|
1403
2184
|
}
|
@@ -1418,7 +2199,7 @@ test_message_count_body (const struct message *message)
|
|
1418
2199
|
read = parse_count_body(message->raw + i, toread);
|
1419
2200
|
if (read != toread) {
|
1420
2201
|
print_error(message->raw, read);
|
1421
|
-
|
2202
|
+
abort();
|
1422
2203
|
}
|
1423
2204
|
}
|
1424
2205
|
|
@@ -1426,36 +2207,47 @@ test_message_count_body (const struct message *message)
|
|
1426
2207
|
read = parse_count_body(NULL, 0);
|
1427
2208
|
if (read != 0) {
|
1428
2209
|
print_error(message->raw, read);
|
1429
|
-
|
2210
|
+
abort();
|
1430
2211
|
}
|
1431
2212
|
|
1432
2213
|
if (num_messages != 1) {
|
1433
2214
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
1434
|
-
|
2215
|
+
abort();
|
1435
2216
|
}
|
1436
2217
|
|
1437
|
-
if(!message_eq(0, message))
|
2218
|
+
if(!message_eq(0, message)) abort();
|
1438
2219
|
|
1439
2220
|
parser_free();
|
1440
2221
|
}
|
1441
2222
|
|
1442
2223
|
void
|
1443
|
-
test_simple (const char *buf,
|
2224
|
+
test_simple (const char *buf, enum http_errno err_expected)
|
1444
2225
|
{
|
1445
2226
|
parser_init(HTTP_REQUEST);
|
1446
2227
|
|
1447
2228
|
size_t parsed;
|
1448
2229
|
int pass;
|
2230
|
+
enum http_errno err;
|
2231
|
+
|
1449
2232
|
parsed = parse(buf, strlen(buf));
|
1450
2233
|
pass = (parsed == strlen(buf));
|
2234
|
+
err = HTTP_PARSER_ERRNO(parser);
|
1451
2235
|
parsed = parse(NULL, 0);
|
1452
2236
|
pass &= (parsed == 0);
|
1453
2237
|
|
1454
2238
|
parser_free();
|
1455
2239
|
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
2240
|
+
/* In strict mode, allow us to pass with an unexpected HPE_STRICT as
|
2241
|
+
* long as the caller isn't expecting success.
|
2242
|
+
*/
|
2243
|
+
#if HTTP_PARSER_STRICT
|
2244
|
+
if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
|
2245
|
+
#else
|
2246
|
+
if (err_expected != err) {
|
2247
|
+
#endif
|
2248
|
+
fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
|
2249
|
+
http_errno_name(err_expected), http_errno_name(err), buf);
|
2250
|
+
abort();
|
1459
2251
|
}
|
1460
2252
|
}
|
1461
2253
|
|
@@ -1471,16 +2263,67 @@ test_header_overflow_error (int req)
|
|
1471
2263
|
assert(parsed == strlen(buf));
|
1472
2264
|
|
1473
2265
|
buf = "header-key: header-value\r\n";
|
2266
|
+
size_t buflen = strlen(buf);
|
2267
|
+
|
1474
2268
|
int i;
|
1475
2269
|
for (i = 0; i < 10000; i++) {
|
1476
|
-
|
2270
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
2271
|
+
if (parsed != buflen) {
|
1477
2272
|
//fprintf(stderr, "error found on iter %d\n", i);
|
2273
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
|
1478
2274
|
return;
|
1479
2275
|
}
|
1480
2276
|
}
|
1481
2277
|
|
1482
2278
|
fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
|
1483
|
-
|
2279
|
+
abort();
|
2280
|
+
}
|
2281
|
+
|
2282
|
+
static void
|
2283
|
+
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
|
2284
|
+
{
|
2285
|
+
http_parser parser;
|
2286
|
+
http_parser_init(&parser, HTTP_RESPONSE);
|
2287
|
+
http_parser_execute(&parser, &settings_null, buf, buflen);
|
2288
|
+
|
2289
|
+
if (expect_ok)
|
2290
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
|
2291
|
+
else
|
2292
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
|
2293
|
+
}
|
2294
|
+
|
2295
|
+
void
|
2296
|
+
test_header_content_length_overflow_error (void)
|
2297
|
+
{
|
2298
|
+
#define X(size) \
|
2299
|
+
"HTTP/1.1 200 OK\r\n" \
|
2300
|
+
"Content-Length: " #size "\r\n" \
|
2301
|
+
"\r\n"
|
2302
|
+
const char a[] = X(18446744073709551614); /* 2^64-2 */
|
2303
|
+
const char b[] = X(18446744073709551615); /* 2^64-1 */
|
2304
|
+
const char c[] = X(18446744073709551616); /* 2^64 */
|
2305
|
+
#undef X
|
2306
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
2307
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
2308
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
2309
|
+
}
|
2310
|
+
|
2311
|
+
void
|
2312
|
+
test_chunk_content_length_overflow_error (void)
|
2313
|
+
{
|
2314
|
+
#define X(size) \
|
2315
|
+
"HTTP/1.1 200 OK\r\n" \
|
2316
|
+
"Transfer-Encoding: chunked\r\n" \
|
2317
|
+
"\r\n" \
|
2318
|
+
#size "\r\n" \
|
2319
|
+
"..."
|
2320
|
+
const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
|
2321
|
+
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
|
2322
|
+
const char c[] = X(10000000000000000); /* 2^64 */
|
2323
|
+
#undef X
|
2324
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
2325
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
2326
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
1484
2327
|
}
|
1485
2328
|
|
1486
2329
|
void
|
@@ -1513,18 +2356,13 @@ test_no_overflow_long_body (int req, size_t length)
|
|
1513
2356
|
"\n*** error in test_no_overflow_long_body %s of length %zu ***\n",
|
1514
2357
|
req ? "REQUEST" : "RESPONSE",
|
1515
2358
|
length);
|
1516
|
-
|
2359
|
+
abort();
|
1517
2360
|
}
|
1518
2361
|
|
1519
2362
|
void
|
1520
2363
|
test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
|
1521
2364
|
{
|
1522
|
-
int message_count =
|
1523
|
-
if (!r1->upgrade) {
|
1524
|
-
message_count++;
|
1525
|
-
if (!r2->upgrade) message_count++;
|
1526
|
-
}
|
1527
|
-
int has_upgrade = (message_count < 3 || r3->upgrade);
|
2365
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
1528
2366
|
|
1529
2367
|
char total[ strlen(r1->raw)
|
1530
2368
|
+ strlen(r2->raw)
|
@@ -1543,36 +2381,33 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
|
|
1543
2381
|
|
1544
2382
|
read = parse(total, strlen(total));
|
1545
2383
|
|
1546
|
-
if (
|
2384
|
+
if (parser->upgrade) {
|
2385
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
2386
|
+
goto test;
|
2387
|
+
}
|
1547
2388
|
|
1548
2389
|
if (read != strlen(total)) {
|
1549
2390
|
print_error(total, read);
|
1550
|
-
|
2391
|
+
abort();
|
1551
2392
|
}
|
1552
2393
|
|
1553
2394
|
read = parse(NULL, 0);
|
1554
2395
|
|
1555
|
-
if (has_upgrade && parser->upgrade) goto test;
|
1556
|
-
|
1557
2396
|
if (read != 0) {
|
1558
2397
|
print_error(total, read);
|
1559
|
-
|
2398
|
+
abort();
|
1560
2399
|
}
|
1561
2400
|
|
1562
2401
|
test:
|
1563
2402
|
|
1564
2403
|
if (message_count != num_messages) {
|
1565
2404
|
fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
|
1566
|
-
|
2405
|
+
abort();
|
1567
2406
|
}
|
1568
2407
|
|
1569
|
-
if (!message_eq(0, r1))
|
1570
|
-
if (message_count > 1)
|
1571
|
-
|
1572
|
-
if (message_count > 2) {
|
1573
|
-
if (!message_eq(2, r3)) exit(1);
|
1574
|
-
}
|
1575
|
-
}
|
2408
|
+
if (!message_eq(0, r1)) abort();
|
2409
|
+
if (message_count > 1 && !message_eq(1, r2)) abort();
|
2410
|
+
if (message_count > 2 && !message_eq(2, r3)) abort();
|
1576
2411
|
|
1577
2412
|
parser_free();
|
1578
2413
|
}
|
@@ -1601,6 +2436,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1601
2436
|
int ops = 0 ;
|
1602
2437
|
|
1603
2438
|
size_t buf1_len, buf2_len, buf3_len;
|
2439
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
1604
2440
|
|
1605
2441
|
int i,j,type_both;
|
1606
2442
|
for (type_both = 0; type_both < 2; type_both ++ ) {
|
@@ -1629,27 +2465,27 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1629
2465
|
|
1630
2466
|
read = parse(buf1, buf1_len);
|
1631
2467
|
|
1632
|
-
if (
|
2468
|
+
if (parser->upgrade) goto test;
|
1633
2469
|
|
1634
2470
|
if (read != buf1_len) {
|
1635
2471
|
print_error(buf1, read);
|
1636
2472
|
goto error;
|
1637
2473
|
}
|
1638
2474
|
|
1639
|
-
read
|
2475
|
+
read += parse(buf2, buf2_len);
|
1640
2476
|
|
1641
|
-
if (
|
2477
|
+
if (parser->upgrade) goto test;
|
1642
2478
|
|
1643
|
-
if (read != buf2_len) {
|
2479
|
+
if (read != buf1_len + buf2_len) {
|
1644
2480
|
print_error(buf2, read);
|
1645
2481
|
goto error;
|
1646
2482
|
}
|
1647
2483
|
|
1648
|
-
read
|
2484
|
+
read += parse(buf3, buf3_len);
|
1649
2485
|
|
1650
|
-
if (
|
2486
|
+
if (parser->upgrade) goto test;
|
1651
2487
|
|
1652
|
-
if (read != buf3_len) {
|
2488
|
+
if (read != buf1_len + buf2_len + buf3_len) {
|
1653
2489
|
print_error(buf3, read);
|
1654
2490
|
goto error;
|
1655
2491
|
}
|
@@ -1657,9 +2493,13 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1657
2493
|
parse(NULL, 0);
|
1658
2494
|
|
1659
2495
|
test:
|
2496
|
+
if (parser->upgrade) {
|
2497
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
2498
|
+
}
|
1660
2499
|
|
1661
|
-
if (
|
1662
|
-
fprintf(stderr, "\n\nParser didn't see
|
2500
|
+
if (message_count != num_messages) {
|
2501
|
+
fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
|
2502
|
+
message_count, num_messages);
|
1663
2503
|
goto error;
|
1664
2504
|
}
|
1665
2505
|
|
@@ -1668,12 +2508,12 @@ test:
|
|
1668
2508
|
goto error;
|
1669
2509
|
}
|
1670
2510
|
|
1671
|
-
if (!message_eq(1, r2)) {
|
2511
|
+
if (message_count > 1 && !message_eq(1, r2)) {
|
1672
2512
|
fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
|
1673
2513
|
goto error;
|
1674
2514
|
}
|
1675
2515
|
|
1676
|
-
if (!message_eq(2, r3)) {
|
2516
|
+
if (message_count > 2 && !message_eq(2, r3)) {
|
1677
2517
|
fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
|
1678
2518
|
goto error;
|
1679
2519
|
}
|
@@ -1690,7 +2530,7 @@ test:
|
|
1690
2530
|
fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
|
1691
2531
|
fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
|
1692
2532
|
fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
|
1693
|
-
|
2533
|
+
abort();
|
1694
2534
|
}
|
1695
2535
|
|
1696
2536
|
// user required to free the result
|
@@ -1724,49 +2564,50 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
|
1724
2564
|
return buf;
|
1725
2565
|
}
|
1726
2566
|
|
1727
|
-
char *
|
2567
|
+
char *
|
1728
2568
|
quote(const char * orig) {
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
2569
|
+
if (!orig) return NULL;
|
2570
|
+
size_t j, i, len = strlen(orig);
|
2571
|
+
char * quoted = malloc(len == 0 ? 1 : len*2); // hm..
|
2572
|
+
bzero(quoted, len == 0 ? 1 : len*2);
|
2573
|
+
for (i=0, j=0; i!=len; ++i) {
|
2574
|
+
switch (orig[i]){
|
2575
|
+
case '\n':
|
2576
|
+
quoted[j++] = '\\';
|
2577
|
+
quoted[j++] = 'n';
|
2578
|
+
break;
|
2579
|
+
case '\r':
|
2580
|
+
quoted[j++] = '\\';
|
2581
|
+
quoted[j++] = 'r';
|
2582
|
+
break;
|
2583
|
+
case '"':
|
2584
|
+
quoted[j++] = '\\';
|
2585
|
+
quoted[j++] = '"';
|
2586
|
+
break;
|
2587
|
+
default :
|
2588
|
+
quoted[j++] = orig[i];
|
2589
|
+
}
|
2590
|
+
}
|
2591
|
+
return quoted;
|
1751
2592
|
}
|
1752
2593
|
|
1753
|
-
void
|
2594
|
+
void
|
1754
2595
|
dump_message(const struct message * m)
|
1755
2596
|
{
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
2597
|
+
int i;
|
2598
|
+
printf("name :%s\n", m->name);
|
2599
|
+
char * bla = quote(m->raw);
|
2600
|
+
printf("raw :\"%s\"\n", bla);
|
2601
|
+
free(bla);
|
2602
|
+
switch (m->type){
|
2603
|
+
case HTTP_REQUEST:
|
2604
|
+
printf("type :HTTP_REQUEST\n");break;
|
2605
|
+
case HTTP_RESPONSE:
|
2606
|
+
printf("type :HTTP_RESPONSE\n"); break;
|
2607
|
+
case HTTP_BOTH:
|
2608
|
+
printf("type :HTTP_BOTH\n");
|
2609
|
+
}
|
2610
|
+
switch (m->method) {
|
1770
2611
|
case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
|
1771
2612
|
case HTTP_GET: printf("method: HTTP_GET\n");break;
|
1772
2613
|
case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
|
@@ -1792,38 +2633,42 @@ dump_message(const struct message * m)
|
|
1792
2633
|
case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
|
1793
2634
|
case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
|
1794
2635
|
case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
|
1795
|
-
|
2636
|
+
default:
|
1796
2637
|
printf("method: UNKNOWN\n"); break;
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
2638
|
+
break;
|
2639
|
+
}
|
2640
|
+
printf("status_code :%d\n", m->status_code);
|
1800
2641
|
printf("request_path:%s\n", m->request_path);
|
1801
2642
|
printf("request_url :%s\n", m->request_url);
|
1802
2643
|
printf("fragment :%s\n", m->fragment);
|
1803
2644
|
printf("query_string:%s\n", m->query_string);
|
1804
2645
|
|
1805
|
-
|
2646
|
+
bla = quote(m->body);
|
1806
2647
|
printf("body :\"%s\"\n", bla);
|
1807
|
-
|
2648
|
+
free(bla);
|
1808
2649
|
printf("body_size :%zu\n", m->body_size);
|
1809
2650
|
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
2651
|
+
for (i=0; i!=m->num_headers; ++i){
|
2652
|
+
printf("header_%d :{ \"%s\": \"%s\"}\n", i, m->headers[i][0], m->headers[i][1]);
|
2653
|
+
}
|
1813
2654
|
|
1814
2655
|
printf("should_keep_alive :%d\n", m->should_keep_alive);
|
1815
|
-
|
2656
|
+
bla = quote(m->upgrade);
|
2657
|
+
if (bla) {
|
2658
|
+
printf("upgrade :\"%s\"\n", bla);
|
2659
|
+
}
|
2660
|
+
free(bla);
|
1816
2661
|
printf("http_major :%d\n", m->http_major);
|
1817
2662
|
printf("http_minor :%d\n", m->http_minor);
|
1818
2663
|
// printf("message_begin_cb_called :%d\n", m->message_begin_cb_called);
|
1819
2664
|
// printf("headers_complete_cb_called:%d\n", m->headers_complete_cb_called);
|
1820
2665
|
// printf("message_complete_cb_called:%d\n", m->message_complete_cb_called);
|
1821
2666
|
// printf("message_complete_on_eof :%d\n", m->message_complete_on_eof);
|
1822
|
-
|
2667
|
+
printf("\n");
|
1823
2668
|
}
|
1824
2669
|
|
1825
|
-
void
|
1826
|
-
dump_messages(void)
|
2670
|
+
void
|
2671
|
+
dump_messages(void)
|
1827
2672
|
{
|
1828
2673
|
int request_count;
|
1829
2674
|
for (request_count = 0; requests[request_count].name; request_count++){
|
@@ -1834,6 +2679,60 @@ dump_messages(void)
|
|
1834
2679
|
}
|
1835
2680
|
}
|
1836
2681
|
|
2682
|
+
/* Verify that we can pause parsing at any of the bytes in the
|
2683
|
+
* message and still get the result that we're expecting. */
|
2684
|
+
void
|
2685
|
+
test_message_pause (const struct message *msg)
|
2686
|
+
{
|
2687
|
+
char *buf = (char*) msg->raw;
|
2688
|
+
size_t buflen = strlen(msg->raw);
|
2689
|
+
size_t nread;
|
2690
|
+
|
2691
|
+
parser_init(msg->type);
|
2692
|
+
|
2693
|
+
do {
|
2694
|
+
nread = parse_pause(buf, buflen);
|
2695
|
+
|
2696
|
+
// We can only set the upgrade buffer once we've gotten our message
|
2697
|
+
// completion callback.
|
2698
|
+
if (messages[0].message_complete_cb_called &&
|
2699
|
+
msg->upgrade &&
|
2700
|
+
parser->upgrade) {
|
2701
|
+
messages[0].upgrade = buf + nread;
|
2702
|
+
goto test;
|
2703
|
+
}
|
2704
|
+
|
2705
|
+
if (nread < buflen) {
|
2706
|
+
|
2707
|
+
// Not much do to if we failed a strict-mode check
|
2708
|
+
if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
|
2709
|
+
parser_free();
|
2710
|
+
return;
|
2711
|
+
}
|
2712
|
+
|
2713
|
+
assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
|
2714
|
+
}
|
2715
|
+
|
2716
|
+
buf += nread;
|
2717
|
+
buflen -= nread;
|
2718
|
+
http_parser_pause(parser, 0);
|
2719
|
+
} while (buflen > 0);
|
2720
|
+
|
2721
|
+
nread = parse_pause(NULL, 0);
|
2722
|
+
assert (nread == 0);
|
2723
|
+
|
2724
|
+
test:
|
2725
|
+
if (num_messages != 1) {
|
2726
|
+
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
2727
|
+
abort();
|
2728
|
+
}
|
2729
|
+
|
2730
|
+
if(!message_eq(0, msg)) abort();
|
2731
|
+
|
2732
|
+
parser_free();
|
2733
|
+
|
2734
|
+
}
|
2735
|
+
|
1837
2736
|
int
|
1838
2737
|
main (int argc, char * argv[])
|
1839
2738
|
{
|
@@ -1854,6 +2753,10 @@ main (int argc, char * argv[])
|
|
1854
2753
|
for (request_count = 0; requests[request_count].name; request_count++);
|
1855
2754
|
for (response_count = 0; responses[response_count].name; response_count++);
|
1856
2755
|
|
2756
|
+
//// API
|
2757
|
+
test_preserve_data();
|
2758
|
+
test_parse_url();
|
2759
|
+
|
1857
2760
|
//// OVERFLOW CONDITIONS
|
1858
2761
|
|
1859
2762
|
test_header_overflow_error(HTTP_REQUEST);
|
@@ -1864,12 +2767,19 @@ main (int argc, char * argv[])
|
|
1864
2767
|
test_no_overflow_long_body(HTTP_RESPONSE, 1000);
|
1865
2768
|
test_no_overflow_long_body(HTTP_RESPONSE, 100000);
|
1866
2769
|
|
2770
|
+
test_header_content_length_overflow_error();
|
2771
|
+
test_chunk_content_length_overflow_error();
|
2772
|
+
|
1867
2773
|
//// RESPONSES
|
1868
2774
|
|
1869
2775
|
for (i = 0; i < response_count; i++) {
|
1870
2776
|
test_message(&responses[i]);
|
1871
2777
|
}
|
1872
2778
|
|
2779
|
+
for (i = 0; i < response_count; i++) {
|
2780
|
+
test_message_pause(&responses[i]);
|
2781
|
+
}
|
2782
|
+
|
1873
2783
|
for (i = 0; i < response_count; i++) {
|
1874
2784
|
if (!responses[i].should_keep_alive) continue;
|
1875
2785
|
for (j = 0; j < response_count; j++) {
|
@@ -1914,7 +2824,7 @@ main (int argc, char * argv[])
|
|
1914
2824
|
|
1915
2825
|
printf("response scan 1/2 ");
|
1916
2826
|
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
|
1917
|
-
, &responses[
|
2827
|
+
, &responses[NO_BODY_HTTP10_KA_204]
|
1918
2828
|
, &responses[NO_REASON_PHRASE]
|
1919
2829
|
);
|
1920
2830
|
|
@@ -1929,13 +2839,13 @@ main (int argc, char * argv[])
|
|
1929
2839
|
|
1930
2840
|
/// REQUESTS
|
1931
2841
|
|
1932
|
-
test_simple("hello world",
|
1933
|
-
test_simple("GET / HTP/1.1\r\n\r\n",
|
2842
|
+
test_simple("hello world", HPE_INVALID_METHOD);
|
2843
|
+
test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
|
1934
2844
|
|
1935
2845
|
|
1936
|
-
test_simple("ASDF / HTTP/1.1\r\n\r\n",
|
1937
|
-
test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n",
|
1938
|
-
test_simple("GETA / HTTP/1.1\r\n\r\n",
|
2846
|
+
test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
2847
|
+
test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
2848
|
+
test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
1939
2849
|
|
1940
2850
|
// Well-formed but incomplete
|
1941
2851
|
test_simple("GET / HTTP/1.1\r\n"
|
@@ -1943,7 +2853,7 @@ main (int argc, char * argv[])
|
|
1943
2853
|
"Content-Length: 6\r\n"
|
1944
2854
|
"\r\n"
|
1945
2855
|
"fooba",
|
1946
|
-
|
2856
|
+
HPE_OK);
|
1947
2857
|
|
1948
2858
|
static const char *all_methods[] = {
|
1949
2859
|
"DELETE",
|
@@ -1961,12 +2871,31 @@ main (int argc, char * argv[])
|
|
1961
2871
|
"PROPFIND",
|
1962
2872
|
"PROPPATCH",
|
1963
2873
|
"UNLOCK",
|
2874
|
+
"REPORT",
|
2875
|
+
"MKACTIVITY",
|
2876
|
+
"CHECKOUT",
|
2877
|
+
"MERGE",
|
2878
|
+
"M-SEARCH",
|
2879
|
+
"NOTIFY",
|
2880
|
+
"SUBSCRIBE",
|
2881
|
+
"UNSUBSCRIBE",
|
2882
|
+
"PATCH",
|
1964
2883
|
0 };
|
1965
2884
|
const char **this_method;
|
1966
2885
|
for (this_method = all_methods; *this_method; this_method++) {
|
1967
2886
|
char buf[200];
|
1968
2887
|
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
1969
|
-
test_simple(buf,
|
2888
|
+
test_simple(buf, HPE_OK);
|
2889
|
+
}
|
2890
|
+
|
2891
|
+
static const char *bad_methods[] = {
|
2892
|
+
"C******",
|
2893
|
+
"M****",
|
2894
|
+
0 };
|
2895
|
+
for (this_method = bad_methods; *this_method; this_method++) {
|
2896
|
+
char buf[200];
|
2897
|
+
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
2898
|
+
test_simple(buf, HPE_UNKNOWN);
|
1970
2899
|
}
|
1971
2900
|
|
1972
2901
|
const char *dumbfuck2 =
|
@@ -2004,7 +2933,7 @@ main (int argc, char * argv[])
|
|
2004
2933
|
"\tRA==\r\n"
|
2005
2934
|
"\t-----END CERTIFICATE-----\r\n"
|
2006
2935
|
"\r\n";
|
2007
|
-
test_simple(dumbfuck2,
|
2936
|
+
test_simple(dumbfuck2, HPE_OK);
|
2008
2937
|
|
2009
2938
|
#if 0
|
2010
2939
|
// NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
|
@@ -2026,7 +2955,9 @@ main (int argc, char * argv[])
|
|
2026
2955
|
test_message(&requests[i]);
|
2027
2956
|
}
|
2028
2957
|
|
2029
|
-
|
2958
|
+
for (i = 0; i < request_count; i++) {
|
2959
|
+
test_message_pause(&requests[i]);
|
2960
|
+
}
|
2030
2961
|
|
2031
2962
|
for (i = 0; i < request_count; i++) {
|
2032
2963
|
if (!requests[i].should_keep_alive) continue;
|