midori_http_parser 0.6.1.3 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitmodules +0 -3
  4. data/.travis.yml +12 -17
  5. data/Gemfile +5 -0
  6. data/{LICENSE-MIT → LICENSE} +5 -2
  7. data/midori_http_parser.gemspec +3 -9
  8. data/spec/spec_helper.rb +8 -1
  9. data/tasks/compile.rake +7 -13
  10. metadata +5 -74
  11. data/ext/ruby_http_parser/RubyHttpParserService.java +0 -18
  12. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +0 -495
  13. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +0 -32
  14. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +0 -48
  15. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +0 -183
  16. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +0 -28
  17. data/ext/ruby_http_parser/vendor/http-parser-java/build.xml +0 -74
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +0 -2175
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +0 -79
  20. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +0 -304
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +0 -22
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +0 -41
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPCallback.java +0 -8
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPDataCallback.java +0 -34
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPErrorCallback.java +0 -12
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +0 -9
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +0 -113
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +0 -36
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +0 -76
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +0 -256
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java +0 -13
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +0 -111
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java +0 -5
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java +0 -25
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java +0 -7
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +0 -2171
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +0 -83
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +0 -374
  39. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +0 -51
  40. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +0 -69
  41. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +0 -52
  42. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +0 -16
  43. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +0 -48
  44. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +0 -212
  45. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +0 -62
  46. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +0 -117
  47. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +0 -27
  48. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +0 -127
  49. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +0 -236
  50. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +0 -59
  51. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +0 -3425
  52. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +0 -845
  53. data/ext/ruby_http_parser/vendor/http-parser-java/tests.utf8 +0 -17
  54. data/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb +0 -6
  55. data/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb +0 -13
  56. data/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb +0 -15
  57. data/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb +0 -33
  58. data/ext/ruby_http_parser/vendor/http-parser/test_fast +0 -0
  59. data/ext/ruby_http_parser/vendor/http-parser/test_g +0 -0
