http_parser.rb 0.5.2 → 0.7.0
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.
- checksums.yaml +7 -0
- data/.github/workflows/linux.yml +23 -0
- data/.github/workflows/windows.yml +23 -0
- data/.gitignore +5 -4
- data/.gitmodules +4 -4
- data/Gemfile +1 -1
- data/README.md +52 -47
- data/Rakefile +1 -0
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +1 -0
- data/ext/ruby_http_parser/extconf.rb +1 -1
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +139 -83
- data/ext/ruby_http_parser/ruby_http_parser.c +40 -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 +1202 -671
- 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 +172 -51
- 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/HTTPMethod.java +8 -3
- 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 +35 -102
- 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/HTTPParser.java +775 -682
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
- 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 +1637 -280
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +68 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -1
- data/ext/ruby_http_parser/vendor/http-parser/README.md +113 -38
- data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
- data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
- data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1576 -780
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +111 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +308 -58
- data/ext/ruby_http_parser/vendor/http-parser/test.c +2964 -460
- data/http_parser.rb.gemspec +14 -7
- data/spec/parser_spec.rb +196 -102
- data/spec/support/requests.json +236 -24
- data/spec/support/responses.json +202 -36
- data/tasks/compile.rake +2 -2
- data/tasks/fixtures.rake +8 -2
- data/tasks/spec.rake +1 -1
- metadata +141 -134
- data/Gemfile.lock +0 -32
- 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
- data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
@@ -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
|
};
|
@@ -32,7 +32,7 @@
|
|
32
32
|
#define FALSE 0
|
33
33
|
|
34
34
|
#define MAX_HEADERS 13
|
35
|
-
#define MAX_ELEMENT_SIZE
|
35
|
+
#define MAX_ELEMENT_SIZE 2048
|
36
36
|
|
37
37
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
38
38
|
|
@@ -50,12 +50,15 @@ struct message {
|
|
50
50
|
char query_string[MAX_ELEMENT_SIZE];
|
51
51
|
char body[MAX_ELEMENT_SIZE];
|
52
52
|
size_t body_size;
|
53
|
+
const char *host;
|
54
|
+
const char *userinfo;
|
55
|
+
uint16_t port;
|
53
56
|
int num_headers;
|
54
57
|
enum { NONE=0, FIELD, VALUE } last_header_element;
|
55
58
|
char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
|
56
59
|
int should_keep_alive;
|
57
60
|
|
58
|
-
|
61
|
+
const char *upgrade; // upgraded body
|
59
62
|
|
60
63
|
unsigned short http_major;
|
61
64
|
unsigned short http_minor;
|
@@ -64,12 +67,14 @@ struct message {
|
|
64
67
|
int headers_complete_cb_called;
|
65
68
|
int message_complete_cb_called;
|
66
69
|
int message_complete_on_eof;
|
70
|
+
int body_is_final;
|
67
71
|
};
|
68
72
|
|
69
73
|
static int currently_parsing_eof;
|
70
74
|
|
71
75
|
static struct message messages[5];
|
72
76
|
static int num_messages;
|
77
|
+
static http_parser_settings *current_pause_parser;
|
73
78
|
|
74
79
|
/* * R E Q U E S T S * */
|
75
80
|
const struct message requests[] =
|
@@ -473,6 +478,7 @@ const struct message requests[] =
|
|
473
478
|
"Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
|
474
479
|
"Origin: http://example.com\r\n"
|
475
480
|
"\r\n"
|
481
|
+
"Hot diggity dogg"
|
476
482
|
,.should_keep_alive= TRUE
|
477
483
|
,.message_complete_on_eof= FALSE
|
478
484
|
,.http_major= 1
|
@@ -483,7 +489,7 @@ const struct message requests[] =
|
|
483
489
|
,.request_path= "/demo"
|
484
490
|
,.request_url= "/demo"
|
485
491
|
,.num_headers= 7
|
486
|
-
,.upgrade=
|
492
|
+
,.upgrade="Hot diggity dogg"
|
487
493
|
,.headers= { { "Host", "example.com" }
|
488
494
|
, { "Connection", "Upgrade" }
|
489
495
|
, { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
|
@@ -498,10 +504,12 @@ const struct message requests[] =
|
|
498
504
|
#define CONNECT_REQUEST 17
|
499
505
|
, {.name = "connect request"
|
500
506
|
,.type= HTTP_REQUEST
|
501
|
-
,.raw= "CONNECT home0.netscape.com:443 HTTP/1.0\r\n"
|
507
|
+
,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
|
502
508
|
"User-agent: Mozilla/1.1N\r\n"
|
503
509
|
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
504
510
|
"\r\n"
|
511
|
+
"some data\r\n"
|
512
|
+
"and yet even more data"
|
505
513
|
,.should_keep_alive= FALSE
|
506
514
|
,.message_complete_on_eof= FALSE
|
507
515
|
,.http_major= 1
|
@@ -510,9 +518,9 @@ const struct message requests[] =
|
|
510
518
|
,.query_string= ""
|
511
519
|
,.fragment= ""
|
512
520
|
,.request_path= ""
|
513
|
-
,.request_url= "home0.netscape.com:443"
|
521
|
+
,.request_url= "0-home0.netscape.com:443"
|
514
522
|
,.num_headers= 2
|
515
|
-
,.upgrade=
|
523
|
+
,.upgrade="some data\r\nand yet even more data"
|
516
524
|
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
517
525
|
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
518
526
|
}
|
@@ -582,27 +590,35 @@ const struct message requests[] =
|
|
582
590
|
,.body= ""
|
583
591
|
}
|
584
592
|
|
585
|
-
#define
|
586
|
-
, {.name= "
|
593
|
+
#define LINE_FOLDING_IN_HEADER 21
|
594
|
+
, {.name= "line folding in header value"
|
587
595
|
,.type= HTTP_REQUEST
|
588
|
-
,.raw= "GET
|
589
|
-
"
|
596
|
+
,.raw= "GET / HTTP/1.1\r\n"
|
597
|
+
"Line1: abc\r\n"
|
598
|
+
"\tdef\r\n"
|
599
|
+
" ghi\r\n"
|
600
|
+
"\t\tjkl\r\n"
|
601
|
+
" mno \r\n"
|
602
|
+
"\t \tqrs\r\n"
|
603
|
+
"Line2: \t line2\t\r\n"
|
590
604
|
"\r\n"
|
591
605
|
,.should_keep_alive= TRUE
|
592
606
|
,.message_complete_on_eof= FALSE
|
593
607
|
,.http_major= 1
|
594
608
|
,.http_minor= 1
|
595
609
|
,.method= HTTP_GET
|
596
|
-
,.query_string= "
|
597
|
-
,.fragment= "
|
598
|
-
,.request_path= "
|
599
|
-
,.request_url= "
|
600
|
-
,.num_headers=
|
601
|
-
,.headers= { {"
|
610
|
+
,.query_string= ""
|
611
|
+
,.fragment= ""
|
612
|
+
,.request_path= "/"
|
613
|
+
,.request_url= "/"
|
614
|
+
,.num_headers= 2
|
615
|
+
,.headers= { { "Line1", "abcdefghijklmno qrs" }
|
616
|
+
, { "Line2", "line2\t" }
|
602
617
|
}
|
603
618
|
,.body= ""
|
604
619
|
}
|
605
620
|
|
621
|
+
|
606
622
|
#define QUERY_TERMINATED_HOST 22
|
607
623
|
, {.name= "host terminated by a query string"
|
608
624
|
,.type= HTTP_REQUEST
|
@@ -617,6 +633,7 @@ const struct message requests[] =
|
|
617
633
|
,.fragment= ""
|
618
634
|
,.request_path= ""
|
619
635
|
,.request_url= "http://hypnotoad.org?hail=all"
|
636
|
+
,.host= "hypnotoad.org"
|
620
637
|
,.num_headers= 0
|
621
638
|
,.headers= { }
|
622
639
|
,.body= ""
|
@@ -636,6 +653,8 @@ const struct message requests[] =
|
|
636
653
|
,.fragment= ""
|
637
654
|
,.request_path= ""
|
638
655
|
,.request_url= "http://hypnotoad.org:1234?hail=all"
|
656
|
+
,.host= "hypnotoad.org"
|
657
|
+
,.port= 1234
|
639
658
|
,.num_headers= 0
|
640
659
|
,.headers= { }
|
641
660
|
,.body= ""
|
@@ -655,11 +674,230 @@ const struct message requests[] =
|
|
655
674
|
,.fragment= ""
|
656
675
|
,.request_path= ""
|
657
676
|
,.request_url= "http://hypnotoad.org:1234"
|
677
|
+
,.host= "hypnotoad.org"
|
678
|
+
,.port= 1234
|
679
|
+
,.num_headers= 0
|
680
|
+
,.headers= { }
|
681
|
+
,.body= ""
|
682
|
+
}
|
683
|
+
|
684
|
+
#define PATCH_REQ 25
|
685
|
+
, {.name = "PATCH request"
|
686
|
+
,.type= HTTP_REQUEST
|
687
|
+
,.raw= "PATCH /file.txt HTTP/1.1\r\n"
|
688
|
+
"Host: www.example.com\r\n"
|
689
|
+
"Content-Type: application/example\r\n"
|
690
|
+
"If-Match: \"e0023aa4e\"\r\n"
|
691
|
+
"Content-Length: 10\r\n"
|
692
|
+
"\r\n"
|
693
|
+
"cccccccccc"
|
694
|
+
,.should_keep_alive= TRUE
|
695
|
+
,.message_complete_on_eof= FALSE
|
696
|
+
,.http_major= 1
|
697
|
+
,.http_minor= 1
|
698
|
+
,.method= HTTP_PATCH
|
699
|
+
,.query_string= ""
|
700
|
+
,.fragment= ""
|
701
|
+
,.request_path= "/file.txt"
|
702
|
+
,.request_url= "/file.txt"
|
703
|
+
,.num_headers= 4
|
704
|
+
,.headers= { { "Host", "www.example.com" }
|
705
|
+
, { "Content-Type", "application/example" }
|
706
|
+
, { "If-Match", "\"e0023aa4e\"" }
|
707
|
+
, { "Content-Length", "10" }
|
708
|
+
}
|
709
|
+
,.body= "cccccccccc"
|
710
|
+
}
|
711
|
+
|
712
|
+
#define CONNECT_CAPS_REQUEST 26
|
713
|
+
, {.name = "connect caps request"
|
714
|
+
,.type= HTTP_REQUEST
|
715
|
+
,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
|
716
|
+
"User-agent: Mozilla/1.1N\r\n"
|
717
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
718
|
+
"\r\n"
|
719
|
+
,.should_keep_alive= FALSE
|
720
|
+
,.message_complete_on_eof= FALSE
|
721
|
+
,.http_major= 1
|
722
|
+
,.http_minor= 0
|
723
|
+
,.method= HTTP_CONNECT
|
724
|
+
,.query_string= ""
|
725
|
+
,.fragment= ""
|
726
|
+
,.request_path= ""
|
727
|
+
,.request_url= "HOME0.NETSCAPE.COM:443"
|
728
|
+
,.num_headers= 2
|
729
|
+
,.upgrade=""
|
730
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
731
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
732
|
+
}
|
733
|
+
,.body= ""
|
734
|
+
}
|
735
|
+
|
736
|
+
#if !HTTP_PARSER_STRICT
|
737
|
+
#define UTF8_PATH_REQ 27
|
738
|
+
, {.name= "utf-8 path request"
|
739
|
+
,.type= HTTP_REQUEST
|
740
|
+
,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
|
741
|
+
"Host: github.com\r\n"
|
742
|
+
"\r\n"
|
743
|
+
,.should_keep_alive= TRUE
|
744
|
+
,.message_complete_on_eof= FALSE
|
745
|
+
,.http_major= 1
|
746
|
+
,.http_minor= 1
|
747
|
+
,.method= HTTP_GET
|
748
|
+
,.query_string= "q=1"
|
749
|
+
,.fragment= "narf"
|
750
|
+
,.request_path= "/δ¶/δt/pope"
|
751
|
+
,.request_url= "/δ¶/δt/pope?q=1#narf"
|
752
|
+
,.num_headers= 1
|
753
|
+
,.headers= { {"Host", "github.com" }
|
754
|
+
}
|
755
|
+
,.body= ""
|
756
|
+
}
|
757
|
+
|
758
|
+
#define HOSTNAME_UNDERSCORE 28
|
759
|
+
, {.name = "hostname underscore"
|
760
|
+
,.type= HTTP_REQUEST
|
761
|
+
,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
|
762
|
+
"User-agent: Mozilla/1.1N\r\n"
|
763
|
+
"Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
|
764
|
+
"\r\n"
|
765
|
+
,.should_keep_alive= FALSE
|
766
|
+
,.message_complete_on_eof= FALSE
|
767
|
+
,.http_major= 1
|
768
|
+
,.http_minor= 0
|
769
|
+
,.method= HTTP_CONNECT
|
770
|
+
,.query_string= ""
|
771
|
+
,.fragment= ""
|
772
|
+
,.request_path= ""
|
773
|
+
,.request_url= "home_0.netscape.com:443"
|
774
|
+
,.num_headers= 2
|
775
|
+
,.upgrade=""
|
776
|
+
,.headers= { { "User-agent", "Mozilla/1.1N" }
|
777
|
+
, { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
|
778
|
+
}
|
779
|
+
,.body= ""
|
780
|
+
}
|
781
|
+
#endif /* !HTTP_PARSER_STRICT */
|
782
|
+
|
783
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
784
|
+
#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
|
785
|
+
, {.name = "eat CRLF between requests, no \"Connection: close\" header"
|
786
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
787
|
+
"Host: www.example.com\r\n"
|
788
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
789
|
+
"Content-Length: 4\r\n"
|
790
|
+
"\r\n"
|
791
|
+
"q=42\r\n" /* note the trailing CRLF */
|
792
|
+
,.should_keep_alive= TRUE
|
793
|
+
,.message_complete_on_eof= FALSE
|
794
|
+
,.http_major= 1
|
795
|
+
,.http_minor= 1
|
796
|
+
,.method= HTTP_POST
|
797
|
+
,.query_string= ""
|
798
|
+
,.fragment= ""
|
799
|
+
,.request_path= "/"
|
800
|
+
,.request_url= "/"
|
801
|
+
,.num_headers= 3
|
802
|
+
,.upgrade= 0
|
803
|
+
,.headers= { { "Host", "www.example.com" }
|
804
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
805
|
+
, { "Content-Length", "4" }
|
806
|
+
}
|
807
|
+
,.body= "q=42"
|
808
|
+
}
|
809
|
+
|
810
|
+
/* see https://github.com/ry/http-parser/issues/47 */
|
811
|
+
#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
|
812
|
+
, {.name = "eat CRLF between requests even if \"Connection: close\" is set"
|
813
|
+
,.raw= "POST / HTTP/1.1\r\n"
|
814
|
+
"Host: www.example.com\r\n"
|
815
|
+
"Content-Type: application/x-www-form-urlencoded\r\n"
|
816
|
+
"Content-Length: 4\r\n"
|
817
|
+
"Connection: close\r\n"
|
818
|
+
"\r\n"
|
819
|
+
"q=42\r\n" /* note the trailing CRLF */
|
820
|
+
,.should_keep_alive= FALSE
|
821
|
+
,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */
|
822
|
+
,.http_major= 1
|
823
|
+
,.http_minor= 1
|
824
|
+
,.method= HTTP_POST
|
825
|
+
,.query_string= ""
|
826
|
+
,.fragment= ""
|
827
|
+
,.request_path= "/"
|
828
|
+
,.request_url= "/"
|
829
|
+
,.num_headers= 4
|
830
|
+
,.upgrade= 0
|
831
|
+
,.headers= { { "Host", "www.example.com" }
|
832
|
+
, { "Content-Type", "application/x-www-form-urlencoded" }
|
833
|
+
, { "Content-Length", "4" }
|
834
|
+
, { "Connection", "close" }
|
835
|
+
}
|
836
|
+
,.body= "q=42"
|
837
|
+
}
|
838
|
+
|
839
|
+
#define PURGE_REQ 31
|
840
|
+
, {.name = "PURGE request"
|
841
|
+
,.type= HTTP_REQUEST
|
842
|
+
,.raw= "PURGE /file.txt HTTP/1.1\r\n"
|
843
|
+
"Host: www.example.com\r\n"
|
844
|
+
"\r\n"
|
845
|
+
,.should_keep_alive= TRUE
|
846
|
+
,.message_complete_on_eof= FALSE
|
847
|
+
,.http_major= 1
|
848
|
+
,.http_minor= 1
|
849
|
+
,.method= HTTP_PURGE
|
850
|
+
,.query_string= ""
|
851
|
+
,.fragment= ""
|
852
|
+
,.request_path= "/file.txt"
|
853
|
+
,.request_url= "/file.txt"
|
854
|
+
,.num_headers= 1
|
855
|
+
,.headers= { { "Host", "www.example.com" } }
|
856
|
+
,.body= ""
|
857
|
+
}
|
858
|
+
|
859
|
+
#define SEARCH_REQ 32
|
860
|
+
, {.name = "SEARCH request"
|
861
|
+
,.type= HTTP_REQUEST
|
862
|
+
,.raw= "SEARCH / HTTP/1.1\r\n"
|
863
|
+
"Host: www.example.com\r\n"
|
864
|
+
"\r\n"
|
865
|
+
,.should_keep_alive= TRUE
|
866
|
+
,.message_complete_on_eof= FALSE
|
867
|
+
,.http_major= 1
|
868
|
+
,.http_minor= 1
|
869
|
+
,.method= HTTP_SEARCH
|
870
|
+
,.query_string= ""
|
871
|
+
,.fragment= ""
|
872
|
+
,.request_path= "/"
|
873
|
+
,.request_url= "/"
|
874
|
+
,.num_headers= 1
|
875
|
+
,.headers= { { "Host", "www.example.com" } }
|
876
|
+
,.body= ""
|
877
|
+
}
|
878
|
+
|
879
|
+
#define PROXY_WITH_BASIC_AUTH 33
|
880
|
+
, {.name= "host:port and basic_auth"
|
881
|
+
,.type= HTTP_REQUEST
|
882
|
+
,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
|
883
|
+
"\r\n"
|
884
|
+
,.should_keep_alive= TRUE
|
885
|
+
,.message_complete_on_eof= FALSE
|
886
|
+
,.http_major= 1
|
887
|
+
,.http_minor= 1
|
888
|
+
,.method= HTTP_GET
|
889
|
+
,.fragment= ""
|
890
|
+
,.request_path= "/toto"
|
891
|
+
,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
|
892
|
+
,.host= "hypnotoad.org"
|
893
|
+
,.userinfo= "a%12:b!&*$"
|
894
|
+
,.port= 1234
|
658
895
|
,.num_headers= 0
|
659
896
|
,.headers= { }
|
660
897
|
,.body= ""
|
661
898
|
}
|
662
899
|
|
900
|
+
|
663
901
|
, {.name= NULL } /* sentinel */
|
664
902
|
};
|
665
903
|
|
@@ -760,8 +998,8 @@ const struct message responses[] =
|
|
760
998
|
, {.name= "404 no headers no body"
|
761
999
|
,.type= HTTP_RESPONSE
|
762
1000
|
,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
|
763
|
-
,.should_keep_alive=
|
764
|
-
,.message_complete_on_eof=
|
1001
|
+
,.should_keep_alive= FALSE
|
1002
|
+
,.message_complete_on_eof= TRUE
|
765
1003
|
,.http_major= 1
|
766
1004
|
,.http_minor= 1
|
767
1005
|
,.status_code= 404
|
@@ -775,8 +1013,8 @@ const struct message responses[] =
|
|
775
1013
|
, {.name= "301 no response phrase"
|
776
1014
|
,.type= HTTP_RESPONSE
|
777
1015
|
,.raw= "HTTP/1.1 301\r\n\r\n"
|
778
|
-
,.should_keep_alive =
|
779
|
-
,.message_complete_on_eof=
|
1016
|
+
,.should_keep_alive = FALSE
|
1017
|
+
,.message_complete_on_eof= TRUE
|
780
1018
|
,.http_major= 1
|
781
1019
|
,.http_minor= 1
|
782
1020
|
,.status_code= 301
|
@@ -925,40 +1163,7 @@ const struct message responses[] =
|
|
925
1163
|
,.body= ""
|
926
1164
|
}
|
927
1165
|
|
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
|
1166
|
+
#define RES_FIELD_UNDERSCORE 9
|
962
1167
|
/* Should handle spaces in header fields */
|
963
1168
|
, {.name= "field underscore"
|
964
1169
|
,.type= HTTP_RESPONSE
|
@@ -998,7 +1203,7 @@ const struct message responses[] =
|
|
998
1203
|
,.body= ""
|
999
1204
|
}
|
1000
1205
|
|
1001
|
-
#define NON_ASCII_IN_STATUS_LINE
|
1206
|
+
#define NON_ASCII_IN_STATUS_LINE 10
|
1002
1207
|
/* Should handle non-ASCII in status line */
|
1003
1208
|
, {.name= "non-ASCII in status line"
|
1004
1209
|
,.type= HTTP_RESPONSE
|
@@ -1021,39 +1226,275 @@ const struct message responses[] =
|
|
1021
1226
|
,.body= ""
|
1022
1227
|
}
|
1023
1228
|
|
1229
|
+
#define HTTP_VERSION_0_9 11
|
1230
|
+
/* Should handle HTTP/0.9 */
|
1231
|
+
, {.name= "http version 0.9"
|
1232
|
+
,.type= HTTP_RESPONSE
|
1233
|
+
,.raw= "HTTP/0.9 200 OK\r\n"
|
1234
|
+
"\r\n"
|
1235
|
+
,.should_keep_alive= FALSE
|
1236
|
+
,.message_complete_on_eof= TRUE
|
1237
|
+
,.http_major= 0
|
1238
|
+
,.http_minor= 9
|
1239
|
+
,.status_code= 200
|
1240
|
+
,.num_headers= 0
|
1241
|
+
,.headers=
|
1242
|
+
{}
|
1243
|
+
,.body= ""
|
1244
|
+
}
|
1245
|
+
|
1246
|
+
#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12
|
1247
|
+
/* The client should wait for the server's EOF. That is, when neither
|
1248
|
+
* content-length nor transfer-encoding is specified, the end of body
|
1249
|
+
* is specified by the EOF.
|
1250
|
+
*/
|
1251
|
+
, {.name= "neither content-length nor transfer-encoding response"
|
1252
|
+
,.type= HTTP_RESPONSE
|
1253
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1254
|
+
"Content-Type: text/plain\r\n"
|
1255
|
+
"\r\n"
|
1256
|
+
"hello world"
|
1257
|
+
,.should_keep_alive= FALSE
|
1258
|
+
,.message_complete_on_eof= TRUE
|
1259
|
+
,.http_major= 1
|
1260
|
+
,.http_minor= 1
|
1261
|
+
,.status_code= 200
|
1262
|
+
,.num_headers= 1
|
1263
|
+
,.headers=
|
1264
|
+
{ { "Content-Type", "text/plain" }
|
1265
|
+
}
|
1266
|
+
,.body= "hello world"
|
1267
|
+
}
|
1268
|
+
|
1269
|
+
#define NO_BODY_HTTP10_KA_200 13
|
1270
|
+
, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status"
|
1271
|
+
,.type= HTTP_RESPONSE
|
1272
|
+
,.raw= "HTTP/1.0 200 OK\r\n"
|
1273
|
+
"Connection: keep-alive\r\n"
|
1274
|
+
"\r\n"
|
1275
|
+
,.should_keep_alive= FALSE
|
1276
|
+
,.message_complete_on_eof= TRUE
|
1277
|
+
,.http_major= 1
|
1278
|
+
,.http_minor= 0
|
1279
|
+
,.status_code= 200
|
1280
|
+
,.num_headers= 1
|
1281
|
+
,.headers=
|
1282
|
+
{ { "Connection", "keep-alive" }
|
1283
|
+
}
|
1284
|
+
,.body_size= 0
|
1285
|
+
,.body= ""
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
#define NO_BODY_HTTP10_KA_204 14
|
1289
|
+
, {.name= "HTTP/1.0 with keep-alive and a 204 status"
|
1290
|
+
,.type= HTTP_RESPONSE
|
1291
|
+
,.raw= "HTTP/1.0 204 No content\r\n"
|
1292
|
+
"Connection: keep-alive\r\n"
|
1293
|
+
"\r\n"
|
1294
|
+
,.should_keep_alive= TRUE
|
1295
|
+
,.message_complete_on_eof= FALSE
|
1296
|
+
,.http_major= 1
|
1297
|
+
,.http_minor= 0
|
1298
|
+
,.status_code= 204
|
1299
|
+
,.num_headers= 1
|
1300
|
+
,.headers=
|
1301
|
+
{ { "Connection", "keep-alive" }
|
1302
|
+
}
|
1303
|
+
,.body_size= 0
|
1304
|
+
,.body= ""
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
#define NO_BODY_HTTP11_KA_200 15
|
1308
|
+
, {.name= "HTTP/1.1 with an EOF-terminated 200 status"
|
1309
|
+
,.type= HTTP_RESPONSE
|
1310
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1311
|
+
"\r\n"
|
1312
|
+
,.should_keep_alive= FALSE
|
1313
|
+
,.message_complete_on_eof= TRUE
|
1314
|
+
,.http_major= 1
|
1315
|
+
,.http_minor= 1
|
1316
|
+
,.status_code= 200
|
1317
|
+
,.num_headers= 0
|
1318
|
+
,.headers={}
|
1319
|
+
,.body_size= 0
|
1320
|
+
,.body= ""
|
1321
|
+
}
|
1322
|
+
|
1323
|
+
#define NO_BODY_HTTP11_KA_204 16
|
1324
|
+
, {.name= "HTTP/1.1 with a 204 status"
|
1325
|
+
,.type= HTTP_RESPONSE
|
1326
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
1327
|
+
"\r\n"
|
1328
|
+
,.should_keep_alive= TRUE
|
1329
|
+
,.message_complete_on_eof= FALSE
|
1330
|
+
,.http_major= 1
|
1331
|
+
,.http_minor= 1
|
1332
|
+
,.status_code= 204
|
1333
|
+
,.num_headers= 0
|
1334
|
+
,.headers={}
|
1335
|
+
,.body_size= 0
|
1336
|
+
,.body= ""
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
#define NO_BODY_HTTP11_NOKA_204 17
|
1340
|
+
, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled"
|
1341
|
+
,.type= HTTP_RESPONSE
|
1342
|
+
,.raw= "HTTP/1.1 204 No content\r\n"
|
1343
|
+
"Connection: close\r\n"
|
1344
|
+
"\r\n"
|
1345
|
+
,.should_keep_alive= FALSE
|
1346
|
+
,.message_complete_on_eof= FALSE
|
1347
|
+
,.http_major= 1
|
1348
|
+
,.http_minor= 1
|
1349
|
+
,.status_code= 204
|
1350
|
+
,.num_headers= 1
|
1351
|
+
,.headers=
|
1352
|
+
{ { "Connection", "close" }
|
1353
|
+
}
|
1354
|
+
,.body_size= 0
|
1355
|
+
,.body= ""
|
1356
|
+
}
|
1357
|
+
|
1358
|
+
#define NO_BODY_HTTP11_KA_CHUNKED_200 18
|
1359
|
+
, {.name= "HTTP/1.1 with chunked endocing and a 200 response"
|
1360
|
+
,.type= HTTP_RESPONSE
|
1361
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1362
|
+
"Transfer-Encoding: chunked\r\n"
|
1363
|
+
"\r\n"
|
1364
|
+
"0\r\n"
|
1365
|
+
"\r\n"
|
1366
|
+
,.should_keep_alive= TRUE
|
1367
|
+
,.message_complete_on_eof= FALSE
|
1368
|
+
,.http_major= 1
|
1369
|
+
,.http_minor= 1
|
1370
|
+
,.status_code= 200
|
1371
|
+
,.num_headers= 1
|
1372
|
+
,.headers=
|
1373
|
+
{ { "Transfer-Encoding", "chunked" }
|
1374
|
+
}
|
1375
|
+
,.body_size= 0
|
1376
|
+
,.body= ""
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
#if !HTTP_PARSER_STRICT
|
1380
|
+
#define SPACE_IN_FIELD_RES 19
|
1381
|
+
/* Should handle spaces in header fields */
|
1382
|
+
, {.name= "field space"
|
1383
|
+
,.type= HTTP_RESPONSE
|
1384
|
+
,.raw= "HTTP/1.1 200 OK\r\n"
|
1385
|
+
"Server: Microsoft-IIS/6.0\r\n"
|
1386
|
+
"X-Powered-By: ASP.NET\r\n"
|
1387
|
+
"en-US Content-Type: text/xml\r\n" /* this is the problem */
|
1388
|
+
"Content-Type: text/xml\r\n"
|
1389
|
+
"Content-Length: 16\r\n"
|
1390
|
+
"Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n"
|
1391
|
+
"Connection: keep-alive\r\n"
|
1392
|
+
"\r\n"
|
1393
|
+
"<xml>hello</xml>" /* fake body */
|
1394
|
+
,.should_keep_alive= TRUE
|
1395
|
+
,.message_complete_on_eof= FALSE
|
1396
|
+
,.http_major= 1
|
1397
|
+
,.http_minor= 1
|
1398
|
+
,.status_code= 200
|
1399
|
+
,.num_headers= 7
|
1400
|
+
,.headers=
|
1401
|
+
{ { "Server", "Microsoft-IIS/6.0" }
|
1402
|
+
, { "X-Powered-By", "ASP.NET" }
|
1403
|
+
, { "en-US Content-Type", "text/xml" }
|
1404
|
+
, { "Content-Type", "text/xml" }
|
1405
|
+
, { "Content-Length", "16" }
|
1406
|
+
, { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" }
|
1407
|
+
, { "Connection", "keep-alive" }
|
1408
|
+
}
|
1409
|
+
,.body= "<xml>hello</xml>"
|
1410
|
+
}
|
1411
|
+
#endif /* !HTTP_PARSER_STRICT */
|
1024
1412
|
|
1025
1413
|
, {.name= NULL } /* sentinel */
|
1026
1414
|
};
|
1027
1415
|
|
1028
|
-
|
1029
|
-
|
1416
|
+
/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
|
1417
|
+
* define it ourselves.
|
1418
|
+
*/
|
1419
|
+
size_t
|
1420
|
+
strnlen(const char *s, size_t maxlen)
|
1030
1421
|
{
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1422
|
+
const char *p;
|
1423
|
+
|
1424
|
+
p = memchr(s, '\0', maxlen);
|
1425
|
+
if (p == NULL)
|
1426
|
+
return maxlen;
|
1427
|
+
|
1428
|
+
return p - s;
|
1034
1429
|
}
|
1035
1430
|
|
1036
|
-
|
1037
|
-
|
1431
|
+
size_t
|
1432
|
+
strlncat(char *dst, size_t len, const char *src, size_t n)
|
1038
1433
|
{
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1434
|
+
size_t slen;
|
1435
|
+
size_t dlen;
|
1436
|
+
size_t rlen;
|
1437
|
+
size_t ncpy;
|
1438
|
+
|
1439
|
+
slen = strnlen(src, n);
|
1440
|
+
dlen = strnlen(dst, len);
|
1441
|
+
|
1442
|
+
if (dlen < len) {
|
1443
|
+
rlen = len - dlen;
|
1444
|
+
ncpy = slen < rlen ? slen : (rlen - 1);
|
1445
|
+
memcpy(dst + dlen, src, ncpy);
|
1446
|
+
dst[dlen + ncpy] = '\0';
|
1447
|
+
}
|
1448
|
+
|
1449
|
+
assert(len > slen + dlen);
|
1450
|
+
return slen + dlen;
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
size_t
|
1454
|
+
strlcat(char *dst, const char *src, size_t len)
|
1455
|
+
{
|
1456
|
+
return strlncat(dst, len, src, (size_t) -1);
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
size_t
|
1460
|
+
strlncpy(char *dst, size_t len, const char *src, size_t n)
|
1461
|
+
{
|
1462
|
+
size_t slen;
|
1463
|
+
size_t ncpy;
|
1464
|
+
|
1465
|
+
slen = strnlen(src, n);
|
1466
|
+
|
1467
|
+
if (len > 0) {
|
1468
|
+
ncpy = slen < len ? slen : (len - 1);
|
1469
|
+
memcpy(dst, src, ncpy);
|
1470
|
+
dst[ncpy] = '\0';
|
1471
|
+
}
|
1472
|
+
|
1473
|
+
assert(len > slen);
|
1474
|
+
return slen;
|
1475
|
+
}
|
1476
|
+
|
1477
|
+
size_t
|
1478
|
+
strlcpy(char *dst, const char *src, size_t len)
|
1479
|
+
{
|
1480
|
+
return strlncpy(dst, len, src, (size_t) -1);
|
1042
1481
|
}
|
1043
1482
|
|
1044
1483
|
int
|
1045
|
-
|
1484
|
+
request_url_cb (http_parser *p, const char *buf, size_t len)
|
1046
1485
|
{
|
1047
1486
|
assert(p == parser);
|
1048
|
-
|
1487
|
+
strlncat(messages[num_messages].request_url,
|
1488
|
+
sizeof(messages[num_messages].request_url),
|
1489
|
+
buf,
|
1490
|
+
len);
|
1049
1491
|
return 0;
|
1050
1492
|
}
|
1051
1493
|
|
1052
1494
|
int
|
1053
|
-
|
1054
|
-
{
|
1495
|
+
status_complete_cb (http_parser *p) {
|
1055
1496
|
assert(p == parser);
|
1056
|
-
|
1497
|
+
p->data++;
|
1057
1498
|
return 0;
|
1058
1499
|
}
|
1059
1500
|
|
@@ -1066,7 +1507,10 @@ header_field_cb (http_parser *p, const char *buf, size_t len)
|
|
1066
1507
|
if (m->last_header_element != FIELD)
|
1067
1508
|
m->num_headers++;
|
1068
1509
|
|
1069
|
-
|
1510
|
+
strlncat(m->headers[m->num_headers-1][0],
|
1511
|
+
sizeof(m->headers[m->num_headers-1][0]),
|
1512
|
+
buf,
|
1513
|
+
len);
|
1070
1514
|
|
1071
1515
|
m->last_header_element = FIELD;
|
1072
1516
|
|
@@ -1079,19 +1523,39 @@ header_value_cb (http_parser *p, const char *buf, size_t len)
|
|
1079
1523
|
assert(p == parser);
|
1080
1524
|
struct message *m = &messages[num_messages];
|
1081
1525
|
|
1082
|
-
|
1526
|
+
strlncat(m->headers[m->num_headers-1][1],
|
1527
|
+
sizeof(m->headers[m->num_headers-1][1]),
|
1528
|
+
buf,
|
1529
|
+
len);
|
1083
1530
|
|
1084
1531
|
m->last_header_element = VALUE;
|
1085
1532
|
|
1086
1533
|
return 0;
|
1087
1534
|
}
|
1088
1535
|
|
1536
|
+
void
|
1537
|
+
check_body_is_final (const http_parser *p)
|
1538
|
+
{
|
1539
|
+
if (messages[num_messages].body_is_final) {
|
1540
|
+
fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
|
1541
|
+
"on last on_body callback call "
|
1542
|
+
"but it doesn't! ***\n\n");
|
1543
|
+
assert(0);
|
1544
|
+
abort();
|
1545
|
+
}
|
1546
|
+
messages[num_messages].body_is_final = http_body_is_final(p);
|
1547
|
+
}
|
1548
|
+
|
1089
1549
|
int
|
1090
1550
|
body_cb (http_parser *p, const char *buf, size_t len)
|
1091
1551
|
{
|
1092
1552
|
assert(p == parser);
|
1093
|
-
|
1553
|
+
strlncat(messages[num_messages].body,
|
1554
|
+
sizeof(messages[num_messages].body),
|
1555
|
+
buf,
|
1556
|
+
len);
|
1094
1557
|
messages[num_messages].body_size += len;
|
1558
|
+
check_body_is_final(p);
|
1095
1559
|
// printf("body_cb: '%s'\n", requests[num_messages].body);
|
1096
1560
|
return 0;
|
1097
1561
|
}
|
@@ -1102,6 +1566,7 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
|
|
1102
1566
|
assert(p == parser);
|
1103
1567
|
assert(buf);
|
1104
1568
|
messages[num_messages].body_size += len;
|
1569
|
+
check_body_is_final(p);
|
1105
1570
|
return 0;
|
1106
1571
|
}
|
1107
1572
|
|
@@ -1127,33 +1592,182 @@ headers_complete_cb (http_parser *p)
|
|
1127
1592
|
}
|
1128
1593
|
|
1129
1594
|
int
|
1130
|
-
message_complete_cb (http_parser *p)
|
1595
|
+
message_complete_cb (http_parser *p)
|
1596
|
+
{
|
1597
|
+
assert(p == parser);
|
1598
|
+
if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
|
1599
|
+
{
|
1600
|
+
fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
|
1601
|
+
"value in both on_message_complete and on_headers_complete "
|
1602
|
+
"but it doesn't! ***\n\n");
|
1603
|
+
assert(0);
|
1604
|
+
abort();
|
1605
|
+
}
|
1606
|
+
|
1607
|
+
if (messages[num_messages].body_size &&
|
1608
|
+
http_body_is_final(p) &&
|
1609
|
+
!messages[num_messages].body_is_final)
|
1610
|
+
{
|
1611
|
+
fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
|
1612
|
+
"on last on_body callback call "
|
1613
|
+
"but it doesn't! ***\n\n");
|
1614
|
+
assert(0);
|
1615
|
+
abort();
|
1616
|
+
}
|
1617
|
+
|
1618
|
+
messages[num_messages].message_complete_cb_called = TRUE;
|
1619
|
+
|
1620
|
+
messages[num_messages].message_complete_on_eof = currently_parsing_eof;
|
1621
|
+
|
1622
|
+
num_messages++;
|
1623
|
+
return 0;
|
1624
|
+
}
|
1625
|
+
|
1626
|
+
/* These dontcall_* callbacks exist so that we can verify that when we're
|
1627
|
+
* paused, no additional callbacks are invoked */
|
1628
|
+
int
|
1629
|
+
dontcall_message_begin_cb (http_parser *p)
|
1630
|
+
{
|
1631
|
+
if (p) { } // gcc
|
1632
|
+
fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n");
|
1633
|
+
abort();
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
int
|
1637
|
+
dontcall_header_field_cb (http_parser *p, const char *buf, size_t len)
|
1638
|
+
{
|
1639
|
+
if (p || buf || len) { } // gcc
|
1640
|
+
fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n");
|
1641
|
+
abort();
|
1642
|
+
}
|
1643
|
+
|
1644
|
+
int
|
1645
|
+
dontcall_header_value_cb (http_parser *p, const char *buf, size_t len)
|
1646
|
+
{
|
1647
|
+
if (p || buf || len) { } // gcc
|
1648
|
+
fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n");
|
1649
|
+
abort();
|
1650
|
+
}
|
1651
|
+
|
1652
|
+
int
|
1653
|
+
dontcall_request_url_cb (http_parser *p, const char *buf, size_t len)
|
1654
|
+
{
|
1655
|
+
if (p || buf || len) { } // gcc
|
1656
|
+
fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n");
|
1657
|
+
abort();
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
int
|
1661
|
+
dontcall_body_cb (http_parser *p, const char *buf, size_t len)
|
1662
|
+
{
|
1663
|
+
if (p || buf || len) { } // gcc
|
1664
|
+
fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n");
|
1665
|
+
abort();
|
1666
|
+
}
|
1667
|
+
|
1668
|
+
int
|
1669
|
+
dontcall_headers_complete_cb (http_parser *p)
|
1670
|
+
{
|
1671
|
+
if (p) { } // gcc
|
1672
|
+
fprintf(stderr, "\n\n*** on_headers_complete() called on paused "
|
1673
|
+
"parser ***\n\n");
|
1674
|
+
abort();
|
1675
|
+
}
|
1676
|
+
|
1677
|
+
int
|
1678
|
+
dontcall_message_complete_cb (http_parser *p)
|
1679
|
+
{
|
1680
|
+
if (p) { } // gcc
|
1681
|
+
fprintf(stderr, "\n\n*** on_message_complete() called on paused "
|
1682
|
+
"parser ***\n\n");
|
1683
|
+
abort();
|
1684
|
+
}
|
1685
|
+
|
1686
|
+
static http_parser_settings settings_dontcall =
|
1687
|
+
{.on_message_begin = dontcall_message_begin_cb
|
1688
|
+
,.on_header_field = dontcall_header_field_cb
|
1689
|
+
,.on_header_value = dontcall_header_value_cb
|
1690
|
+
,.on_url = dontcall_request_url_cb
|
1691
|
+
,.on_body = dontcall_body_cb
|
1692
|
+
,.on_headers_complete = dontcall_headers_complete_cb
|
1693
|
+
,.on_message_complete = dontcall_message_complete_cb
|
1694
|
+
};
|
1695
|
+
|
1696
|
+
/* These pause_* callbacks always pause the parser and just invoke the regular
|
1697
|
+
* callback that tracks content. Before returning, we overwrite the parser
|
1698
|
+
* settings to point to the _dontcall variety so that we can verify that
|
1699
|
+
* the pause actually did, you know, pause. */
|
1700
|
+
int
|
1701
|
+
pause_message_begin_cb (http_parser *p)
|
1702
|
+
{
|
1703
|
+
http_parser_pause(p, 1);
|
1704
|
+
*current_pause_parser = settings_dontcall;
|
1705
|
+
return message_begin_cb(p);
|
1706
|
+
}
|
1707
|
+
|
1708
|
+
int
|
1709
|
+
pause_header_field_cb (http_parser *p, const char *buf, size_t len)
|
1710
|
+
{
|
1711
|
+
http_parser_pause(p, 1);
|
1712
|
+
*current_pause_parser = settings_dontcall;
|
1713
|
+
return header_field_cb(p, buf, len);
|
1714
|
+
}
|
1715
|
+
|
1716
|
+
int
|
1717
|
+
pause_header_value_cb (http_parser *p, const char *buf, size_t len)
|
1718
|
+
{
|
1719
|
+
http_parser_pause(p, 1);
|
1720
|
+
*current_pause_parser = settings_dontcall;
|
1721
|
+
return header_value_cb(p, buf, len);
|
1722
|
+
}
|
1723
|
+
|
1724
|
+
int
|
1725
|
+
pause_request_url_cb (http_parser *p, const char *buf, size_t len)
|
1726
|
+
{
|
1727
|
+
http_parser_pause(p, 1);
|
1728
|
+
*current_pause_parser = settings_dontcall;
|
1729
|
+
return request_url_cb(p, buf, len);
|
1730
|
+
}
|
1731
|
+
|
1732
|
+
int
|
1733
|
+
pause_body_cb (http_parser *p, const char *buf, size_t len)
|
1131
1734
|
{
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
"value in both on_message_complete and on_headers_complete "
|
1137
|
-
"but it doesn't! ***\n\n");
|
1138
|
-
assert(0);
|
1139
|
-
exit(1);
|
1140
|
-
}
|
1141
|
-
messages[num_messages].message_complete_cb_called = TRUE;
|
1735
|
+
http_parser_pause(p, 1);
|
1736
|
+
*current_pause_parser = settings_dontcall;
|
1737
|
+
return body_cb(p, buf, len);
|
1738
|
+
}
|
1142
1739
|
|
1143
|
-
|
1740
|
+
int
|
1741
|
+
pause_headers_complete_cb (http_parser *p)
|
1742
|
+
{
|
1743
|
+
http_parser_pause(p, 1);
|
1744
|
+
*current_pause_parser = settings_dontcall;
|
1745
|
+
return headers_complete_cb(p);
|
1746
|
+
}
|
1144
1747
|
|
1145
|
-
|
1146
|
-
|
1748
|
+
int
|
1749
|
+
pause_message_complete_cb (http_parser *p)
|
1750
|
+
{
|
1751
|
+
http_parser_pause(p, 1);
|
1752
|
+
*current_pause_parser = settings_dontcall;
|
1753
|
+
return message_complete_cb(p);
|
1147
1754
|
}
|
1148
1755
|
|
1756
|
+
static http_parser_settings settings_pause =
|
1757
|
+
{.on_message_begin = pause_message_begin_cb
|
1758
|
+
,.on_header_field = pause_header_field_cb
|
1759
|
+
,.on_header_value = pause_header_value_cb
|
1760
|
+
,.on_url = pause_request_url_cb
|
1761
|
+
,.on_body = pause_body_cb
|
1762
|
+
,.on_headers_complete = pause_headers_complete_cb
|
1763
|
+
,.on_message_complete = pause_message_complete_cb
|
1764
|
+
};
|
1765
|
+
|
1149
1766
|
static http_parser_settings settings =
|
1150
1767
|
{.on_message_begin = message_begin_cb
|
1151
1768
|
,.on_header_field = header_field_cb
|
1152
1769
|
,.on_header_value = header_value_cb
|
1153
|
-
,.on_path = request_path_cb
|
1154
1770
|
,.on_url = request_url_cb
|
1155
|
-
,.on_fragment = fragment_cb
|
1156
|
-
,.on_query_string = query_string_cb
|
1157
1771
|
,.on_body = body_cb
|
1158
1772
|
,.on_headers_complete = headers_complete_cb
|
1159
1773
|
,.on_message_complete = message_complete_cb
|
@@ -1163,10 +1777,7 @@ static http_parser_settings settings_count_body =
|
|
1163
1777
|
{.on_message_begin = message_begin_cb
|
1164
1778
|
,.on_header_field = header_field_cb
|
1165
1779
|
,.on_header_value = header_value_cb
|
1166
|
-
,.on_path = request_path_cb
|
1167
1780
|
,.on_url = request_url_cb
|
1168
|
-
,.on_fragment = fragment_cb
|
1169
|
-
,.on_query_string = query_string_cb
|
1170
1781
|
,.on_body = count_body_cb
|
1171
1782
|
,.on_headers_complete = headers_complete_cb
|
1172
1783
|
,.on_message_complete = message_complete_cb
|
@@ -1176,10 +1787,7 @@ static http_parser_settings settings_null =
|
|
1176
1787
|
{.on_message_begin = 0
|
1177
1788
|
,.on_header_field = 0
|
1178
1789
|
,.on_header_value = 0
|
1179
|
-
,.on_path = 0
|
1180
1790
|
,.on_url = 0
|
1181
|
-
,.on_fragment = 0
|
1182
|
-
,.on_query_string = 0
|
1183
1791
|
,.on_body = 0
|
1184
1792
|
,.on_headers_complete = 0
|
1185
1793
|
,.on_message_complete = 0
|
@@ -1224,12 +1832,29 @@ size_t parse_count_body (const char *buf, size_t len)
|
|
1224
1832
|
return nparsed;
|
1225
1833
|
}
|
1226
1834
|
|
1835
|
+
size_t parse_pause (const char *buf, size_t len)
|
1836
|
+
{
|
1837
|
+
size_t nparsed;
|
1838
|
+
http_parser_settings s = settings_pause;
|
1839
|
+
|
1840
|
+
currently_parsing_eof = (len == 0);
|
1841
|
+
current_pause_parser = &s;
|
1842
|
+
nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
|
1843
|
+
return nparsed;
|
1844
|
+
}
|
1845
|
+
|
1227
1846
|
static inline int
|
1228
1847
|
check_str_eq (const struct message *m,
|
1229
1848
|
const char *prop,
|
1230
1849
|
const char *expected,
|
1231
1850
|
const char *found) {
|
1232
|
-
if (
|
1851
|
+
if ((expected == NULL) != (found == NULL)) {
|
1852
|
+
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
1853
|
+
printf("expected %s\n", (expected == NULL) ? "NULL" : expected);
|
1854
|
+
printf(" found %s\n", (found == NULL) ? "NULL" : found);
|
1855
|
+
return 0;
|
1856
|
+
}
|
1857
|
+
if (expected != NULL && 0 != strcmp(expected, found)) {
|
1233
1858
|
printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
|
1234
1859
|
printf("expected '%s'\n", expected);
|
1235
1860
|
printf(" found '%s'\n", found);
|
@@ -1258,6 +1883,20 @@ check_num_eq (const struct message *m,
|
|
1258
1883
|
#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
|
1259
1884
|
if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
|
1260
1885
|
|
1886
|
+
#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \
|
1887
|
+
do { \
|
1888
|
+
char ubuf[256]; \
|
1889
|
+
\
|
1890
|
+
if ((u)->field_set & (1 << (fn))) { \
|
1891
|
+
memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \
|
1892
|
+
(u)->field_data[(fn)].len); \
|
1893
|
+
ubuf[(u)->field_data[(fn)].len] = '\0'; \
|
1894
|
+
} else { \
|
1895
|
+
ubuf[0] = '\0'; \
|
1896
|
+
} \
|
1897
|
+
\
|
1898
|
+
check_str_eq(expected, #prop, expected->prop, ubuf); \
|
1899
|
+
} while(0)
|
1261
1900
|
|
1262
1901
|
int
|
1263
1902
|
message_eq (int index, const struct message *expected)
|
@@ -1282,10 +1921,37 @@ message_eq (int index, const struct message *expected)
|
|
1282
1921
|
assert(m->message_complete_cb_called);
|
1283
1922
|
|
1284
1923
|
|
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
1924
|
MESSAGE_CHECK_STR_EQ(expected, m, request_url);
|
1925
|
+
|
1926
|
+
/* Check URL components; we can't do this w/ CONNECT since it doesn't
|
1927
|
+
* send us a well-formed URL.
|
1928
|
+
*/
|
1929
|
+
if (*m->request_url && m->method != HTTP_CONNECT) {
|
1930
|
+
struct http_parser_url u;
|
1931
|
+
|
1932
|
+
if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) {
|
1933
|
+
fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n",
|
1934
|
+
m->request_url);
|
1935
|
+
abort();
|
1936
|
+
}
|
1937
|
+
|
1938
|
+
if (expected->host) {
|
1939
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
|
1940
|
+
}
|
1941
|
+
|
1942
|
+
if (expected->userinfo) {
|
1943
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
|
1944
|
+
}
|
1945
|
+
|
1946
|
+
m->port = (u.field_set & (1 << UF_PORT)) ?
|
1947
|
+
u.port : 0;
|
1948
|
+
|
1949
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY);
|
1950
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT);
|
1951
|
+
MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH);
|
1952
|
+
MESSAGE_CHECK_NUM_EQ(expected, m, port);
|
1953
|
+
}
|
1954
|
+
|
1289
1955
|
if (expected->body_size) {
|
1290
1956
|
MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
|
1291
1957
|
} else {
|
@@ -1302,13 +1968,80 @@ message_eq (int index, const struct message *expected)
|
|
1302
1968
|
if (!r) return 0;
|
1303
1969
|
}
|
1304
1970
|
|
1971
|
+
MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
|
1972
|
+
|
1305
1973
|
return 1;
|
1306
1974
|
}
|
1307
1975
|
|
1976
|
+
/* Given a sequence of varargs messages, return the number of them that the
|
1977
|
+
* parser should successfully parse, taking into account that upgraded
|
1978
|
+
* messages prevent all subsequent messages from being parsed.
|
1979
|
+
*/
|
1980
|
+
size_t
|
1981
|
+
count_parsed_messages(const size_t nmsgs, ...) {
|
1982
|
+
size_t i;
|
1983
|
+
va_list ap;
|
1984
|
+
|
1985
|
+
va_start(ap, nmsgs);
|
1986
|
+
|
1987
|
+
for (i = 0; i < nmsgs; i++) {
|
1988
|
+
struct message *m = va_arg(ap, struct message *);
|
1989
|
+
|
1990
|
+
if (m->upgrade) {
|
1991
|
+
va_end(ap);
|
1992
|
+
return i + 1;
|
1993
|
+
}
|
1994
|
+
}
|
1995
|
+
|
1996
|
+
va_end(ap);
|
1997
|
+
return nmsgs;
|
1998
|
+
}
|
1999
|
+
|
2000
|
+
/* Given a sequence of bytes and the number of these that we were able to
|
2001
|
+
* parse, verify that upgrade bodies are correct.
|
2002
|
+
*/
|
2003
|
+
void
|
2004
|
+
upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
|
2005
|
+
va_list ap;
|
2006
|
+
size_t i;
|
2007
|
+
size_t off = 0;
|
2008
|
+
|
2009
|
+
va_start(ap, nmsgs);
|
2010
|
+
|
2011
|
+
for (i = 0; i < nmsgs; i++) {
|
2012
|
+
struct message *m = va_arg(ap, struct message *);
|
2013
|
+
|
2014
|
+
off += strlen(m->raw);
|
2015
|
+
|
2016
|
+
if (m->upgrade) {
|
2017
|
+
off -= strlen(m->upgrade);
|
2018
|
+
|
2019
|
+
/* Check the portion of the response after its specified upgrade */
|
2020
|
+
if (!check_str_eq(m, "upgrade", body + off, body + nread)) {
|
2021
|
+
abort();
|
2022
|
+
}
|
2023
|
+
|
2024
|
+
/* Fix up the response so that message_eq() will verify the beginning
|
2025
|
+
* of the upgrade */
|
2026
|
+
*(body + nread + strlen(m->upgrade)) = '\0';
|
2027
|
+
messages[num_messages -1 ].upgrade = body + nread;
|
2028
|
+
|
2029
|
+
va_end(ap);
|
2030
|
+
return;
|
2031
|
+
}
|
2032
|
+
}
|
2033
|
+
|
2034
|
+
va_end(ap);
|
2035
|
+
printf("\n\n*** Error: expected a message with upgrade ***\n");
|
2036
|
+
|
2037
|
+
abort();
|
2038
|
+
}
|
2039
|
+
|
1308
2040
|
static void
|
1309
2041
|
print_error (const char *raw, size_t error_location)
|
1310
2042
|
{
|
1311
|
-
fprintf(stderr, "\n***
|
2043
|
+
fprintf(stderr, "\n*** %s ***\n\n",
|
2044
|
+
http_errno_description(HTTP_PARSER_ERRNO(parser)));
|
1312
2045
|
|
1313
2046
|
int this_line = 0, char_len = 0;
|
1314
2047
|
size_t i, j, len = strlen(raw), error_location_line = 0;
|
@@ -1346,6 +2079,582 @@ print_error (const char *raw, size_t error_location)
|
|
1346
2079
|
fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
|
1347
2080
|
}
|
1348
2081
|
|
2082
|
+
void
|
2083
|
+
test_preserve_data (void)
|
2084
|
+
{
|
2085
|
+
char my_data[] = "application-specific data";
|
2086
|
+
http_parser parser;
|
2087
|
+
parser.data = my_data;
|
2088
|
+
http_parser_init(&parser, HTTP_REQUEST);
|
2089
|
+
if (parser.data != my_data) {
|
2090
|
+
printf("\n*** parser.data not preserved accross http_parser_init ***\n\n");
|
2091
|
+
abort();
|
2092
|
+
}
|
2093
|
+
}
|
2094
|
+
|
2095
|
+
struct url_test {
|
2096
|
+
const char *name;
|
2097
|
+
const char *url;
|
2098
|
+
int is_connect;
|
2099
|
+
struct http_parser_url u;
|
2100
|
+
int rv;
|
2101
|
+
};
|
2102
|
+
|
2103
|
+
const struct url_test url_tests[] =
|
2104
|
+
{ {.name="proxy request"
|
2105
|
+
,.url="http://hostname/"
|
2106
|
+
,.is_connect=0
|
2107
|
+
,.u=
|
2108
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
2109
|
+
,.port=0
|
2110
|
+
,.field_data=
|
2111
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2112
|
+
,{ 7, 8 } /* UF_HOST */
|
2113
|
+
,{ 0, 0 } /* UF_PORT */
|
2114
|
+
,{ 15, 1 } /* UF_PATH */
|
2115
|
+
,{ 0, 0 } /* UF_QUERY */
|
2116
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2117
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2118
|
+
}
|
2119
|
+
}
|
2120
|
+
,.rv=0
|
2121
|
+
}
|
2122
|
+
|
2123
|
+
, {.name="proxy request with port"
|
2124
|
+
,.url="http://hostname:444/"
|
2125
|
+
,.is_connect=0
|
2126
|
+
,.u=
|
2127
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
|
2128
|
+
,.port=444
|
2129
|
+
,.field_data=
|
2130
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2131
|
+
,{ 7, 8 } /* UF_HOST */
|
2132
|
+
,{ 16, 3 } /* UF_PORT */
|
2133
|
+
,{ 19, 1 } /* UF_PATH */
|
2134
|
+
,{ 0, 0 } /* UF_QUERY */
|
2135
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2136
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2137
|
+
}
|
2138
|
+
}
|
2139
|
+
,.rv=0
|
2140
|
+
}
|
2141
|
+
|
2142
|
+
, {.name="CONNECT request"
|
2143
|
+
,.url="hostname:443"
|
2144
|
+
,.is_connect=1
|
2145
|
+
,.u=
|
2146
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
2147
|
+
,.port=443
|
2148
|
+
,.field_data=
|
2149
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2150
|
+
,{ 0, 8 } /* UF_HOST */
|
2151
|
+
,{ 9, 3 } /* UF_PORT */
|
2152
|
+
,{ 0, 0 } /* UF_PATH */
|
2153
|
+
,{ 0, 0 } /* UF_QUERY */
|
2154
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2155
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2156
|
+
}
|
2157
|
+
}
|
2158
|
+
,.rv=0
|
2159
|
+
}
|
2160
|
+
|
2161
|
+
, {.name="CONNECT request but not connect"
|
2162
|
+
,.url="hostname:443"
|
2163
|
+
,.is_connect=0
|
2164
|
+
,.rv=1
|
2165
|
+
}
|
2166
|
+
|
2167
|
+
, {.name="proxy ipv6 request"
|
2168
|
+
,.url="http://[1:2::3:4]/"
|
2169
|
+
,.is_connect=0
|
2170
|
+
,.u=
|
2171
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
2172
|
+
,.port=0
|
2173
|
+
,.field_data=
|
2174
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2175
|
+
,{ 8, 8 } /* UF_HOST */
|
2176
|
+
,{ 0, 0 } /* UF_PORT */
|
2177
|
+
,{ 17, 1 } /* UF_PATH */
|
2178
|
+
,{ 0, 0 } /* UF_QUERY */
|
2179
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2180
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2181
|
+
}
|
2182
|
+
}
|
2183
|
+
,.rv=0
|
2184
|
+
}
|
2185
|
+
|
2186
|
+
, {.name="proxy ipv6 request with port"
|
2187
|
+
,.url="http://[1:2::3:4]:67/"
|
2188
|
+
,.is_connect=0
|
2189
|
+
,.u=
|
2190
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
|
2191
|
+
,.port=67
|
2192
|
+
,.field_data=
|
2193
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2194
|
+
,{ 8, 8 } /* UF_HOST */
|
2195
|
+
,{ 18, 2 } /* UF_PORT */
|
2196
|
+
,{ 20, 1 } /* UF_PATH */
|
2197
|
+
,{ 0, 0 } /* UF_QUERY */
|
2198
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2199
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2200
|
+
}
|
2201
|
+
}
|
2202
|
+
,.rv=0
|
2203
|
+
}
|
2204
|
+
|
2205
|
+
, {.name="CONNECT ipv6 address"
|
2206
|
+
,.url="[1:2::3:4]:443"
|
2207
|
+
,.is_connect=1
|
2208
|
+
,.u=
|
2209
|
+
{.field_set=(1 << UF_HOST) | (1 << UF_PORT)
|
2210
|
+
,.port=443
|
2211
|
+
,.field_data=
|
2212
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2213
|
+
,{ 1, 8 } /* UF_HOST */
|
2214
|
+
,{ 11, 3 } /* UF_PORT */
|
2215
|
+
,{ 0, 0 } /* UF_PATH */
|
2216
|
+
,{ 0, 0 } /* UF_QUERY */
|
2217
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2218
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2219
|
+
}
|
2220
|
+
}
|
2221
|
+
,.rv=0
|
2222
|
+
}
|
2223
|
+
|
2224
|
+
, {.name="ipv4 in ipv6 address"
|
2225
|
+
,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
|
2226
|
+
,.is_connect=0
|
2227
|
+
,.u=
|
2228
|
+
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH)
|
2229
|
+
,.port=0
|
2230
|
+
,.field_data=
|
2231
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2232
|
+
,{ 8, 37 } /* UF_HOST */
|
2233
|
+
,{ 0, 0 } /* UF_PORT */
|
2234
|
+
,{ 46, 1 } /* UF_PATH */
|
2235
|
+
,{ 0, 0 } /* UF_QUERY */
|
2236
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2237
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2238
|
+
}
|
2239
|
+
}
|
2240
|
+
,.rv=0
|
2241
|
+
}
|
2242
|
+
|
2243
|
+
, {.name="extra ? in query string"
|
2244
|
+
,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,"
|
2245
|
+
"fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,"
|
2246
|
+
"fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
|
2247
|
+
,.is_connect=0
|
2248
|
+
,.u=
|
2249
|
+
{.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
|
2250
|
+
,.port=0
|
2251
|
+
,.field_data=
|
2252
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2253
|
+
,{ 7, 10 } /* UF_HOST */
|
2254
|
+
,{ 0, 0 } /* UF_PORT */
|
2255
|
+
,{ 17, 12 } /* UF_PATH */
|
2256
|
+
,{ 30,187 } /* UF_QUERY */
|
2257
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2258
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2259
|
+
}
|
2260
|
+
}
|
2261
|
+
,.rv=0
|
2262
|
+
}
|
2263
|
+
|
2264
|
+
, {.name="space URL encoded"
|
2265
|
+
,.url="/toto.html?toto=a%20b"
|
2266
|
+
,.is_connect=0
|
2267
|
+
,.u=
|
2268
|
+
{.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
|
2269
|
+
,.port=0
|
2270
|
+
,.field_data=
|
2271
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2272
|
+
,{ 0, 0 } /* UF_HOST */
|
2273
|
+
,{ 0, 0 } /* UF_PORT */
|
2274
|
+
,{ 0, 10 } /* UF_PATH */
|
2275
|
+
,{ 11, 10 } /* UF_QUERY */
|
2276
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2277
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2278
|
+
}
|
2279
|
+
}
|
2280
|
+
,.rv=0
|
2281
|
+
}
|
2282
|
+
|
2283
|
+
|
2284
|
+
, {.name="URL fragment"
|
2285
|
+
,.url="/toto.html#titi"
|
2286
|
+
,.is_connect=0
|
2287
|
+
,.u=
|
2288
|
+
{.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
|
2289
|
+
,.port=0
|
2290
|
+
,.field_data=
|
2291
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2292
|
+
,{ 0, 0 } /* UF_HOST */
|
2293
|
+
,{ 0, 0 } /* UF_PORT */
|
2294
|
+
,{ 0, 10 } /* UF_PATH */
|
2295
|
+
,{ 0, 0 } /* UF_QUERY */
|
2296
|
+
,{ 11, 4 } /* UF_FRAGMENT */
|
2297
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2298
|
+
}
|
2299
|
+
}
|
2300
|
+
,.rv=0
|
2301
|
+
}
|
2302
|
+
|
2303
|
+
, {.name="complex URL fragment"
|
2304
|
+
,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
|
2305
|
+
"http://www.example.com/index.html?foo=bar&hello=world#midpage"
|
2306
|
+
,.is_connect=0
|
2307
|
+
,.u=
|
2308
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
|
2309
|
+
(1<<UF_FRAGMENT)
|
2310
|
+
,.port=0
|
2311
|
+
,.field_data=
|
2312
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2313
|
+
,{ 7, 22 } /* UF_HOST */
|
2314
|
+
,{ 0, 0 } /* UF_PORT */
|
2315
|
+
,{ 29, 6 } /* UF_PATH */
|
2316
|
+
,{ 36, 69 } /* UF_QUERY */
|
2317
|
+
,{106, 7 } /* UF_FRAGMENT */
|
2318
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2319
|
+
}
|
2320
|
+
}
|
2321
|
+
,.rv=0
|
2322
|
+
}
|
2323
|
+
|
2324
|
+
, {.name="complex URL from node js url parser doc"
|
2325
|
+
,.url="http://host.com:8080/p/a/t/h?query=string#hash"
|
2326
|
+
,.is_connect=0
|
2327
|
+
,.u=
|
2328
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
|
2329
|
+
(1<<UF_QUERY) | (1<<UF_FRAGMENT)
|
2330
|
+
,.port=8080
|
2331
|
+
,.field_data=
|
2332
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2333
|
+
,{ 7, 8 } /* UF_HOST */
|
2334
|
+
,{ 16, 4 } /* UF_PORT */
|
2335
|
+
,{ 20, 8 } /* UF_PATH */
|
2336
|
+
,{ 29, 12 } /* UF_QUERY */
|
2337
|
+
,{ 42, 4 } /* UF_FRAGMENT */
|
2338
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2339
|
+
}
|
2340
|
+
}
|
2341
|
+
,.rv=0
|
2342
|
+
}
|
2343
|
+
|
2344
|
+
, {.name="complex URL with basic auth from node js url parser doc"
|
2345
|
+
,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
|
2346
|
+
,.is_connect=0
|
2347
|
+
,.u=
|
2348
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
|
2349
|
+
(1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
|
2350
|
+
,.port=8080
|
2351
|
+
,.field_data=
|
2352
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2353
|
+
,{ 11, 8 } /* UF_HOST */
|
2354
|
+
,{ 20, 4 } /* UF_PORT */
|
2355
|
+
,{ 24, 8 } /* UF_PATH */
|
2356
|
+
,{ 33, 12 } /* UF_QUERY */
|
2357
|
+
,{ 46, 4 } /* UF_FRAGMENT */
|
2358
|
+
,{ 7, 3 } /* UF_USERINFO */
|
2359
|
+
}
|
2360
|
+
}
|
2361
|
+
,.rv=0
|
2362
|
+
}
|
2363
|
+
|
2364
|
+
, {.name="double @"
|
2365
|
+
,.url="http://a:b@@hostname:443/"
|
2366
|
+
,.is_connect=0
|
2367
|
+
,.rv=1
|
2368
|
+
}
|
2369
|
+
|
2370
|
+
, {.name="proxy empty host"
|
2371
|
+
,.url="http://:443/"
|
2372
|
+
,.is_connect=0
|
2373
|
+
,.rv=1
|
2374
|
+
}
|
2375
|
+
|
2376
|
+
, {.name="proxy empty port"
|
2377
|
+
,.url="http://hostname:/"
|
2378
|
+
,.is_connect=0
|
2379
|
+
,.rv=1
|
2380
|
+
}
|
2381
|
+
|
2382
|
+
, {.name="CONNECT with basic auth"
|
2383
|
+
,.url="a:b@hostname:443"
|
2384
|
+
,.is_connect=1
|
2385
|
+
,.rv=1
|
2386
|
+
}
|
2387
|
+
|
2388
|
+
, {.name="CONNECT empty host"
|
2389
|
+
,.url=":443"
|
2390
|
+
,.is_connect=1
|
2391
|
+
,.rv=1
|
2392
|
+
}
|
2393
|
+
|
2394
|
+
, {.name="CONNECT empty port"
|
2395
|
+
,.url="hostname:"
|
2396
|
+
,.is_connect=1
|
2397
|
+
,.rv=1
|
2398
|
+
}
|
2399
|
+
|
2400
|
+
, {.name="CONNECT with extra bits"
|
2401
|
+
,.url="hostname:443/"
|
2402
|
+
,.is_connect=1
|
2403
|
+
,.rv=1
|
2404
|
+
}
|
2405
|
+
|
2406
|
+
, {.name="space in URL"
|
2407
|
+
,.url="/foo bar/"
|
2408
|
+
,.rv=1 /* s_dead */
|
2409
|
+
}
|
2410
|
+
|
2411
|
+
, {.name="proxy basic auth with space url encoded"
|
2412
|
+
,.url="http://a%20:b@host.com/"
|
2413
|
+
,.is_connect=0
|
2414
|
+
,.u=
|
2415
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
2416
|
+
,.port=0
|
2417
|
+
,.field_data=
|
2418
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2419
|
+
,{ 14, 8 } /* UF_HOST */
|
2420
|
+
,{ 0, 0 } /* UF_PORT */
|
2421
|
+
,{ 22, 1 } /* UF_PATH */
|
2422
|
+
,{ 0, 0 } /* UF_QUERY */
|
2423
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2424
|
+
,{ 7, 6 } /* UF_USERINFO */
|
2425
|
+
}
|
2426
|
+
}
|
2427
|
+
,.rv=0
|
2428
|
+
}
|
2429
|
+
|
2430
|
+
, {.name="carriage return in URL"
|
2431
|
+
,.url="/foo\rbar/"
|
2432
|
+
,.rv=1 /* s_dead */
|
2433
|
+
}
|
2434
|
+
|
2435
|
+
, {.name="proxy double : in URL"
|
2436
|
+
,.url="http://hostname::443/"
|
2437
|
+
,.rv=1 /* s_dead */
|
2438
|
+
}
|
2439
|
+
|
2440
|
+
, {.name="proxy basic auth with double :"
|
2441
|
+
,.url="http://a::b@host.com/"
|
2442
|
+
,.is_connect=0
|
2443
|
+
,.u=
|
2444
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
2445
|
+
,.port=0
|
2446
|
+
,.field_data=
|
2447
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2448
|
+
,{ 12, 8 } /* UF_HOST */
|
2449
|
+
,{ 0, 0 } /* UF_PORT */
|
2450
|
+
,{ 20, 1 } /* UF_PATH */
|
2451
|
+
,{ 0, 0 } /* UF_QUERY */
|
2452
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2453
|
+
,{ 7, 4 } /* UF_USERINFO */
|
2454
|
+
}
|
2455
|
+
}
|
2456
|
+
,.rv=0
|
2457
|
+
}
|
2458
|
+
|
2459
|
+
, {.name="line feed in URL"
|
2460
|
+
,.url="/foo\nbar/"
|
2461
|
+
,.rv=1 /* s_dead */
|
2462
|
+
}
|
2463
|
+
|
2464
|
+
, {.name="proxy empty basic auth"
|
2465
|
+
,.url="http://@hostname/fo"
|
2466
|
+
,.u=
|
2467
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
|
2468
|
+
,.port=0
|
2469
|
+
,.field_data=
|
2470
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2471
|
+
,{ 8, 8 } /* UF_HOST */
|
2472
|
+
,{ 0, 0 } /* UF_PORT */
|
2473
|
+
,{ 16, 3 } /* UF_PATH */
|
2474
|
+
,{ 0, 0 } /* UF_QUERY */
|
2475
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2476
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2477
|
+
}
|
2478
|
+
}
|
2479
|
+
,.rv=0
|
2480
|
+
}
|
2481
|
+
, {.name="proxy line feed in hostname"
|
2482
|
+
,.url="http://host\name/fo"
|
2483
|
+
,.rv=1 /* s_dead */
|
2484
|
+
}
|
2485
|
+
|
2486
|
+
, {.name="proxy % in hostname"
|
2487
|
+
,.url="http://host%name/fo"
|
2488
|
+
,.rv=1 /* s_dead */
|
2489
|
+
}
|
2490
|
+
|
2491
|
+
, {.name="proxy ; in hostname"
|
2492
|
+
,.url="http://host;ame/fo"
|
2493
|
+
,.rv=1 /* s_dead */
|
2494
|
+
}
|
2495
|
+
|
2496
|
+
, {.name="proxy basic auth with unreservedchars"
|
2497
|
+
,.url="http://a!;-_!=+$@host.com/"
|
2498
|
+
,.is_connect=0
|
2499
|
+
,.u=
|
2500
|
+
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
2501
|
+
,.port=0
|
2502
|
+
,.field_data=
|
2503
|
+
{{ 0, 4 } /* UF_SCHEMA */
|
2504
|
+
,{ 17, 8 } /* UF_HOST */
|
2505
|
+
,{ 0, 0 } /* UF_PORT */
|
2506
|
+
,{ 25, 1 } /* UF_PATH */
|
2507
|
+
,{ 0, 0 } /* UF_QUERY */
|
2508
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2509
|
+
,{ 7, 9 } /* UF_USERINFO */
|
2510
|
+
}
|
2511
|
+
}
|
2512
|
+
,.rv=0
|
2513
|
+
}
|
2514
|
+
|
2515
|
+
, {.name="proxy only empty basic auth"
|
2516
|
+
,.url="http://@/fo"
|
2517
|
+
,.rv=1 /* s_dead */
|
2518
|
+
}
|
2519
|
+
|
2520
|
+
, {.name="proxy only basic auth"
|
2521
|
+
,.url="http://toto@/fo"
|
2522
|
+
,.rv=1 /* s_dead */
|
2523
|
+
}
|
2524
|
+
|
2525
|
+
, {.name="proxy emtpy hostname"
|
2526
|
+
,.url="http:///fo"
|
2527
|
+
,.rv=1 /* s_dead */
|
2528
|
+
}
|
2529
|
+
|
2530
|
+
, {.name="proxy = in URL"
|
2531
|
+
,.url="http://host=ame/fo"
|
2532
|
+
,.rv=1 /* s_dead */
|
2533
|
+
}
|
2534
|
+
|
2535
|
+
#if HTTP_PARSER_STRICT
|
2536
|
+
|
2537
|
+
, {.name="tab in URL"
|
2538
|
+
,.url="/foo\tbar/"
|
2539
|
+
,.rv=1 /* s_dead */
|
2540
|
+
}
|
2541
|
+
|
2542
|
+
, {.name="form feed in URL"
|
2543
|
+
,.url="/foo\fbar/"
|
2544
|
+
,.rv=1 /* s_dead */
|
2545
|
+
}
|
2546
|
+
|
2547
|
+
#else /* !HTTP_PARSER_STRICT */
|
2548
|
+
|
2549
|
+
, {.name="tab in URL"
|
2550
|
+
,.url="/foo\tbar/"
|
2551
|
+
,.u=
|
2552
|
+
{.field_set=(1 << UF_PATH)
|
2553
|
+
,.field_data=
|
2554
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2555
|
+
,{ 0, 0 } /* UF_HOST */
|
2556
|
+
,{ 0, 0 } /* UF_PORT */
|
2557
|
+
,{ 0, 9 } /* UF_PATH */
|
2558
|
+
,{ 0, 0 } /* UF_QUERY */
|
2559
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2560
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2561
|
+
}
|
2562
|
+
}
|
2563
|
+
,.rv=0
|
2564
|
+
}
|
2565
|
+
|
2566
|
+
, {.name="form feed in URL"
|
2567
|
+
,.url="/foo\fbar/"
|
2568
|
+
,.u=
|
2569
|
+
{.field_set=(1 << UF_PATH)
|
2570
|
+
,.field_data=
|
2571
|
+
{{ 0, 0 } /* UF_SCHEMA */
|
2572
|
+
,{ 0, 0 } /* UF_HOST */
|
2573
|
+
,{ 0, 0 } /* UF_PORT */
|
2574
|
+
,{ 0, 9 } /* UF_PATH */
|
2575
|
+
,{ 0, 0 } /* UF_QUERY */
|
2576
|
+
,{ 0, 0 } /* UF_FRAGMENT */
|
2577
|
+
,{ 0, 0 } /* UF_USERINFO */
|
2578
|
+
}
|
2579
|
+
}
|
2580
|
+
,.rv=0
|
2581
|
+
}
|
2582
|
+
#endif
|
2583
|
+
};
|
2584
|
+
|
2585
|
+
void
|
2586
|
+
dump_url (const char *url, const struct http_parser_url *u)
|
2587
|
+
{
|
2588
|
+
unsigned int i;
|
2589
|
+
|
2590
|
+
printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
|
2591
|
+
for (i = 0; i < UF_MAX; i++) {
|
2592
|
+
if ((u->field_set & (1 << i)) == 0) {
|
2593
|
+
printf("\tfield_data[%u]: unset\n", i);
|
2594
|
+
continue;
|
2595
|
+
}
|
2596
|
+
|
2597
|
+
printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
|
2598
|
+
i,
|
2599
|
+
u->field_data[i].off,
|
2600
|
+
u->field_data[i].len,
|
2601
|
+
u->field_data[i].len,
|
2602
|
+
url + u->field_data[i].off);
|
2603
|
+
}
|
2604
|
+
}
|
2605
|
+
|
2606
|
+
void
|
2607
|
+
test_parse_url (void)
|
2608
|
+
{
|
2609
|
+
struct http_parser_url u;
|
2610
|
+
const struct url_test *test;
|
2611
|
+
unsigned int i;
|
2612
|
+
int rv;
|
2613
|
+
|
2614
|
+
for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) {
|
2615
|
+
test = &url_tests[i];
|
2616
|
+
memset(&u, 0, sizeof(u));
|
2617
|
+
|
2618
|
+
rv = http_parser_parse_url(test->url,
|
2619
|
+
strlen(test->url),
|
2620
|
+
test->is_connect,
|
2621
|
+
&u);
|
2622
|
+
|
2623
|
+
if (test->rv == 0) {
|
2624
|
+
if (rv != 0) {
|
2625
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
2626
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
2627
|
+
abort();
|
2628
|
+
}
|
2629
|
+
|
2630
|
+
if (memcmp(&u, &test->u, sizeof(u)) != 0) {
|
2631
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n",
|
2632
|
+
test->url, test->name);
|
2633
|
+
|
2634
|
+
printf("target http_parser_url:\n");
|
2635
|
+
dump_url(test->url, &test->u);
|
2636
|
+
printf("result http_parser_url:\n");
|
2637
|
+
dump_url(test->url, &u);
|
2638
|
+
|
2639
|
+
abort();
|
2640
|
+
}
|
2641
|
+
} else {
|
2642
|
+
/* test->rv != 0 */
|
2643
|
+
if (rv == 0) {
|
2644
|
+
printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, "
|
2645
|
+
"unexpected rv %d ***\n\n", test->url, test->name, rv);
|
2646
|
+
abort();
|
2647
|
+
}
|
2648
|
+
}
|
2649
|
+
}
|
2650
|
+
}
|
2651
|
+
|
2652
|
+
void
|
2653
|
+
test_method_str (void)
|
2654
|
+
{
|
2655
|
+
assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
|
2656
|
+
assert(0 == strcmp("<unknown>", http_method_str(1337)));
|
2657
|
+
}
|
1349
2658
|
|
1350
2659
|
void
|
1351
2660
|
test_message (const struct message *message)
|
@@ -1363,41 +2672,45 @@ test_message (const struct message *message)
|
|
1363
2672
|
if (msg1len) {
|
1364
2673
|
read = parse(msg1, msg1len);
|
1365
2674
|
|
1366
|
-
if (message->upgrade && parser->upgrade)
|
2675
|
+
if (message->upgrade && parser->upgrade) {
|
2676
|
+
messages[num_messages - 1].upgrade = msg1 + read;
|
2677
|
+
goto test;
|
2678
|
+
}
|
1367
2679
|
|
1368
2680
|
if (read != msg1len) {
|
1369
2681
|
print_error(msg1, read);
|
1370
|
-
|
2682
|
+
abort();
|
1371
2683
|
}
|
1372
2684
|
}
|
1373
2685
|
|
1374
2686
|
|
1375
2687
|
read = parse(msg2, msg2len);
|
1376
2688
|
|
1377
|
-
if (message->upgrade && parser->upgrade)
|
2689
|
+
if (message->upgrade && parser->upgrade) {
|
2690
|
+
messages[num_messages - 1].upgrade = msg2 + read;
|
2691
|
+
goto test;
|
2692
|
+
}
|
1378
2693
|
|
1379
2694
|
if (read != msg2len) {
|
1380
2695
|
print_error(msg2, read);
|
1381
|
-
|
2696
|
+
abort();
|
1382
2697
|
}
|
1383
2698
|
|
1384
2699
|
read = parse(NULL, 0);
|
1385
2700
|
|
1386
|
-
if (message->upgrade && parser->upgrade) goto test;
|
1387
|
-
|
1388
2701
|
if (read != 0) {
|
1389
2702
|
print_error(message->raw, read);
|
1390
|
-
|
2703
|
+
abort();
|
1391
2704
|
}
|
1392
2705
|
|
1393
2706
|
test:
|
1394
2707
|
|
1395
2708
|
if (num_messages != 1) {
|
1396
2709
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
1397
|
-
|
2710
|
+
abort();
|
1398
2711
|
}
|
1399
2712
|
|
1400
|
-
if(!message_eq(0, message))
|
2713
|
+
if(!message_eq(0, message)) abort();
|
1401
2714
|
|
1402
2715
|
parser_free();
|
1403
2716
|
}
|
@@ -1418,7 +2731,7 @@ test_message_count_body (const struct message *message)
|
|
1418
2731
|
read = parse_count_body(message->raw + i, toread);
|
1419
2732
|
if (read != toread) {
|
1420
2733
|
print_error(message->raw, read);
|
1421
|
-
|
2734
|
+
abort();
|
1422
2735
|
}
|
1423
2736
|
}
|
1424
2737
|
|
@@ -1426,36 +2739,47 @@ test_message_count_body (const struct message *message)
|
|
1426
2739
|
read = parse_count_body(NULL, 0);
|
1427
2740
|
if (read != 0) {
|
1428
2741
|
print_error(message->raw, read);
|
1429
|
-
|
2742
|
+
abort();
|
1430
2743
|
}
|
1431
2744
|
|
1432
2745
|
if (num_messages != 1) {
|
1433
2746
|
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
|
1434
|
-
|
2747
|
+
abort();
|
1435
2748
|
}
|
1436
2749
|
|
1437
|
-
if(!message_eq(0, message))
|
2750
|
+
if(!message_eq(0, message)) abort();
|
1438
2751
|
|
1439
2752
|
parser_free();
|
1440
2753
|
}
|
1441
2754
|
|
1442
2755
|
void
|
1443
|
-
test_simple (const char *buf,
|
2756
|
+
test_simple (const char *buf, enum http_errno err_expected)
|
1444
2757
|
{
|
1445
2758
|
parser_init(HTTP_REQUEST);
|
1446
2759
|
|
1447
2760
|
size_t parsed;
|
1448
2761
|
int pass;
|
2762
|
+
enum http_errno err;
|
2763
|
+
|
1449
2764
|
parsed = parse(buf, strlen(buf));
|
1450
2765
|
pass = (parsed == strlen(buf));
|
2766
|
+
err = HTTP_PARSER_ERRNO(parser);
|
1451
2767
|
parsed = parse(NULL, 0);
|
1452
2768
|
pass &= (parsed == 0);
|
1453
2769
|
|
1454
2770
|
parser_free();
|
1455
2771
|
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
2772
|
+
/* In strict mode, allow us to pass with an unexpected HPE_STRICT as
|
2773
|
+
* long as the caller isn't expecting success.
|
2774
|
+
*/
|
2775
|
+
#if HTTP_PARSER_STRICT
|
2776
|
+
if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) {
|
2777
|
+
#else
|
2778
|
+
if (err_expected != err) {
|
2779
|
+
#endif
|
2780
|
+
fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n",
|
2781
|
+
http_errno_name(err_expected), http_errno_name(err), buf);
|
2782
|
+
abort();
|
1459
2783
|
}
|
1460
2784
|
}
|
1461
2785
|
|
@@ -1471,16 +2795,67 @@ test_header_overflow_error (int req)
|
|
1471
2795
|
assert(parsed == strlen(buf));
|
1472
2796
|
|
1473
2797
|
buf = "header-key: header-value\r\n";
|
2798
|
+
size_t buflen = strlen(buf);
|
2799
|
+
|
1474
2800
|
int i;
|
1475
2801
|
for (i = 0; i < 10000; i++) {
|
1476
|
-
|
2802
|
+
parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
|
2803
|
+
if (parsed != buflen) {
|
1477
2804
|
//fprintf(stderr, "error found on iter %d\n", i);
|
2805
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
|
1478
2806
|
return;
|
1479
2807
|
}
|
1480
2808
|
}
|
1481
2809
|
|
1482
2810
|
fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
|
1483
|
-
|
2811
|
+
abort();
|
2812
|
+
}
|
2813
|
+
|
2814
|
+
static void
|
2815
|
+
test_content_length_overflow (const char *buf, size_t buflen, int expect_ok)
|
2816
|
+
{
|
2817
|
+
http_parser parser;
|
2818
|
+
http_parser_init(&parser, HTTP_RESPONSE);
|
2819
|
+
http_parser_execute(&parser, &settings_null, buf, buflen);
|
2820
|
+
|
2821
|
+
if (expect_ok)
|
2822
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK);
|
2823
|
+
else
|
2824
|
+
assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH);
|
2825
|
+
}
|
2826
|
+
|
2827
|
+
void
|
2828
|
+
test_header_content_length_overflow_error (void)
|
2829
|
+
{
|
2830
|
+
#define X(size) \
|
2831
|
+
"HTTP/1.1 200 OK\r\n" \
|
2832
|
+
"Content-Length: " #size "\r\n" \
|
2833
|
+
"\r\n"
|
2834
|
+
const char a[] = X(18446744073709551614); /* 2^64-2 */
|
2835
|
+
const char b[] = X(18446744073709551615); /* 2^64-1 */
|
2836
|
+
const char c[] = X(18446744073709551616); /* 2^64 */
|
2837
|
+
#undef X
|
2838
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
2839
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
2840
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
2841
|
+
}
|
2842
|
+
|
2843
|
+
void
|
2844
|
+
test_chunk_content_length_overflow_error (void)
|
2845
|
+
{
|
2846
|
+
#define X(size) \
|
2847
|
+
"HTTP/1.1 200 OK\r\n" \
|
2848
|
+
"Transfer-Encoding: chunked\r\n" \
|
2849
|
+
"\r\n" \
|
2850
|
+
#size "\r\n" \
|
2851
|
+
"..."
|
2852
|
+
const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
|
2853
|
+
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
|
2854
|
+
const char c[] = X(10000000000000000); /* 2^64 */
|
2855
|
+
#undef X
|
2856
|
+
test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */
|
2857
|
+
test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */
|
2858
|
+
test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */
|
1484
2859
|
}
|
1485
2860
|
|
1486
2861
|
void
|
@@ -1491,8 +2866,8 @@ test_no_overflow_long_body (int req, size_t length)
|
|
1491
2866
|
size_t parsed;
|
1492
2867
|
size_t i;
|
1493
2868
|
char buf1[3000];
|
1494
|
-
size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %
|
1495
|
-
req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", length);
|
2869
|
+
size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n",
|
2870
|
+
req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length);
|
1496
2871
|
parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
|
1497
2872
|
if (parsed != buf1len)
|
1498
2873
|
goto err;
|
@@ -1510,21 +2885,16 @@ test_no_overflow_long_body (int req, size_t length)
|
|
1510
2885
|
|
1511
2886
|
err:
|
1512
2887
|
fprintf(stderr,
|
1513
|
-
"\n*** error in test_no_overflow_long_body %s of length %
|
2888
|
+
"\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
|
1514
2889
|
req ? "REQUEST" : "RESPONSE",
|
1515
|
-
length);
|
1516
|
-
|
2890
|
+
(unsigned long)length);
|
2891
|
+
abort();
|
1517
2892
|
}
|
1518
2893
|
|
1519
2894
|
void
|
1520
2895
|
test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
|
1521
2896
|
{
|
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);
|
2897
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
1528
2898
|
|
1529
2899
|
char total[ strlen(r1->raw)
|
1530
2900
|
+ strlen(r2->raw)
|
@@ -1543,36 +2913,33 @@ test_multiple3 (const struct message *r1, const struct message *r2, const struct
|
|
1543
2913
|
|
1544
2914
|
read = parse(total, strlen(total));
|
1545
2915
|
|
1546
|
-
if (
|
2916
|
+
if (parser->upgrade) {
|
2917
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
2918
|
+
goto test;
|
2919
|
+
}
|
1547
2920
|
|
1548
2921
|
if (read != strlen(total)) {
|
1549
2922
|
print_error(total, read);
|
1550
|
-
|
2923
|
+
abort();
|
1551
2924
|
}
|
1552
2925
|
|
1553
2926
|
read = parse(NULL, 0);
|
1554
2927
|
|
1555
|
-
if (has_upgrade && parser->upgrade) goto test;
|
1556
|
-
|
1557
2928
|
if (read != 0) {
|
1558
2929
|
print_error(total, read);
|
1559
|
-
|
2930
|
+
abort();
|
1560
2931
|
}
|
1561
2932
|
|
1562
2933
|
test:
|
1563
2934
|
|
1564
2935
|
if (message_count != num_messages) {
|
1565
2936
|
fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
|
1566
|
-
|
2937
|
+
abort();
|
1567
2938
|
}
|
1568
2939
|
|
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
|
-
}
|
2940
|
+
if (!message_eq(0, r1)) abort();
|
2941
|
+
if (message_count > 1 && !message_eq(1, r2)) abort();
|
2942
|
+
if (message_count > 2 && !message_eq(2, r3)) abort();
|
1576
2943
|
|
1577
2944
|
parser_free();
|
1578
2945
|
}
|
@@ -1601,6 +2968,7 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1601
2968
|
int ops = 0 ;
|
1602
2969
|
|
1603
2970
|
size_t buf1_len, buf2_len, buf3_len;
|
2971
|
+
int message_count = count_parsed_messages(3, r1, r2, r3);
|
1604
2972
|
|
1605
2973
|
int i,j,type_both;
|
1606
2974
|
for (type_both = 0; type_both < 2; type_both ++ ) {
|
@@ -1616,40 +2984,40 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1616
2984
|
parser_init(type_both ? HTTP_BOTH : r1->type);
|
1617
2985
|
|
1618
2986
|
buf1_len = i;
|
1619
|
-
|
2987
|
+
strlncpy(buf1, sizeof(buf1), total, buf1_len);
|
1620
2988
|
buf1[buf1_len] = 0;
|
1621
2989
|
|
1622
2990
|
buf2_len = j - i;
|
1623
|
-
|
2991
|
+
strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
|
1624
2992
|
buf2[buf2_len] = 0;
|
1625
2993
|
|
1626
2994
|
buf3_len = total_len - j;
|
1627
|
-
|
2995
|
+
strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
|
1628
2996
|
buf3[buf3_len] = 0;
|
1629
2997
|
|
1630
2998
|
read = parse(buf1, buf1_len);
|
1631
2999
|
|
1632
|
-
if (
|
3000
|
+
if (parser->upgrade) goto test;
|
1633
3001
|
|
1634
3002
|
if (read != buf1_len) {
|
1635
3003
|
print_error(buf1, read);
|
1636
3004
|
goto error;
|
1637
3005
|
}
|
1638
3006
|
|
1639
|
-
read
|
3007
|
+
read += parse(buf2, buf2_len);
|
1640
3008
|
|
1641
|
-
if (
|
3009
|
+
if (parser->upgrade) goto test;
|
1642
3010
|
|
1643
|
-
if (read != buf2_len) {
|
3011
|
+
if (read != buf1_len + buf2_len) {
|
1644
3012
|
print_error(buf2, read);
|
1645
3013
|
goto error;
|
1646
3014
|
}
|
1647
3015
|
|
1648
|
-
read
|
3016
|
+
read += parse(buf3, buf3_len);
|
1649
3017
|
|
1650
|
-
if (
|
3018
|
+
if (parser->upgrade) goto test;
|
1651
3019
|
|
1652
|
-
if (read != buf3_len) {
|
3020
|
+
if (read != buf1_len + buf2_len + buf3_len) {
|
1653
3021
|
print_error(buf3, read);
|
1654
3022
|
goto error;
|
1655
3023
|
}
|
@@ -1657,9 +3025,13 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
|
|
1657
3025
|
parse(NULL, 0);
|
1658
3026
|
|
1659
3027
|
test:
|
3028
|
+
if (parser->upgrade) {
|
3029
|
+
upgrade_message_fix(total, read, 3, r1, r2, r3);
|
3030
|
+
}
|
1660
3031
|
|
1661
|
-
if (
|
1662
|
-
fprintf(stderr, "\n\nParser didn't see
|
3032
|
+
if (message_count != num_messages) {
|
3033
|
+
fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
|
3034
|
+
message_count, num_messages);
|
1663
3035
|
goto error;
|
1664
3036
|
}
|
1665
3037
|
|
@@ -1668,12 +3040,12 @@ test:
|
|
1668
3040
|
goto error;
|
1669
3041
|
}
|
1670
3042
|
|
1671
|
-
if (!message_eq(1, r2)) {
|
3043
|
+
if (message_count > 1 && !message_eq(1, r2)) {
|
1672
3044
|
fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
|
1673
3045
|
goto error;
|
1674
3046
|
}
|
1675
3047
|
|
1676
|
-
if (!message_eq(2, r3)) {
|
3048
|
+
if (message_count > 2 && !message_eq(2, r3)) {
|
1677
3049
|
fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
|
1678
3050
|
goto error;
|
1679
3051
|
}
|
@@ -1690,7 +3062,7 @@ test:
|
|
1690
3062
|
fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
|
1691
3063
|
fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
|
1692
3064
|
fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
|
1693
|
-
|
3065
|
+
abort();
|
1694
3066
|
}
|
1695
3067
|
|
1696
3068
|
// user required to free the result
|
@@ -1724,136 +3096,91 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
|
1724
3096
|
return buf;
|
1725
3097
|
}
|
1726
3098
|
|
1727
|
-
|
1728
|
-
|
1729
|
-
size_t j, i, len = strlen(orig);
|
1730
|
-
char * quoted = malloc(len == 0 ? 1 : len*2); // hm..
|
1731
|
-
bzero(quoted, len == 0 ? 1 : len*2);
|
1732
|
-
for (i=0, j=0; i!=len; ++i) {
|
1733
|
-
switch (orig[i]){
|
1734
|
-
case '\n':
|
1735
|
-
quoted[j++] = '\\';
|
1736
|
-
quoted[j++] = 'n';
|
1737
|
-
break;
|
1738
|
-
case '\r':
|
1739
|
-
quoted[j++] = '\\';
|
1740
|
-
quoted[j++] = 'r';
|
1741
|
-
break;
|
1742
|
-
case '"':
|
1743
|
-
quoted[j++] = '\\';
|
1744
|
-
quoted[j++] = '"';
|
1745
|
-
break;
|
1746
|
-
default :
|
1747
|
-
quoted[j++] = orig[i];
|
1748
|
-
}
|
1749
|
-
}
|
1750
|
-
return quoted;
|
1751
|
-
}
|
1752
|
-
|
1753
|
-
void
|
1754
|
-
dump_message(const struct message * m)
|
3099
|
+
void
|
3100
|
+
test_status_complete (void)
|
1755
3101
|
{
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
printf("type :HTTP_RESPONSE\n"); break;
|
1766
|
-
case HTTP_BOTH:
|
1767
|
-
printf("type :HTTP_BOTH\n");
|
1768
|
-
}
|
1769
|
-
switch (m->method) {
|
1770
|
-
case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
|
1771
|
-
case HTTP_GET: printf("method: HTTP_GET\n");break;
|
1772
|
-
case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
|
1773
|
-
case HTTP_POST: printf("method: HTTP_POST\n");break;
|
1774
|
-
case HTTP_PUT: printf("method: HTTP_PUT\n");break;
|
1775
|
-
case HTTP_CONNECT: printf("method: HTTP_CONNECT\n");break;
|
1776
|
-
case HTTP_OPTIONS: printf("method: HTTP_OPTIONS\n");break;
|
1777
|
-
case HTTP_TRACE: printf("method: HTTP_TRACE\n");break;
|
1778
|
-
case HTTP_COPY: printf("method: HTTP_COPY\n");break;
|
1779
|
-
case HTTP_LOCK: printf("method: HTTP_LOCK\n");break;
|
1780
|
-
case HTTP_MKCOL: printf("method: HTTP_MKCOL\n");break;
|
1781
|
-
case HTTP_MOVE: printf("method: HTTP_MOVE\n");break;
|
1782
|
-
case HTTP_PROPFIND: printf("method: HTTP_PROPFIND\n");break;
|
1783
|
-
case HTTP_PROPPATCH: printf("method: HTTP_PROPPATCH\n");break;
|
1784
|
-
case HTTP_UNLOCK: printf("method: HTTP_UNLOCK\n");break;
|
1785
|
-
/* subversion */
|
1786
|
-
case HTTP_REPORT: printf("method: HTTP_REPORT\n"); break;
|
1787
|
-
case HTTP_MKACTIVITY: printf("method: HTTP_MKACTIVITY\n"); break;
|
1788
|
-
case HTTP_CHECKOUT: printf("method: HTTP_CHECKOUT\n"); break;
|
1789
|
-
case HTTP_MERGE: printf("method: HTTP_MERGE\n"); break;
|
1790
|
-
|
1791
|
-
case HTTP_MSEARCH: printf("method: HTTP_MSEARCH\n"); break;
|
1792
|
-
case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
|
1793
|
-
case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
|
1794
|
-
case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
|
1795
|
-
default:
|
1796
|
-
printf("method: UNKNOWN\n"); break;
|
1797
|
-
break;
|
1798
|
-
}
|
1799
|
-
printf("status_code :%d\n", m->status_code);
|
1800
|
-
printf("request_path:%s\n", m->request_path);
|
1801
|
-
printf("request_url :%s\n", m->request_url);
|
1802
|
-
printf("fragment :%s\n", m->fragment);
|
1803
|
-
printf("query_string:%s\n", m->query_string);
|
1804
|
-
|
1805
|
-
bla = quote(m->body);
|
1806
|
-
printf("body :\"%s\"\n", bla);
|
1807
|
-
free(bla);
|
1808
|
-
printf("body_size :%zu\n", m->body_size);
|
1809
|
-
|
1810
|
-
for (i=0; i!=m->num_headers; ++i){
|
1811
|
-
printf("header_%d :{ \"%s\": \"%s\"}\n", i, m->headers[i][0], m->headers[i][1]);
|
1812
|
-
}
|
1813
|
-
|
1814
|
-
printf("should_keep_alive :%d\n", m->should_keep_alive);
|
1815
|
-
printf("upgrade :%d\n", m->upgrade);
|
1816
|
-
printf("http_major :%d\n", m->http_major);
|
1817
|
-
printf("http_minor :%d\n", m->http_minor);
|
1818
|
-
// printf("message_begin_cb_called :%d\n", m->message_begin_cb_called);
|
1819
|
-
// printf("headers_complete_cb_called:%d\n", m->headers_complete_cb_called);
|
1820
|
-
// printf("message_complete_cb_called:%d\n", m->message_complete_cb_called);
|
1821
|
-
// printf("message_complete_on_eof :%d\n", m->message_complete_on_eof);
|
1822
|
-
printf("\n");
|
3102
|
+
parser_init(HTTP_RESPONSE);
|
3103
|
+
parser->data = 0;
|
3104
|
+
http_parser_settings settings = settings_null;
|
3105
|
+
settings.on_status_complete = status_complete_cb;
|
3106
|
+
|
3107
|
+
char *response = "don't mind me, just a simple response";
|
3108
|
+
http_parser_execute(parser, &settings, response, strlen(response));
|
3109
|
+
assert(parser->data == (void*)0); // the status_complete callback was never called
|
3110
|
+
assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line
|
1823
3111
|
}
|
1824
3112
|
|
1825
|
-
|
1826
|
-
|
3113
|
+
/* Verify that we can pause parsing at any of the bytes in the
|
3114
|
+
* message and still get the result that we're expecting. */
|
3115
|
+
void
|
3116
|
+
test_message_pause (const struct message *msg)
|
1827
3117
|
{
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
3118
|
+
char *buf = (char*) msg->raw;
|
3119
|
+
size_t buflen = strlen(msg->raw);
|
3120
|
+
size_t nread;
|
3121
|
+
|
3122
|
+
parser_init(msg->type);
|
3123
|
+
|
3124
|
+
do {
|
3125
|
+
nread = parse_pause(buf, buflen);
|
3126
|
+
|
3127
|
+
// We can only set the upgrade buffer once we've gotten our message
|
3128
|
+
// completion callback.
|
3129
|
+
if (messages[0].message_complete_cb_called &&
|
3130
|
+
msg->upgrade &&
|
3131
|
+
parser->upgrade) {
|
3132
|
+
messages[0].upgrade = buf + nread;
|
3133
|
+
goto test;
|
3134
|
+
}
|
3135
|
+
|
3136
|
+
if (nread < buflen) {
|
3137
|
+
|
3138
|
+
// Not much do to if we failed a strict-mode check
|
3139
|
+
if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
|
3140
|
+
parser_free();
|
3141
|
+
return;
|
3142
|
+
}
|
3143
|
+
|
3144
|
+
assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
|
3145
|
+
}
|
3146
|
+
|
3147
|
+
buf += nread;
|
3148
|
+
buflen -= nread;
|
3149
|
+
http_parser_pause(parser, 0);
|
3150
|
+
} while (buflen > 0);
|
3151
|
+
|
3152
|
+
nread = parse_pause(NULL, 0);
|
3153
|
+
assert (nread == 0);
|
3154
|
+
|
3155
|
+
test:
|
3156
|
+
if (num_messages != 1) {
|
3157
|
+
printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name);
|
3158
|
+
abort();
|
1834
3159
|
}
|
3160
|
+
|
3161
|
+
if(!message_eq(0, msg)) abort();
|
3162
|
+
|
3163
|
+
parser_free();
|
1835
3164
|
}
|
1836
3165
|
|
1837
3166
|
int
|
1838
|
-
main (
|
3167
|
+
main (void)
|
1839
3168
|
{
|
1840
3169
|
parser = NULL;
|
1841
3170
|
int i, j, k;
|
1842
3171
|
int request_count;
|
1843
3172
|
int response_count;
|
1844
|
-
|
1845
|
-
if (1 != argc) {
|
1846
|
-
if (0 == (strncmp("-dump", argv[1], sizeof("-dump")))) {
|
1847
|
-
dump_messages();
|
1848
|
-
exit(0);
|
1849
|
-
}
|
1850
|
-
}
|
1851
3173
|
|
1852
3174
|
printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
|
1853
3175
|
|
1854
3176
|
for (request_count = 0; requests[request_count].name; request_count++);
|
1855
3177
|
for (response_count = 0; responses[response_count].name; response_count++);
|
1856
3178
|
|
3179
|
+
//// API
|
3180
|
+
test_preserve_data();
|
3181
|
+
test_parse_url();
|
3182
|
+
test_method_str();
|
3183
|
+
|
1857
3184
|
//// OVERFLOW CONDITIONS
|
1858
3185
|
|
1859
3186
|
test_header_overflow_error(HTTP_REQUEST);
|
@@ -1864,12 +3191,19 @@ main (int argc, char * argv[])
|
|
1864
3191
|
test_no_overflow_long_body(HTTP_RESPONSE, 1000);
|
1865
3192
|
test_no_overflow_long_body(HTTP_RESPONSE, 100000);
|
1866
3193
|
|
3194
|
+
test_header_content_length_overflow_error();
|
3195
|
+
test_chunk_content_length_overflow_error();
|
3196
|
+
|
1867
3197
|
//// RESPONSES
|
1868
3198
|
|
1869
3199
|
for (i = 0; i < response_count; i++) {
|
1870
3200
|
test_message(&responses[i]);
|
1871
3201
|
}
|
1872
3202
|
|
3203
|
+
for (i = 0; i < response_count; i++) {
|
3204
|
+
test_message_pause(&responses[i]);
|
3205
|
+
}
|
3206
|
+
|
1873
3207
|
for (i = 0; i < response_count; i++) {
|
1874
3208
|
if (!responses[i].should_keep_alive) continue;
|
1875
3209
|
for (j = 0; j < response_count; j++) {
|
@@ -1914,7 +3248,7 @@ main (int argc, char * argv[])
|
|
1914
3248
|
|
1915
3249
|
printf("response scan 1/2 ");
|
1916
3250
|
test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
|
1917
|
-
, &responses[
|
3251
|
+
, &responses[NO_BODY_HTTP10_KA_204]
|
1918
3252
|
, &responses[NO_REASON_PHRASE]
|
1919
3253
|
);
|
1920
3254
|
|
@@ -1929,13 +3263,13 @@ main (int argc, char * argv[])
|
|
1929
3263
|
|
1930
3264
|
/// REQUESTS
|
1931
3265
|
|
1932
|
-
test_simple("hello world",
|
1933
|
-
test_simple("GET / HTP/1.1\r\n\r\n",
|
3266
|
+
test_simple("hello world", HPE_INVALID_METHOD);
|
3267
|
+
test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
|
1934
3268
|
|
1935
3269
|
|
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",
|
3270
|
+
test_simple("ASDF / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
3271
|
+
test_simple("PROPPATCHA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
3272
|
+
test_simple("GETA / HTTP/1.1\r\n\r\n", HPE_INVALID_METHOD);
|
1939
3273
|
|
1940
3274
|
// Well-formed but incomplete
|
1941
3275
|
test_simple("GET / HTTP/1.1\r\n"
|
@@ -1943,7 +3277,7 @@ main (int argc, char * argv[])
|
|
1943
3277
|
"Content-Length: 6\r\n"
|
1944
3278
|
"\r\n"
|
1945
3279
|
"fooba",
|
1946
|
-
|
3280
|
+
HPE_OK);
|
1947
3281
|
|
1948
3282
|
static const char *all_methods[] = {
|
1949
3283
|
"DELETE",
|
@@ -1961,12 +3295,31 @@ main (int argc, char * argv[])
|
|
1961
3295
|
"PROPFIND",
|
1962
3296
|
"PROPPATCH",
|
1963
3297
|
"UNLOCK",
|
3298
|
+
"REPORT",
|
3299
|
+
"MKACTIVITY",
|
3300
|
+
"CHECKOUT",
|
3301
|
+
"MERGE",
|
3302
|
+
"M-SEARCH",
|
3303
|
+
"NOTIFY",
|
3304
|
+
"SUBSCRIBE",
|
3305
|
+
"UNSUBSCRIBE",
|
3306
|
+
"PATCH",
|
1964
3307
|
0 };
|
1965
3308
|
const char **this_method;
|
1966
3309
|
for (this_method = all_methods; *this_method; this_method++) {
|
1967
3310
|
char buf[200];
|
1968
3311
|
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
1969
|
-
test_simple(buf,
|
3312
|
+
test_simple(buf, HPE_OK);
|
3313
|
+
}
|
3314
|
+
|
3315
|
+
static const char *bad_methods[] = {
|
3316
|
+
"C******",
|
3317
|
+
"M****",
|
3318
|
+
0 };
|
3319
|
+
for (this_method = bad_methods; *this_method; this_method++) {
|
3320
|
+
char buf[200];
|
3321
|
+
sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
|
3322
|
+
test_simple(buf, HPE_UNKNOWN);
|
1970
3323
|
}
|
1971
3324
|
|
1972
3325
|
const char *dumbfuck2 =
|
@@ -2004,7 +3357,7 @@ main (int argc, char * argv[])
|
|
2004
3357
|
"\tRA==\r\n"
|
2005
3358
|
"\t-----END CERTIFICATE-----\r\n"
|
2006
3359
|
"\r\n";
|
2007
|
-
test_simple(dumbfuck2,
|
3360
|
+
test_simple(dumbfuck2, HPE_OK);
|
2008
3361
|
|
2009
3362
|
#if 0
|
2010
3363
|
// NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
|
@@ -2026,7 +3379,9 @@ main (int argc, char * argv[])
|
|
2026
3379
|
test_message(&requests[i]);
|
2027
3380
|
}
|
2028
3381
|
|
2029
|
-
|
3382
|
+
for (i = 0; i < request_count; i++) {
|
3383
|
+
test_message_pause(&requests[i]);
|
3384
|
+
}
|
2030
3385
|
|
2031
3386
|
for (i = 0; i < request_count; i++) {
|
2032
3387
|
if (!requests[i].should_keep_alive) continue;
|
@@ -2062,6 +3417,8 @@ main (int argc, char * argv[])
|
|
2062
3417
|
, &requests[CONNECT_REQUEST]
|
2063
3418
|
);
|
2064
3419
|
|
3420
|
+
test_status_complete();
|
3421
|
+
|
2065
3422
|
puts("requests okay");
|
2066
3423
|
|
2067
3424
|
return 0;
|