@@ -1,59 +0,0 @@
1
- package http_parser.lolevel;
2
-
3
- import java.nio.*;
4
- import java.util.*;
5
-
6
- import http_parser.ParserType;
7
-
8
- import static http_parser.lolevel.Util.*;
9
-
10
- public class WrongContentLength {
11
- static final String contentLength = "GET / HTTP/1.0\r\n" +
12
- "Content-Length: 5\r\n" +
13
- "\r\n" +
14
- "hello" +
15
- "hello_again";
16
- static void test () {
17
- p(WrongContentLength.class);
18
- HTTPParser parser = new HTTPParser(ParserType.HTTP_REQUEST);
19
- ByteBuffer buf = buffer(contentLength);
20
-
21
- Settings settings = new Settings();
22
-
23
- int read = parser.execute(settings, buf);
24
- check (settings.msg_cmplt_called);
25
- check ("invalid method".equals(settings.err));
26
-
27
- }
28
- public static void main(String [] args) {
29
- test();
30
- }
31
-
32
- static class Settings extends ParserSettings {
33
- public int bodyCount;
34
- public boolean msg_cmplt_called;
35
- public String err;
36
- Settings () {
37
- this.on_message_complete = new HTTPCallback () {
38
- public int cb (HTTPParser p) {
39
- check (5 == bodyCount);
40
- msg_cmplt_called = true;
41
- return 0;
42
- }
43
- };
44
- this.on_body = new HTTPDataCallback() {
45
- public int cb (HTTPParser p, ByteBuffer b, int pos, int len) {
46
- bodyCount += len;
47
- check ("hello".equals(str(b, pos, len)));
48
- return 0;
49
- }
50
- };
51
- this.on_error = new HTTPErrorCallback() {
52
- public void cb (HTTPParser p, String mes, ByteBuffer b, int i) {
53
- err = mes;
54
- }
55
- };
56
- }
57
- }
58
-
59
- }
@@ -1,3425 +0,0 @@
1
- /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
- *
3
- * Permission is hereby granted, free of charge, to any person obtaining a copy
4
- * of this software and associated documentation files (the "Software"), to
5
- * deal in the Software without restriction, including without limitation the
6
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
- * sell copies of the Software, and to permit persons to whom the Software is
8
- * furnished to do so, subject to the following conditions:
9
- *
10
- * The above copyright notice and this permission notice shall be included in
11
- * all copies or substantial portions of the Software.
12
- *
13
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
- * IN THE SOFTWARE.
20
- */
21
- #include "http_parser.h"
22
- #include <stdlib.h>
23
- #include <assert.h>
24
- #include <stdio.h>
25
- #include <stdlib.h> /* rand */
26
- #include <string.h>
27
- #include <stdarg.h>
28
-
29
- #undef TRUE
30
- #define TRUE 1
31
- #undef FALSE
32
- #define FALSE 0
33
-
34
- #define MAX_HEADERS 13
35
- #define MAX_ELEMENT_SIZE 2048
36
-
37
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
38
-
39
- static http_parser *parser;
40
-
41
- struct message {
42
- const char *name; // for debugging purposes
43
- const char *raw;
44
- enum http_parser_type type;
45
- enum http_method method;
46
- int status_code;
47
- char request_path[MAX_ELEMENT_SIZE];
48
- char request_url[MAX_ELEMENT_SIZE];
49
- char fragment[MAX_ELEMENT_SIZE];
50
- char query_string[MAX_ELEMENT_SIZE];
51
- char body[MAX_ELEMENT_SIZE];
52
- size_t body_size;
53
- const char *host;
54
- const char *userinfo;
55
- uint16_t port;
56
- int num_headers;
57
- enum { NONE=0, FIELD, VALUE } last_header_element;
58
- char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
59
- int should_keep_alive;
60
-
61
- const char *upgrade; // upgraded body
62
-
63
- unsigned short http_major;
64
- unsigned short http_minor;
65
-
66
- int message_begin_cb_called;
67
- int headers_complete_cb_called;
68
- int message_complete_cb_called;
69
- int message_complete_on_eof;
70
- int body_is_final;
71
- };
72
-
73
- static int currently_parsing_eof;
74
-
75
- static struct message messages[5];
76
- static int num_messages;
77
- static http_parser_settings *current_pause_parser;
78
-
79
- /* * R E Q U E S T S * */
80
- const struct message requests[] =
81
- #define CURL_GET 0
82
- { {.name= "curl get"
83
- ,.type= HTTP_REQUEST
84
- ,.raw= "GET /test HTTP/1.1\r\n"
85
- "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n"
86
- "Host: 0.0.0.0=5000\r\n"
87
- "Accept: */*\r\n"
88
- "\r\n"
89
- ,.should_keep_alive= TRUE
90
- ,.message_complete_on_eof= FALSE
91
- ,.http_major= 1
92
- ,.http_minor= 1
93
- ,.method= HTTP_GET
94
- ,.query_string= ""
95
- ,.fragment= ""
96
- ,.request_path= "/test"
97
- ,.request_url= "/test"
98
- ,.num_headers= 3
99
- ,.headers=
100
- { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" }
101
- , { "Host", "0.0.0.0=5000" }
102
- , { "Accept", "*/*" }
103
- }
104
- ,.body= ""
105
- }
106
-
107
- #define FIREFOX_GET 1
108
- , {.name= "firefox get"
109
- ,.type= HTTP_REQUEST
110
- ,.raw= "GET /favicon.ico HTTP/1.1\r\n"
111
- "Host: 0.0.0.0=5000\r\n"
112
- "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
113
- "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
114
- "Accept-Language: en-us,en;q=0.5\r\n"
115
- "Accept-Encoding: gzip,deflate\r\n"
116
- "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
117
- "Keep-Alive: 300\r\n"
118
- "Connection: keep-alive\r\n"
119
- "\r\n"
120
- ,.should_keep_alive= TRUE
121
- ,.message_complete_on_eof= FALSE
122
- ,.http_major= 1
123
- ,.http_minor= 1
124
- ,.method= HTTP_GET
125
- ,.query_string= ""
126
- ,.fragment= ""
127
- ,.request_path= "/favicon.ico"
128
- ,.request_url= "/favicon.ico"
129
- ,.num_headers= 8
130
- ,.headers=
131
- { { "Host", "0.0.0.0=5000" }
132
- , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" }
133
- , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }
134
- , { "Accept-Language", "en-us,en;q=0.5" }
135
- , { "Accept-Encoding", "gzip,deflate" }
136
- , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" }
137
- , { "Keep-Alive", "300" }
138
- , { "Connection", "keep-alive" }
139
- }
140
- ,.body= ""
141
- }
142
-
143
- #define DUMBFUCK 2
144
- , {.name= "dumbfuck"
145
- ,.type= HTTP_REQUEST
146
- ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
147
- "aaaaaaaaaaaaa:++++++++++\r\n"
148
- "\r\n"
149
- ,.should_keep_alive= TRUE
150
- ,.message_complete_on_eof= FALSE
151
- ,.http_major= 1
152
- ,.http_minor= 1
153
- ,.method= HTTP_GET
154
- ,.query_string= ""
155
- ,.fragment= ""
156
- ,.request_path= "/dumbfuck"
157
- ,.request_url= "/dumbfuck"
158
- ,.num_headers= 1
159
- ,.headers=
160
- { { "aaaaaaaaaaaaa", "++++++++++" }
161
- }
162
- ,.body= ""
163
- }
164
-
165
- #define FRAGMENT_IN_URI 3
166
- , {.name= "fragment in url"
167
- ,.type= HTTP_REQUEST
168
- ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
169
- "\r\n"
170
- ,.should_keep_alive= TRUE
171
- ,.message_complete_on_eof= FALSE
172
- ,.http_major= 1
173
- ,.http_minor= 1
174
- ,.method= HTTP_GET
175
- ,.query_string= "page=1"
176
- ,.fragment= "posts-17408"
177
- ,.request_path= "/forums/1/topics/2375"
178
- /* XXX request url does include fragment? */
179
- ,.request_url= "/forums/1/topics/2375?page=1#posts-17408"
180
- ,.num_headers= 0
181
- ,.body= ""
182
- }
183
-
184
- #define GET_NO_HEADERS_NO_BODY 4
185
- , {.name= "get no headers no body"
186
- ,.type= HTTP_REQUEST
187
- ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n"
188
- "\r\n"
189
- ,.should_keep_alive= TRUE
190
- ,.message_complete_on_eof= FALSE /* would need Connection: close */
191
- ,.http_major= 1
192
- ,.http_minor= 1
193
- ,.method= HTTP_GET
194
- ,.query_string= ""
195
- ,.fragment= ""
196
- ,.request_path= "/get_no_headers_no_body/world"
197
- ,.request_url= "/get_no_headers_no_body/world"
198
- ,.num_headers= 0
199
- ,.body= ""
200
- }
201
-
202
- #define GET_ONE_HEADER_NO_BODY 5
203
- , {.name= "get one header no body"
204
- ,.type= HTTP_REQUEST
205
- ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n"
206
- "Accept: */*\r\n"
207
- "\r\n"
208
- ,.should_keep_alive= TRUE
209
- ,.message_complete_on_eof= FALSE /* would need Connection: close */
210
- ,.http_major= 1
211
- ,.http_minor= 1
212
- ,.method= HTTP_GET
213
- ,.query_string= ""
214
- ,.fragment= ""
215
- ,.request_path= "/get_one_header_no_body"
216
- ,.request_url= "/get_one_header_no_body"
217
- ,.num_headers= 1
218
- ,.headers=
219
- { { "Accept" , "*/*" }
220
- }
221
- ,.body= ""
222
- }
223
-
224
- #define GET_FUNKY_CONTENT_LENGTH 6
225
- , {.name= "get funky content length body hello"
226
- ,.type= HTTP_REQUEST
227
- ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
228
- "conTENT-Length: 5\r\n"
229
- "\r\n"
230
- "HELLO"
231
- ,.should_keep_alive= FALSE
232
- ,.message_complete_on_eof= FALSE
233
- ,.http_major= 1
234
- ,.http_minor= 0
235
- ,.method= HTTP_GET
236
- ,.query_string= ""
237
- ,.fragment= ""
238
- ,.request_path= "/get_funky_content_length_body_hello"
239
- ,.request_url= "/get_funky_content_length_body_hello"
240
- ,.num_headers= 1
241
- ,.headers=
242
- { { "conTENT-Length" , "5" }
243
- }
244
- ,.body= "HELLO"
245
- }
246
-
247
- #define POST_IDENTITY_BODY_WORLD 7
248
- , {.name= "post identity body world"
249
- ,.type= HTTP_REQUEST
250
- ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
251
- "Accept: */*\r\n"
252
- "Transfer-Encoding: identity\r\n"
253
- "Content-Length: 5\r\n"
254
- "\r\n"
255
- "World"
256
- ,.should_keep_alive= TRUE
257
- ,.message_complete_on_eof= FALSE
258
- ,.http_major= 1
259
- ,.http_minor= 1
260
- ,.method= HTTP_POST
261
- ,.query_string= "q=search"
262
- ,.fragment= "hey"
263
- ,.request_path= "/post_identity_body_world"
264
- ,.request_url= "/post_identity_body_world?q=search#hey"
265
- ,.num_headers= 3
266
- ,.headers=
267
- { { "Accept", "*/*" }
268
- , { "Transfer-Encoding", "identity" }
269
- , { "Content-Length", "5" }
270
- }
271
- ,.body= "World"
272
- }
273
-
274
- #define POST_CHUNKED_ALL_YOUR_BASE 8
275
- , {.name= "post - chunked body: all your base are belong to us"
276
- ,.type= HTTP_REQUEST
277
- ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n"
278
- "Transfer-Encoding: chunked\r\n"
279
- "\r\n"
280
- "1e\r\nall your base are belong to us\r\n"
281
- "0\r\n"
282
- "\r\n"
283
- ,.should_keep_alive= TRUE
284
- ,.message_complete_on_eof= FALSE
285
- ,.http_major= 1
286
- ,.http_minor= 1
287
- ,.method= HTTP_POST
288
- ,.query_string= ""
289
- ,.fragment= ""
290
- ,.request_path= "/post_chunked_all_your_base"
291
- ,.request_url= "/post_chunked_all_your_base"
292
- ,.num_headers= 1
293
- ,.headers=
294
- { { "Transfer-Encoding" , "chunked" }
295
- }
296
- ,.body= "all your base are belong to us"
297
- }
298
-
299
- #define TWO_CHUNKS_MULT_ZERO_END 9
300
- , {.name= "two chunks ; triple zero ending"
301
- ,.type= HTTP_REQUEST
302
- ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
303
- "Transfer-Encoding: chunked\r\n"
304
- "\r\n"
305
- "5\r\nhello\r\n"
306
- "6\r\n world\r\n"
307
- "000\r\n"
308
- "\r\n"
309
- ,.should_keep_alive= TRUE
310
- ,.message_complete_on_eof= FALSE
311
- ,.http_major= 1
312
- ,.http_minor= 1
313
- ,.method= HTTP_POST
314
- ,.query_string= ""
315
- ,.fragment= ""
316
- ,.request_path= "/two_chunks_mult_zero_end"
317
- ,.request_url= "/two_chunks_mult_zero_end"
318
- ,.num_headers= 1
319
- ,.headers=
320
- { { "Transfer-Encoding", "chunked" }
321
- }
322
- ,.body= "hello world"
323
- }
324
-
325
- #define CHUNKED_W_TRAILING_HEADERS 10
326
- , {.name= "chunked with trailing headers. blech."
327
- ,.type= HTTP_REQUEST
328
- ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n"
329
- "Transfer-Encoding: chunked\r\n"
330
- "\r\n"
331
- "5\r\nhello\r\n"
332
- "6\r\n world\r\n"
333
- "0\r\n"
334
- "Vary: *\r\n"
335
- "Content-Type: text/plain\r\n"
336
- "\r\n"
337
- ,.should_keep_alive= TRUE
338
- ,.message_complete_on_eof= FALSE
339
- ,.http_major= 1
340
- ,.http_minor= 1
341
- ,.method= HTTP_POST
342
- ,.query_string= ""
343
- ,.fragment= ""
344
- ,.request_path= "/chunked_w_trailing_headers"
345
- ,.request_url= "/chunked_w_trailing_headers"
346
- ,.num_headers= 3
347
- ,.headers=
348
- { { "Transfer-Encoding", "chunked" }
349
- , { "Vary", "*" }
350
- , { "Content-Type", "text/plain" }
351
- }
352
- ,.body= "hello world"
353
- }
354
-
355
- #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
356
- , {.name= "with bullshit after the length"
357
- ,.type= HTTP_REQUEST
358
- ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
359
- "Transfer-Encoding: chunked\r\n"
360
- "\r\n"
361
- "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
362
- "6; blahblah; blah\r\n world\r\n"
363
- "0\r\n"
364
- "\r\n"
365
- ,.should_keep_alive= TRUE
366
- ,.message_complete_on_eof= FALSE
367
- ,.http_major= 1
368
- ,.http_minor= 1
369
- ,.method= HTTP_POST
370
- ,.query_string= ""
371
- ,.fragment= ""
372
- ,.request_path= "/chunked_w_bullshit_after_length"
373
- ,.request_url= "/chunked_w_bullshit_after_length"
374
- ,.num_headers= 1
375
- ,.headers=
376
- { { "Transfer-Encoding", "chunked" }
377
- }
378
- ,.body= "hello world"
379
- }
380
-
381
- #define WITH_QUOTES 12
382
- , {.name= "with quotes"
383
- ,.type= HTTP_REQUEST
384
- ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n"
385
- ,.should_keep_alive= TRUE
386
- ,.message_complete_on_eof= FALSE
387
- ,.http_major= 1
388
- ,.http_minor= 1
389
- ,.method= HTTP_GET
390
- ,.query_string= "foo=\"bar\""
391
- ,.fragment= ""
392
- ,.request_path= "/with_\"stupid\"_quotes"
393
- ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\""
394
- ,.num_headers= 0
395
- ,.headers= { }
396
- ,.body= ""
397
- }
398
-
399
- #define APACHEBENCH_GET 13
400
- /* The server receiving this request SHOULD NOT wait for EOF
401
- * to know that content-length == 0.
402
- * How to represent this in a unit test? message_complete_on_eof
403
- * Compare with NO_CONTENT_LENGTH_RESPONSE.
404
- */
405
- , {.name = "apachebench get"
406
- ,.type= HTTP_REQUEST
407
- ,.raw= "GET /test HTTP/1.0\r\n"
408
- "Host: 0.0.0.0:5000\r\n"
409
- "User-Agent: ApacheBench/2.3\r\n"
410
- "Accept: */*\r\n\r\n"
411
- ,.should_keep_alive= FALSE
412
- ,.message_complete_on_eof= FALSE
413
- ,.http_major= 1
414
- ,.http_minor= 0
415
- ,.method= HTTP_GET
416
- ,.query_string= ""
417
- ,.fragment= ""
418
- ,.request_path= "/test"
419
- ,.request_url= "/test"
420
- ,.num_headers= 3
421
- ,.headers= { { "Host", "0.0.0.0:5000" }
422
- , { "User-Agent", "ApacheBench/2.3" }
423
- , { "Accept", "*/*" }
424
- }
425
- ,.body= ""
426
- }
427
-
428
- #define QUERY_URL_WITH_QUESTION_MARK_GET 14
429
- /* Some clients include '?' characters in query strings.
430
- */
431
- , {.name = "query url with question mark"
432
- ,.type= HTTP_REQUEST
433
- ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n"
434
- ,.should_keep_alive= TRUE
435
- ,.message_complete_on_eof= FALSE
436
- ,.http_major= 1
437
- ,.http_minor= 1
438
- ,.method= HTTP_GET
439
- ,.query_string= "foo=bar?baz"
440
- ,.fragment= ""
441
- ,.request_path= "/test.cgi"
442
- ,.request_url= "/test.cgi?foo=bar?baz"
443
- ,.num_headers= 0
444
- ,.headers= {}
445
- ,.body= ""
446
- }
447
-
448
- #define PREFIX_NEWLINE_GET 15
449
- /* Some clients, especially after a POST in a keep-alive connection,
450
- * will send an extra CRLF before the next request
451
- */
452
- , {.name = "newline prefix get"
453
- ,.type= HTTP_REQUEST
454
- ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n"
455
- ,.should_keep_alive= TRUE
456
- ,.message_complete_on_eof= FALSE
457
- ,.http_major= 1
458
- ,.http_minor= 1
459
- ,.method= HTTP_GET
460
- ,.query_string= ""
461
- ,.fragment= ""
462
- ,.request_path= "/test"
463
- ,.request_url= "/test"
464
- ,.num_headers= 0
465
- ,.headers= { }
466
- ,.body= ""
467
- }
468
-
469
- #define UPGRADE_REQUEST 16
470
- , {.name = "upgrade request"
471
- ,.type= HTTP_REQUEST
472
- ,.raw= "GET /demo HTTP/1.1\r\n"
473
- "Host: example.com\r\n"
474
- "Connection: Upgrade\r\n"
475
- "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
476
- "Sec-WebSocket-Protocol: sample\r\n"
477
- "Upgrade: WebSocket\r\n"
478
- "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
479
- "Origin: http://example.com\r\n"
480
- "\r\n"
481
- "Hot diggity dogg"
482
- ,.should_keep_alive= TRUE
483
- ,.message_complete_on_eof= FALSE
484
- ,.http_major= 1
485
- ,.http_minor= 1
486
- ,.method= HTTP_GET
487
- ,.query_string= ""
488
- ,.fragment= ""
489
- ,.request_path= "/demo"
490
- ,.request_url= "/demo"
491
- ,.num_headers= 7
492
- ,.upgrade="Hot diggity dogg"
493
- ,.headers= { { "Host", "example.com" }
494
- , { "Connection", "Upgrade" }
495
- , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" }
496
- , { "Sec-WebSocket-Protocol", "sample" }
497
- , { "Upgrade", "WebSocket" }
498
- , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" }
499
- , { "Origin", "http://example.com" }
500
- }
501
- ,.body= ""
502
- }
503
-
504
- #define CONNECT_REQUEST 17
505
- , {.name = "connect request"
506
- ,.type= HTTP_REQUEST
507
- ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n"
508
- "User-agent: Mozilla/1.1N\r\n"
509
- "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n"
510
- "\r\n"
511
- "some data\r\n"
512
- "and yet even more data"
513
- ,.should_keep_alive= FALSE
514
- ,.message_complete_on_eof= FALSE
515
- ,.http_major= 1
516
- ,.http_minor= 0
517
- ,.method= HTTP_CONNECT
518
- ,.query_string= ""
519
- ,.fragment= ""
520
- ,.request_path= ""
521
- ,.request_url= "0-home0.netscape.com:443"
522
- ,.num_headers= 2
523
- ,.upgrade="some data\r\nand yet even more data"
524
- ,.headers= { { "User-agent", "Mozilla/1.1N" }
525
- , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" }
526
- }
527
- ,.body= ""
528
- }
529
-
530
- #define REPORT_REQ 18
531
- , {.name= "report request"
532
- ,.type= HTTP_REQUEST
533
- ,.raw= "REPORT /test HTTP/1.1\r\n"
534
- "\r\n"
535
- ,.should_keep_alive= TRUE
536
- ,.message_complete_on_eof= FALSE
537
- ,.http_major= 1
538
- ,.http_minor= 1
539
- ,.method= HTTP_REPORT
540
- ,.query_string= ""
541
- ,.fragment= ""
542
- ,.request_path= "/test"
543
- ,.request_url= "/test"
544
- ,.num_headers= 0
545
- ,.headers= {}
546
- ,.body= ""
547
- }
548
-
549
- #define NO_HTTP_VERSION 19
550
- , {.name= "request with no http version"
551
- ,.type= HTTP_REQUEST
552
- ,.raw= "GET /\r\n"
553
- "\r\n"
554
- ,.should_keep_alive= FALSE
555
- ,.message_complete_on_eof= FALSE
556
- ,.http_major= 0
557
- ,.http_minor= 9
558
- ,.method= HTTP_GET
559
- ,.query_string= ""
560
- ,.fragment= ""
561
- ,.request_path= "/"
562
- ,.request_url= "/"
563
- ,.num_headers= 0
564
- ,.headers= {}
565
- ,.body= ""
566
- }
567
-
568
- #define MSEARCH_REQ 20
569
- , {.name= "m-search request"
570
- ,.type= HTTP_REQUEST
571
- ,.raw= "M-SEARCH * HTTP/1.1\r\n"
572
- "HOST: 239.255.255.250:1900\r\n"
573
- "MAN: \"ssdp:discover\"\r\n"
574
- "ST: \"ssdp:all\"\r\n"
575
- "\r\n"
576
- ,.should_keep_alive= TRUE
577
- ,.message_complete_on_eof= FALSE
578
- ,.http_major= 1
579
- ,.http_minor= 1
580
- ,.method= HTTP_MSEARCH
581
- ,.query_string= ""
582
- ,.fragment= ""
583
- ,.request_path= "*"
584
- ,.request_url= "*"
585
- ,.num_headers= 3
586
- ,.headers= { { "HOST", "239.255.255.250:1900" }
587
- , { "MAN", "\"ssdp:discover\"" }
588
- , { "ST", "\"ssdp:all\"" }
589
- }
590
- ,.body= ""
591
- }
592
-
593
- #define LINE_FOLDING_IN_HEADER 21
594
- , {.name= "line folding in header value"
595
- ,.type= HTTP_REQUEST
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"
604
- "\r\n"
605
- ,.should_keep_alive= TRUE
606
- ,.message_complete_on_eof= FALSE
607
- ,.http_major= 1
608
- ,.http_minor= 1
609
- ,.method= HTTP_GET
610
- ,.query_string= ""
611
- ,.fragment= ""
612
- ,.request_path= "/"
613
- ,.request_url= "/"
614
- ,.num_headers= 2
615
- ,.headers= { { "Line1", "abcdefghijklmno qrs" }
616
- , { "Line2", "line2\t" }
617
- }
618
- ,.body= ""
619
- }
620
-
621
-
622
- #define QUERY_TERMINATED_HOST 22
623
- , {.name= "host terminated by a query string"
624
- ,.type= HTTP_REQUEST
625
- ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
626
- "\r\n"
627
- ,.should_keep_alive= TRUE
628
- ,.message_complete_on_eof= FALSE
629
- ,.http_major= 1
630
- ,.http_minor= 1
631
- ,.method= HTTP_GET
632
- ,.query_string= "hail=all"
633
- ,.fragment= ""
634
- ,.request_path= ""
635
- ,.request_url= "http://hypnotoad.org?hail=all"
636
- ,.host= "hypnotoad.org"
637
- ,.num_headers= 0
638
- ,.headers= { }
639
- ,.body= ""
640
- }
641
-
642
- #define QUERY_TERMINATED_HOSTPORT 23
643
- , {.name= "host:port terminated by a query string"
644
- ,.type= HTTP_REQUEST
645
- ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
646
- "\r\n"
647
- ,.should_keep_alive= TRUE
648
- ,.message_complete_on_eof= FALSE
649
- ,.http_major= 1
650
- ,.http_minor= 1
651
- ,.method= HTTP_GET
652
- ,.query_string= "hail=all"
653
- ,.fragment= ""
654
- ,.request_path= ""
655
- ,.request_url= "http://hypnotoad.org:1234?hail=all"
656
- ,.host= "hypnotoad.org"
657
- ,.port= 1234
658
- ,.num_headers= 0
659
- ,.headers= { }
660
- ,.body= ""
661
- }
662
-
663
- #define SPACE_TERMINATED_HOSTPORT 24
664
- , {.name= "host:port terminated by a space"
665
- ,.type= HTTP_REQUEST
666
- ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
667
- "\r\n"
668
- ,.should_keep_alive= TRUE
669
- ,.message_complete_on_eof= FALSE
670
- ,.http_major= 1
671
- ,.http_minor= 1
672
- ,.method= HTTP_GET
673
- ,.query_string= ""
674
- ,.fragment= ""
675
- ,.request_path= ""
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
895
- ,.num_headers= 0
896
- ,.headers= { }
897
- ,.body= ""
898
- }
899
-
900
-
901
- , {.name= NULL } /* sentinel */
902
- };
903
-
904
- /* * R E S P O N S E S * */
905
- const struct message responses[] =
906
- #define GOOGLE_301 0
907
- { {.name= "google 301"
908
- ,.type= HTTP_RESPONSE
909
- ,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
910
- "Location: http://www.google.com/\r\n"
911
- "Content-Type: text/html; charset=UTF-8\r\n"
912
- "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
913
- "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
914
- "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */
915
- "Cache-Control: public, max-age=2592000\r\n"
916
- "Server: gws\r\n"
917
- "Content-Length: 219 \r\n"
918
- "\r\n"
919
- "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
920
- "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
921
- "<H1>301 Moved</H1>\n"
922
- "The document has moved\n"
923
- "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
924
- "</BODY></HTML>\r\n"
925
- ,.should_keep_alive= TRUE
926
- ,.message_complete_on_eof= FALSE
927
- ,.http_major= 1
928
- ,.http_minor= 1
929
- ,.status_code= 301
930
- ,.num_headers= 8
931
- ,.headers=
932
- { { "Location", "http://www.google.com/" }
933
- , { "Content-Type", "text/html; charset=UTF-8" }
934
- , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
935
- , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
936
- , { "X-$PrototypeBI-Version", "1.6.0.3" }
937
- , { "Cache-Control", "public, max-age=2592000" }
938
- , { "Server", "gws" }
939
- , { "Content-Length", "219 " }
940
- }
941
- ,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
942
- "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
943
- "<H1>301 Moved</H1>\n"
944
- "The document has moved\n"
945
- "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
946
- "</BODY></HTML>\r\n"
947
- }
948
-
949
- #define NO_CONTENT_LENGTH_RESPONSE 1
950
- /* The client should wait for the server's EOF. That is, when content-length
951
- * is not specified, and "Connection: close", the end of body is specified
952
- * by the EOF.
953
- * Compare with APACHEBENCH_GET
954
- */
955
- , {.name= "no content-length response"
956
- ,.type= HTTP_RESPONSE
957
- ,.raw= "HTTP/1.1 200 OK\r\n"
958
- "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n"
959
- "Server: Apache\r\n"
960
- "X-Powered-By: Servlet/2.5 JSP/2.1\r\n"
961
- "Content-Type: text/xml; charset=utf-8\r\n"
962
- "Connection: close\r\n"
963
- "\r\n"
964
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
965
- "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
966
- " <SOAP-ENV:Body>\n"
967
- " <SOAP-ENV:Fault>\n"
968
- " <faultcode>SOAP-ENV:Client</faultcode>\n"
969
- " <faultstring>Client Error</faultstring>\n"
970
- " </SOAP-ENV:Fault>\n"
971
- " </SOAP-ENV:Body>\n"
972
- "</SOAP-ENV:Envelope>"
973
- ,.should_keep_alive= FALSE
974
- ,.message_complete_on_eof= TRUE
975
- ,.http_major= 1
976
- ,.http_minor= 1
977
- ,.status_code= 200
978
- ,.num_headers= 5
979
- ,.headers=
980
- { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
981
- , { "Server", "Apache" }
982
- , { "X-Powered-By", "Servlet/2.5 JSP/2.1" }
983
- , { "Content-Type", "text/xml; charset=utf-8" }
984
- , { "Connection", "close" }
985
- }
986
- ,.body= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
987
- "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
988
- " <SOAP-ENV:Body>\n"
989
- " <SOAP-ENV:Fault>\n"
990
- " <faultcode>SOAP-ENV:Client</faultcode>\n"
991
- " <faultstring>Client Error</faultstring>\n"
992
- " </SOAP-ENV:Fault>\n"
993
- " </SOAP-ENV:Body>\n"
994
- "</SOAP-ENV:Envelope>"
995
- }
996
-
997
- #define NO_HEADERS_NO_BODY_404 2
998
- , {.name= "404 no headers no body"
999
- ,.type= HTTP_RESPONSE
1000
- ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
1001
- ,.should_keep_alive= FALSE
1002
- ,.message_complete_on_eof= TRUE
1003
- ,.http_major= 1
1004
- ,.http_minor= 1
1005
- ,.status_code= 404
1006
- ,.num_headers= 0
1007
- ,.headers= {}
1008
- ,.body_size= 0
1009
- ,.body= ""
1010
- }
1011
-
1012
- #define NO_REASON_PHRASE 3
1013
- , {.name= "301 no response phrase"
1014
- ,.type= HTTP_RESPONSE
1015
- ,.raw= "HTTP/1.1 301\r\n\r\n"
1016
- ,.should_keep_alive = FALSE
1017
- ,.message_complete_on_eof= TRUE
1018
- ,.http_major= 1
1019
- ,.http_minor= 1
1020
- ,.status_code= 301
1021
- ,.num_headers= 0
1022
- ,.headers= {}
1023
- ,.body= ""
1024
- }
1025
-
1026
- #define TRAILING_SPACE_ON_CHUNKED_BODY 4
1027
- , {.name="200 trailing space on chunked body"
1028
- ,.type= HTTP_RESPONSE
1029
- ,.raw= "HTTP/1.1 200 OK\r\n"
1030
- "Content-Type: text/plain\r\n"
1031
- "Transfer-Encoding: chunked\r\n"
1032
- "\r\n"
1033
- "25 \r\n"
1034
- "This is the data in the first chunk\r\n"
1035
- "\r\n"
1036
- "1C\r\n"
1037
- "and this is the second one\r\n"
1038
- "\r\n"
1039
- "0 \r\n"
1040
- "\r\n"
1041
- ,.should_keep_alive= TRUE
1042
- ,.message_complete_on_eof= FALSE
1043
- ,.http_major= 1
1044
- ,.http_minor= 1
1045
- ,.status_code= 200
1046
- ,.num_headers= 2
1047
- ,.headers=
1048
- { {"Content-Type", "text/plain" }
1049
- , {"Transfer-Encoding", "chunked" }
1050
- }
1051
- ,.body_size = 37+28
1052
- ,.body =
1053
- "This is the data in the first chunk\r\n"
1054
- "and this is the second one\r\n"
1055
-
1056
- }
1057
-
1058
- #define NO_CARRIAGE_RET 5
1059
- , {.name="no carriage ret"
1060
- ,.type= HTTP_RESPONSE
1061
- ,.raw= "HTTP/1.1 200 OK\n"
1062
- "Content-Type: text/html; charset=utf-8\n"
1063
- "Connection: close\n"
1064
- "\n"
1065
- "these headers are from http://news.ycombinator.com/"
1066
- ,.should_keep_alive= FALSE
1067
- ,.message_complete_on_eof= TRUE
1068
- ,.http_major= 1
1069
- ,.http_minor= 1
1070
- ,.status_code= 200
1071
- ,.num_headers= 2
1072
- ,.headers=
1073
- { {"Content-Type", "text/html; charset=utf-8" }
1074
- , {"Connection", "close" }
1075
- }
1076
- ,.body= "these headers are from http://news.ycombinator.com/"
1077
- }
1078
-
1079
- #define PROXY_CONNECTION 6
1080
- , {.name="proxy connection"
1081
- ,.type= HTTP_RESPONSE
1082
- ,.raw= "HTTP/1.1 200 OK\r\n"
1083
- "Content-Type: text/html; charset=UTF-8\r\n"
1084
- "Content-Length: 11\r\n"
1085
- "Proxy-Connection: close\r\n"
1086
- "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n"
1087
- "\r\n"
1088
- "hello world"
1089
- ,.should_keep_alive= FALSE
1090
- ,.message_complete_on_eof= FALSE
1091
- ,.http_major= 1
1092
- ,.http_minor= 1
1093
- ,.status_code= 200
1094
- ,.num_headers= 4
1095
- ,.headers=
1096
- { {"Content-Type", "text/html; charset=UTF-8" }
1097
- , {"Content-Length", "11" }
1098
- , {"Proxy-Connection", "close" }
1099
- , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"}
1100
- }
1101
- ,.body= "hello world"
1102
- }
1103
-
1104
- #define UNDERSTORE_HEADER_KEY 7
1105
- // shown by
1106
- // curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;"
1107
- , {.name="underscore header key"
1108
- ,.type= HTTP_RESPONSE
1109
- ,.raw= "HTTP/1.1 200 OK\r\n"
1110
- "Server: DCLK-AdSvr\r\n"
1111
- "Content-Type: text/xml\r\n"
1112
- "Content-Length: 0\r\n"
1113
- "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n"
1114
- ,.should_keep_alive= TRUE
1115
- ,.message_complete_on_eof= FALSE
1116
- ,.http_major= 1
1117
- ,.http_minor= 1
1118
- ,.status_code= 200
1119
- ,.num_headers= 4
1120
- ,.headers=
1121
- { {"Server", "DCLK-AdSvr" }
1122
- , {"Content-Type", "text/xml" }
1123
- , {"Content-Length", "0" }
1124
- , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" }
1125
- }
1126
- ,.body= ""
1127
- }
1128
-
1129
- #define BONJOUR_MADAME_FR 8
1130
- /* The client should not merge two headers fields when the first one doesn't
1131
- * have a value.
1132
- */
1133
- , {.name= "bonjourmadame.fr"
1134
- ,.type= HTTP_RESPONSE
1135
- ,.raw= "HTTP/1.0 301 Moved Permanently\r\n"
1136
- "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n"
1137
- "Server: Apache/2.2.3 (Red Hat)\r\n"
1138
- "Cache-Control: public\r\n"
1139
- "Pragma: \r\n"
1140
- "Location: http://www.bonjourmadame.fr/\r\n"
1141
- "Vary: Accept-Encoding\r\n"
1142
- "Content-Length: 0\r\n"
1143
- "Content-Type: text/html; charset=UTF-8\r\n"
1144
- "Connection: keep-alive\r\n"
1145
- "\r\n"
1146
- ,.should_keep_alive= TRUE
1147
- ,.message_complete_on_eof= FALSE
1148
- ,.http_major= 1
1149
- ,.http_minor= 0
1150
- ,.status_code= 301
1151
- ,.num_headers= 9
1152
- ,.headers=
1153
- { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
1154
- , { "Server", "Apache/2.2.3 (Red Hat)" }
1155
- , { "Cache-Control", "public" }
1156
- , { "Pragma", "" }
1157
- , { "Location", "http://www.bonjourmadame.fr/" }
1158
- , { "Vary", "Accept-Encoding" }
1159
- , { "Content-Length", "0" }
1160
- , { "Content-Type", "text/html; charset=UTF-8" }
1161
- , { "Connection", "keep-alive" }
1162
- }
1163
- ,.body= ""
1164
- }
1165
-
1166
- #define RES_FIELD_UNDERSCORE 9
1167
- /* Should handle spaces in header fields */
1168
- , {.name= "field underscore"
1169
- ,.type= HTTP_RESPONSE
1170
- ,.raw= "HTTP/1.1 200 OK\r\n"
1171
- "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n"
1172
- "Server: Apache\r\n"
1173
- "Cache-Control: no-cache, must-revalidate\r\n"
1174
- "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
1175
- ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n"
1176
- "Vary: Accept-Encoding\r\n"
1177
- "_eep-Alive: timeout=45\r\n" /* semantic value ignored */
1178
- "_onnection: Keep-Alive\r\n" /* semantic value ignored */
1179
- "Transfer-Encoding: chunked\r\n"
1180
- "Content-Type: text/html\r\n"
1181
- "Connection: close\r\n"
1182
- "\r\n"
1183
- "0\r\n\r\n"
1184
- ,.should_keep_alive= FALSE
1185
- ,.message_complete_on_eof= FALSE
1186
- ,.http_major= 1
1187
- ,.http_minor= 1
1188
- ,.status_code= 200
1189
- ,.num_headers= 11
1190
- ,.headers=
1191
- { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
1192
- , { "Server", "Apache" }
1193
- , { "Cache-Control", "no-cache, must-revalidate" }
1194
- , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" }
1195
- , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" }
1196
- , { "Vary", "Accept-Encoding" }
1197
- , { "_eep-Alive", "timeout=45" }
1198
- , { "_onnection", "Keep-Alive" }
1199
- , { "Transfer-Encoding", "chunked" }
1200
- , { "Content-Type", "text/html" }
1201
- , { "Connection", "close" }
1202
- }
1203
- ,.body= ""
1204
- }
1205
-
1206
- #define NON_ASCII_IN_STATUS_LINE 10
1207
- /* Should handle non-ASCII in status line */
1208
- , {.name= "non-ASCII in status line"
1209
- ,.type= HTTP_RESPONSE
1210
- ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n"
1211
- "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n"
1212
- "Content-Length: 0\r\n"
1213
- "Connection: close\r\n"
1214
- "\r\n"
1215
- ,.should_keep_alive= FALSE
1216
- ,.message_complete_on_eof= FALSE
1217
- ,.http_major= 1
1218
- ,.http_minor= 1
1219
- ,.status_code= 500
1220
- ,.num_headers= 3
1221
- ,.headers=
1222
- { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
1223
- , { "Content-Length", "0" }
1224
- , { "Connection", "close" }
1225
- }
1226
- ,.body= ""
1227
- }
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 */
1412
-
1413
- , {.name= NULL } /* sentinel */
1414
- };
1415
-
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)
1421
- {
1422
- const char *p;
1423
-
1424
- p = memchr(s, '\0', maxlen);
1425
- if (p == NULL)
1426
- return maxlen;
1427
-
1428
- return p - s;
1429
- }
1430
-
1431
- size_t
1432
- strlncat(char *dst, size_t len, const char *src, size_t n)
1433
- {
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);
1481
- }
1482
-
1483
- int
1484
- request_url_cb (http_parser *p, const char *buf, size_t len)
1485
- {
1486
- assert(p == parser);
1487
- strlncat(messages[num_messages].request_url,
1488
- sizeof(messages[num_messages].request_url),
1489
- buf,
1490
- len);
1491
- return 0;
1492
- }
1493
-
1494
- int
1495
- status_complete_cb (http_parser *p) {
1496
- assert(p == parser);
1497
- p->data++;
1498
- return 0;
1499
- }
1500
-
1501
- int
1502
- header_field_cb (http_parser *p, const char *buf, size_t len)
1503
- {
1504
- assert(p == parser);
1505
- struct message *m = &messages[num_messages];
1506
-
1507
- if (m->last_header_element != FIELD)
1508
- m->num_headers++;
1509
-
1510
- strlncat(m->headers[m->num_headers-1][0],
1511
- sizeof(m->headers[m->num_headers-1][0]),
1512
- buf,
1513
- len);
1514
-
1515
- m->last_header_element = FIELD;
1516
-
1517
- return 0;
1518
- }
1519
-
1520
- int
1521
- header_value_cb (http_parser *p, const char *buf, size_t len)
1522
- {
1523
- assert(p == parser);
1524
- struct message *m = &messages[num_messages];
1525
-
1526
- strlncat(m->headers[m->num_headers-1][1],
1527
- sizeof(m->headers[m->num_headers-1][1]),
1528
- buf,
1529
- len);
1530
-
1531
- m->last_header_element = VALUE;
1532
-
1533
- return 0;
1534
- }
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
-
1549
- int
1550
- body_cb (http_parser *p, const char *buf, size_t len)
1551
- {
1552
- assert(p == parser);
1553
- strlncat(messages[num_messages].body,
1554
- sizeof(messages[num_messages].body),
1555
- buf,
1556
- len);
1557
- messages[num_messages].body_size += len;
1558
- check_body_is_final(p);
1559
- // printf("body_cb: '%s'\n", requests[num_messages].body);
1560
- return 0;
1561
- }
1562
-
1563
- int
1564
- count_body_cb (http_parser *p, const char *buf, size_t len)
1565
- {
1566
- assert(p == parser);
1567
- assert(buf);
1568
- messages[num_messages].body_size += len;
1569
- check_body_is_final(p);
1570
- return 0;
1571
- }
1572
-
1573
- int
1574
- message_begin_cb (http_parser *p)
1575
- {
1576
- assert(p == parser);
1577
- messages[num_messages].message_begin_cb_called = TRUE;
1578
- return 0;
1579
- }
1580
-
1581
- int
1582
- headers_complete_cb (http_parser *p)
1583
- {
1584
- assert(p == parser);
1585
- messages[num_messages].method = parser->method;
1586
- messages[num_messages].status_code = parser->status_code;
1587
- messages[num_messages].http_major = parser->http_major;
1588
- messages[num_messages].http_minor = parser->http_minor;
1589
- messages[num_messages].headers_complete_cb_called = TRUE;
1590
- messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
1591
- return 0;
1592
- }
1593
-
1594
- int
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)
1734
- {
1735
- http_parser_pause(p, 1);
1736
- *current_pause_parser = settings_dontcall;
1737
- return body_cb(p, buf, len);
1738
- }
1739
-
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
- }
1747
-
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);
1754
- }
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
-
1766
- static http_parser_settings settings =
1767
- {.on_message_begin = message_begin_cb
1768
- ,.on_header_field = header_field_cb
1769
- ,.on_header_value = header_value_cb
1770
- ,.on_url = request_url_cb
1771
- ,.on_body = body_cb
1772
- ,.on_headers_complete = headers_complete_cb
1773
- ,.on_message_complete = message_complete_cb
1774
- };
1775
-
1776
- static http_parser_settings settings_count_body =
1777
- {.on_message_begin = message_begin_cb
1778
- ,.on_header_field = header_field_cb
1779
- ,.on_header_value = header_value_cb
1780
- ,.on_url = request_url_cb
1781
- ,.on_body = count_body_cb
1782
- ,.on_headers_complete = headers_complete_cb
1783
- ,.on_message_complete = message_complete_cb
1784
- };
1785
-
1786
- static http_parser_settings settings_null =
1787
- {.on_message_begin = 0
1788
- ,.on_header_field = 0
1789
- ,.on_header_value = 0
1790
- ,.on_url = 0
1791
- ,.on_body = 0
1792
- ,.on_headers_complete = 0
1793
- ,.on_message_complete = 0
1794
- };
1795
-
1796
- void
1797
- parser_init (enum http_parser_type type)
1798
- {
1799
- num_messages = 0;
1800
-
1801
- assert(parser == NULL);
1802
-
1803
- parser = malloc(sizeof(http_parser));
1804
-
1805
- http_parser_init(parser, type);
1806
-
1807
- memset(&messages, 0, sizeof messages);
1808
-
1809
- }
1810
-
1811
- void
1812
- parser_free ()
1813
- {
1814
- assert(parser);
1815
- free(parser);
1816
- parser = NULL;
1817
- }
1818
-
1819
- size_t parse (const char *buf, size_t len)
1820
- {
1821
- size_t nparsed;
1822
- currently_parsing_eof = (len == 0);
1823
- nparsed = http_parser_execute(parser, &settings, buf, len);
1824
- return nparsed;
1825
- }
1826
-
1827
- size_t parse_count_body (const char *buf, size_t len)
1828
- {
1829
- size_t nparsed;
1830
- currently_parsing_eof = (len == 0);
1831
- nparsed = http_parser_execute(parser, &settings_count_body, buf, len);
1832
- return nparsed;
1833
- }
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
-
1846
- static inline int
1847
- check_str_eq (const struct message *m,
1848
- const char *prop,
1849
- const char *expected,
1850
- const char *found) {
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)) {
1858
- printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1859
- printf("expected '%s'\n", expected);
1860
- printf(" found '%s'\n", found);
1861
- return 0;
1862
- }
1863
- return 1;
1864
- }
1865
-
1866
- static inline int
1867
- check_num_eq (const struct message *m,
1868
- const char *prop,
1869
- int expected,
1870
- int found) {
1871
- if (expected != found) {
1872
- printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name);
1873
- printf("expected %d\n", expected);
1874
- printf(" found %d\n", found);
1875
- return 0;
1876
- }
1877
- return 1;
1878
- }
1879
-
1880
- #define MESSAGE_CHECK_STR_EQ(expected, found, prop) \
1881
- if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0
1882
-
1883
- #define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \
1884
- if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0
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)
1900
-
1901
- int
1902
- message_eq (int index, const struct message *expected)
1903
- {
1904
- int i;
1905
- struct message *m = &messages[index];
1906
-
1907
- MESSAGE_CHECK_NUM_EQ(expected, m, http_major);
1908
- MESSAGE_CHECK_NUM_EQ(expected, m, http_minor);
1909
-
1910
- if (expected->type == HTTP_REQUEST) {
1911
- MESSAGE_CHECK_NUM_EQ(expected, m, method);
1912
- } else {
1913
- MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
1914
- }
1915
-
1916
- MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
1917
- MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof);
1918
-
1919
- assert(m->message_begin_cb_called);
1920
- assert(m->headers_complete_cb_called);
1921
- assert(m->message_complete_cb_called);
1922
-
1923
-
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
-
1955
- if (expected->body_size) {
1956
- MESSAGE_CHECK_NUM_EQ(expected, m, body_size);
1957
- } else {
1958
- MESSAGE_CHECK_STR_EQ(expected, m, body);
1959
- }
1960
-
1961
- MESSAGE_CHECK_NUM_EQ(expected, m, num_headers);
1962
-
1963
- int r;
1964
- for (i = 0; i < m->num_headers; i++) {
1965
- r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]);
1966
- if (!r) return 0;
1967
- r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]);
1968
- if (!r) return 0;
1969
- }
1970
-
1971
- MESSAGE_CHECK_STR_EQ(expected, m, upgrade);
1972
-
1973
- return 1;
1974
- }
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
-
2040
- static void
2041
- print_error (const char *raw, size_t error_location)
2042
- {
2043
- fprintf(stderr, "\n*** %s ***\n\n",
2044
- http_errno_description(HTTP_PARSER_ERRNO(parser)));
2045
-
2046
- int this_line = 0, char_len = 0;
2047
- size_t i, j, len = strlen(raw), error_location_line = 0;
2048
- for (i = 0; i < len; i++) {
2049
- if (i == error_location) this_line = 1;
2050
- switch (raw[i]) {
2051
- case '\r':
2052
- char_len = 2;
2053
- fprintf(stderr, "\\r");
2054
- break;
2055
-
2056
- case '\n':
2057
- char_len = 2;
2058
- fprintf(stderr, "\\n\n");
2059
-
2060
- if (this_line) goto print;
2061
-
2062
- error_location_line = 0;
2063
- continue;
2064
-
2065
- default:
2066
- char_len = 1;
2067
- fputc(raw[i], stderr);
2068
- break;
2069
- }
2070
- if (!this_line) error_location_line += char_len;
2071
- }
2072
-
2073
- fprintf(stderr, "[eof]\n");
2074
-
2075
- print:
2076
- for (j = 0; j < error_location_line; j++) {
2077
- fputc(' ', stderr);
2078
- }
2079
- fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location);
2080
- }
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
- }
2658
-
2659
- void
2660
- test_message (const struct message *message)
2661
- {
2662
- size_t raw_len = strlen(message->raw);
2663
- size_t msg1len;
2664
- for (msg1len = 0; msg1len < raw_len; msg1len++) {
2665
- parser_init(message->type);
2666
-
2667
- size_t read;
2668
- const char *msg1 = message->raw;
2669
- const char *msg2 = msg1 + msg1len;
2670
- size_t msg2len = raw_len - msg1len;
2671
-
2672
- if (msg1len) {
2673
- read = parse(msg1, msg1len);
2674
-
2675
- if (message->upgrade && parser->upgrade) {
2676
- messages[num_messages - 1].upgrade = msg1 + read;
2677
- goto test;
2678
- }
2679
-
2680
- if (read != msg1len) {
2681
- print_error(msg1, read);
2682
- abort();
2683
- }
2684
- }
2685
-
2686
-
2687
- read = parse(msg2, msg2len);
2688
-
2689
- if (message->upgrade && parser->upgrade) {
2690
- messages[num_messages - 1].upgrade = msg2 + read;
2691
- goto test;
2692
- }
2693
-
2694
- if (read != msg2len) {
2695
- print_error(msg2, read);
2696
- abort();
2697
- }
2698
-
2699
- read = parse(NULL, 0);
2700
-
2701
- if (read != 0) {
2702
- print_error(message->raw, read);
2703
- abort();
2704
- }
2705
-
2706
- test:
2707
-
2708
- if (num_messages != 1) {
2709
- printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
2710
- abort();
2711
- }
2712
-
2713
- if(!message_eq(0, message)) abort();
2714
-
2715
- parser_free();
2716
- }
2717
- }
2718
-
2719
- void
2720
- test_message_count_body (const struct message *message)
2721
- {
2722
- parser_init(message->type);
2723
-
2724
- size_t read;
2725
- size_t l = strlen(message->raw);
2726
- size_t i, toread;
2727
- size_t chunk = 4024;
2728
-
2729
- for (i = 0; i < l; i+= chunk) {
2730
- toread = MIN(l-i, chunk);
2731
- read = parse_count_body(message->raw + i, toread);
2732
- if (read != toread) {
2733
- print_error(message->raw, read);
2734
- abort();
2735
- }
2736
- }
2737
-
2738
-
2739
- read = parse_count_body(NULL, 0);
2740
- if (read != 0) {
2741
- print_error(message->raw, read);
2742
- abort();
2743
- }
2744
-
2745
- if (num_messages != 1) {
2746
- printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name);
2747
- abort();
2748
- }
2749
-
2750
- if(!message_eq(0, message)) abort();
2751
-
2752
- parser_free();
2753
- }
2754
-
2755
- void
2756
- test_simple (const char *buf, enum http_errno err_expected)
2757
- {
2758
- parser_init(HTTP_REQUEST);
2759
-
2760
- size_t parsed;
2761
- int pass;
2762
- enum http_errno err;
2763
-
2764
- parsed = parse(buf, strlen(buf));
2765
- pass = (parsed == strlen(buf));
2766
- err = HTTP_PARSER_ERRNO(parser);
2767
- parsed = parse(NULL, 0);
2768
- pass &= (parsed == 0);
2769
-
2770
- parser_free();
2771
-
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();
2783
- }
2784
- }
2785
-
2786
- void
2787
- test_header_overflow_error (int req)
2788
- {
2789
- http_parser parser;
2790
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
2791
- size_t parsed;
2792
- const char *buf;
2793
- buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n";
2794
- parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
2795
- assert(parsed == strlen(buf));
2796
-
2797
- buf = "header-key: header-value\r\n";
2798
- size_t buflen = strlen(buf);
2799
-
2800
- int i;
2801
- for (i = 0; i < 10000; i++) {
2802
- parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
2803
- if (parsed != buflen) {
2804
- //fprintf(stderr, "error found on iter %d\n", i);
2805
- assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW);
2806
- return;
2807
- }
2808
- }
2809
-
2810
- fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n");
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 */
2859
- }
2860
-
2861
- void
2862
- test_no_overflow_long_body (int req, size_t length)
2863
- {
2864
- http_parser parser;
2865
- http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
2866
- size_t parsed;
2867
- size_t i;
2868
- char buf1[3000];
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);
2871
- parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
2872
- if (parsed != buf1len)
2873
- goto err;
2874
-
2875
- for (i = 0; i < length; i++) {
2876
- char foo = 'a';
2877
- parsed = http_parser_execute(&parser, &settings_null, &foo, 1);
2878
- if (parsed != 1)
2879
- goto err;
2880
- }
2881
-
2882
- parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
2883
- if (parsed != buf1len) goto err;
2884
- return;
2885
-
2886
- err:
2887
- fprintf(stderr,
2888
- "\n*** error in test_no_overflow_long_body %s of length %lu ***\n",
2889
- req ? "REQUEST" : "RESPONSE",
2890
- (unsigned long)length);
2891
- abort();
2892
- }
2893
-
2894
- void
2895
- test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
2896
- {
2897
- int message_count = count_parsed_messages(3, r1, r2, r3);
2898
-
2899
- char total[ strlen(r1->raw)
2900
- + strlen(r2->raw)
2901
- + strlen(r3->raw)
2902
- + 1
2903
- ];
2904
- total[0] = '\0';
2905
-
2906
- strcat(total, r1->raw);
2907
- strcat(total, r2->raw);
2908
- strcat(total, r3->raw);
2909
-
2910
- parser_init(r1->type);
2911
-
2912
- size_t read;
2913
-
2914
- read = parse(total, strlen(total));
2915
-
2916
- if (parser->upgrade) {
2917
- upgrade_message_fix(total, read, 3, r1, r2, r3);
2918
- goto test;
2919
- }
2920
-
2921
- if (read != strlen(total)) {
2922
- print_error(total, read);
2923
- abort();
2924
- }
2925
-
2926
- read = parse(NULL, 0);
2927
-
2928
- if (read != 0) {
2929
- print_error(total, read);
2930
- abort();
2931
- }
2932
-
2933
- test:
2934
-
2935
- if (message_count != num_messages) {
2936
- fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages);
2937
- abort();
2938
- }
2939
-
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();
2943
-
2944
- parser_free();
2945
- }
2946
-
2947
- /* SCAN through every possible breaking to make sure the
2948
- * parser can handle getting the content in any chunks that
2949
- * might come from the socket
2950
- */
2951
- void
2952
- test_scan (const struct message *r1, const struct message *r2, const struct message *r3)
2953
- {
2954
- char total[80*1024] = "\0";
2955
- char buf1[80*1024] = "\0";
2956
- char buf2[80*1024] = "\0";
2957
- char buf3[80*1024] = "\0";
2958
-
2959
- strcat(total, r1->raw);
2960
- strcat(total, r2->raw);
2961
- strcat(total, r3->raw);
2962
-
2963
- size_t read;
2964
-
2965
- int total_len = strlen(total);
2966
-
2967
- int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2;
2968
- int ops = 0 ;
2969
-
2970
- size_t buf1_len, buf2_len, buf3_len;
2971
- int message_count = count_parsed_messages(3, r1, r2, r3);
2972
-
2973
- int i,j,type_both;
2974
- for (type_both = 0; type_both < 2; type_both ++ ) {
2975
- for (j = 2; j < total_len; j ++ ) {
2976
- for (i = 1; i < j; i ++ ) {
2977
-
2978
- if (ops % 1000 == 0) {
2979
- printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops);
2980
- fflush(stdout);
2981
- }
2982
- ops += 1;
2983
-
2984
- parser_init(type_both ? HTTP_BOTH : r1->type);
2985
-
2986
- buf1_len = i;
2987
- strlncpy(buf1, sizeof(buf1), total, buf1_len);
2988
- buf1[buf1_len] = 0;
2989
-
2990
- buf2_len = j - i;
2991
- strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
2992
- buf2[buf2_len] = 0;
2993
-
2994
- buf3_len = total_len - j;
2995
- strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
2996
- buf3[buf3_len] = 0;
2997
-
2998
- read = parse(buf1, buf1_len);
2999
-
3000
- if (parser->upgrade) goto test;
3001
-
3002
- if (read != buf1_len) {
3003
- print_error(buf1, read);
3004
- goto error;
3005
- }
3006
-
3007
- read += parse(buf2, buf2_len);
3008
-
3009
- if (parser->upgrade) goto test;
3010
-
3011
- if (read != buf1_len + buf2_len) {
3012
- print_error(buf2, read);
3013
- goto error;
3014
- }
3015
-
3016
- read += parse(buf3, buf3_len);
3017
-
3018
- if (parser->upgrade) goto test;
3019
-
3020
- if (read != buf1_len + buf2_len + buf3_len) {
3021
- print_error(buf3, read);
3022
- goto error;
3023
- }
3024
-
3025
- parse(NULL, 0);
3026
-
3027
- test:
3028
- if (parser->upgrade) {
3029
- upgrade_message_fix(total, read, 3, r1, r2, r3);
3030
- }
3031
-
3032
- if (message_count != num_messages) {
3033
- fprintf(stderr, "\n\nParser didn't see %d messages only %d\n",
3034
- message_count, num_messages);
3035
- goto error;
3036
- }
3037
-
3038
- if (!message_eq(0, r1)) {
3039
- fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n");
3040
- goto error;
3041
- }
3042
-
3043
- if (message_count > 1 && !message_eq(1, r2)) {
3044
- fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n");
3045
- goto error;
3046
- }
3047
-
3048
- if (message_count > 2 && !message_eq(2, r3)) {
3049
- fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
3050
- goto error;
3051
- }
3052
-
3053
- parser_free();
3054
- }
3055
- }
3056
- }
3057
- puts("\b\b\b\b100%");
3058
- return;
3059
-
3060
- error:
3061
- fprintf(stderr, "i=%d j=%d\n", i, j);
3062
- fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1);
3063
- fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2);
3064
- fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3);
3065
- abort();
3066
- }
3067
-
3068
- // user required to free the result
3069
- // string terminated by \0
3070
- char *
3071
- create_large_chunked_message (int body_size_in_kb, const char* headers)
3072
- {
3073
- int i;
3074
- size_t wrote = 0;
3075
- size_t headers_len = strlen(headers);
3076
- size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6;
3077
- char * buf = malloc(bufsize);
3078
-
3079
- memcpy(buf, headers, headers_len);
3080
- wrote += headers_len;
3081
-
3082
- for (i = 0; i < body_size_in_kb; i++) {
3083
- // write 1kb chunk into the body.
3084
- memcpy(buf + wrote, "400\r\n", 5);
3085
- wrote += 5;
3086
- memset(buf + wrote, 'C', 1024);
3087
- wrote += 1024;
3088
- strcpy(buf + wrote, "\r\n");
3089
- wrote += 2;
3090
- }
3091
-
3092
- memcpy(buf + wrote, "0\r\n\r\n", 6);
3093
- wrote += 6;
3094
- assert(wrote == bufsize);
3095
-
3096
- return buf;
3097
- }
3098
-
3099
- void
3100
- test_status_complete (void)
3101
- {
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
3111
- }
3112
-
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)
3117
- {
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();
3159
- }
3160
-
3161
- if(!message_eq(0, msg)) abort();
3162
-
3163
- parser_free();
3164
- }
3165
-
3166
- int
3167
- main (void)
3168
- {
3169
- parser = NULL;
3170
- int i, j, k;
3171
- int request_count;
3172
- int response_count;
3173
-
3174
- printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
3175
-
3176
- for (request_count = 0; requests[request_count].name; request_count++);
3177
- for (response_count = 0; responses[response_count].name; response_count++);
3178
-
3179
- //// API
3180
- test_preserve_data();
3181
- test_parse_url();
3182
- test_method_str();
3183
-
3184
- //// OVERFLOW CONDITIONS
3185
-
3186
- test_header_overflow_error(HTTP_REQUEST);
3187
- test_no_overflow_long_body(HTTP_REQUEST, 1000);
3188
- test_no_overflow_long_body(HTTP_REQUEST, 100000);
3189
-
3190
- test_header_overflow_error(HTTP_RESPONSE);
3191
- test_no_overflow_long_body(HTTP_RESPONSE, 1000);
3192
- test_no_overflow_long_body(HTTP_RESPONSE, 100000);
3193
-
3194
- test_header_content_length_overflow_error();
3195
- test_chunk_content_length_overflow_error();
3196
-
3197
- //// RESPONSES
3198
-
3199
- for (i = 0; i < response_count; i++) {
3200
- test_message(&responses[i]);
3201
- }
3202
-
3203
- for (i = 0; i < response_count; i++) {
3204
- test_message_pause(&responses[i]);
3205
- }
3206
-
3207
- for (i = 0; i < response_count; i++) {
3208
- if (!responses[i].should_keep_alive) continue;
3209
- for (j = 0; j < response_count; j++) {
3210
- if (!responses[j].should_keep_alive) continue;
3211
- for (k = 0; k < response_count; k++) {
3212
- test_multiple3(&responses[i], &responses[j], &responses[k]);
3213
- }
3214
- }
3215
- }
3216
-
3217
- test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]);
3218
- test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]);
3219
-
3220
- // test very large chunked response
3221
- {
3222
- char * msg = create_large_chunked_message(31337,
3223
- "HTTP/1.0 200 OK\r\n"
3224
- "Transfer-Encoding: chunked\r\n"
3225
- "Content-Type: text/plain\r\n"
3226
- "\r\n");
3227
- struct message large_chunked =
3228
- {.name= "large chunked"
3229
- ,.type= HTTP_RESPONSE
3230
- ,.raw= msg
3231
- ,.should_keep_alive= FALSE
3232
- ,.message_complete_on_eof= FALSE
3233
- ,.http_major= 1
3234
- ,.http_minor= 0
3235
- ,.status_code= 200
3236
- ,.num_headers= 2
3237
- ,.headers=
3238
- { { "Transfer-Encoding", "chunked" }
3239
- , { "Content-Type", "text/plain" }
3240
- }
3241
- ,.body_size= 31337*1024
3242
- };
3243
- test_message_count_body(&large_chunked);
3244
- free(msg);
3245
- }
3246
-
3247
-
3248
-
3249
- printf("response scan 1/2 ");
3250
- test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY]
3251
- , &responses[NO_BODY_HTTP10_KA_204]
3252
- , &responses[NO_REASON_PHRASE]
3253
- );
3254
-
3255
- printf("response scan 2/2 ");
3256
- test_scan( &responses[BONJOUR_MADAME_FR]
3257
- , &responses[UNDERSTORE_HEADER_KEY]
3258
- , &responses[NO_CARRIAGE_RET]
3259
- );
3260
-
3261
- puts("responses okay");
3262
-
3263
-
3264
- /// REQUESTS
3265
-
3266
- test_simple("hello world", HPE_INVALID_METHOD);
3267
- test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
3268
-
3269
-
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);
3273
-
3274
- // Well-formed but incomplete
3275
- test_simple("GET / HTTP/1.1\r\n"
3276
- "Content-Type: text/plain\r\n"
3277
- "Content-Length: 6\r\n"
3278
- "\r\n"
3279
- "fooba",
3280
- HPE_OK);
3281
-
3282
- static const char *all_methods[] = {
3283
- "DELETE",
3284
- "GET",
3285
- "HEAD",
3286
- "POST",
3287
- "PUT",
3288
- //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel
3289
- "OPTIONS",
3290
- "TRACE",
3291
- "COPY",
3292
- "LOCK",
3293
- "MKCOL",
3294
- "MOVE",
3295
- "PROPFIND",
3296
- "PROPPATCH",
3297
- "UNLOCK",
3298
- "REPORT",
3299
- "MKACTIVITY",
3300
- "CHECKOUT",
3301
- "MERGE",
3302
- "M-SEARCH",
3303
- "NOTIFY",
3304
- "SUBSCRIBE",
3305
- "UNSUBSCRIBE",
3306
- "PATCH",
3307
- 0 };
3308
- const char **this_method;
3309
- for (this_method = all_methods; *this_method; this_method++) {
3310
- char buf[200];
3311
- sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method);
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);
3323
- }
3324
-
3325
- const char *dumbfuck2 =
3326
- "GET / HTTP/1.1\r\n"
3327
- "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
3328
- "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
3329
- "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
3330
- "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
3331
- "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n"
3332
- "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n"
3333
- "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n"
3334
- "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n"
3335
- "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n"
3336
- "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n"
3337
- "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n"
3338
- "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n"
3339
- "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n"
3340
- "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n"
3341
- "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n"
3342
- "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n"
3343
- "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n"
3344
- "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n"
3345
- "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n"
3346
- "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n"
3347
- "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n"
3348
- "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n"
3349
- "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n"
3350
- "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n"
3351
- "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n"
3352
- "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n"
3353
- "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n"
3354
- "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n"
3355
- "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n"
3356
- "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n"
3357
- "\tRA==\r\n"
3358
- "\t-----END CERTIFICATE-----\r\n"
3359
- "\r\n";
3360
- test_simple(dumbfuck2, HPE_OK);
3361
-
3362
- #if 0
3363
- // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body
3364
- // until EOF.
3365
- //
3366
- // no content-length
3367
- // error if there is a body without content length
3368
- const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n"
3369
- "Accept: */*\r\n"
3370
- "\r\n"
3371
- "HELLO";
3372
- test_simple(bad_get_no_headers_no_body, 0);
3373
- #endif
3374
- /* TODO sending junk and large headers gets rejected */
3375
-
3376
-
3377
- /* check to make sure our predefined requests are okay */
3378
- for (i = 0; requests[i].name; i++) {
3379
- test_message(&requests[i]);
3380
- }
3381
-
3382
- for (i = 0; i < request_count; i++) {
3383
- test_message_pause(&requests[i]);
3384
- }
3385
-
3386
- for (i = 0; i < request_count; i++) {
3387
- if (!requests[i].should_keep_alive) continue;
3388
- for (j = 0; j < request_count; j++) {
3389
- if (!requests[j].should_keep_alive) continue;
3390
- for (k = 0; k < request_count; k++) {
3391
- test_multiple3(&requests[i], &requests[j], &requests[k]);
3392
- }
3393
- }
3394
- }
3395
-
3396
- printf("request scan 1/4 ");
3397
- test_scan( &requests[GET_NO_HEADERS_NO_BODY]
3398
- , &requests[GET_ONE_HEADER_NO_BODY]
3399
- , &requests[GET_NO_HEADERS_NO_BODY]
3400
- );
3401
-
3402
- printf("request scan 2/4 ");
3403
- test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE]
3404
- , &requests[POST_IDENTITY_BODY_WORLD]
3405
- , &requests[GET_FUNKY_CONTENT_LENGTH]
3406
- );
3407
-
3408
- printf("request scan 3/4 ");
3409
- test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
3410
- , &requests[CHUNKED_W_TRAILING_HEADERS]
3411
- , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
3412
- );
3413
-
3414
- printf("request scan 4/4 ");
3415
- test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET]
3416
- , &requests[PREFIX_NEWLINE_GET ]
3417
- , &requests[CONNECT_REQUEST]
3418
- );
3419
-
3420
- test_status_complete();
3421
-
3422
- puts("requests okay");
3423
-
3424
- return 0;
3425
- }