yakischloba-http-parser 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/src/test.c ADDED
@@ -0,0 +1,785 @@
1
+ #include "http_parser.h"
2
+ #include <stdlib.h>
3
+ #include <assert.h>
4
+ #include <stdio.h>
5
+ #include <string.h>
6
+ #include <stdarg.h>
7
+
8
+ #undef TRUE
9
+ #define TRUE 1
10
+ #undef FALSE
11
+ #define FALSE 0
12
+
13
+ #define MAX_HEADERS 10
14
+ #define MAX_ELEMENT_SIZE 500
15
+
16
+ static http_parser parser;
17
+ struct message {
18
+ const char *name; // for debugging purposes
19
+ const char *raw;
20
+ enum http_parser_type type;
21
+ int method;
22
+ int status_code;
23
+ char request_path[MAX_ELEMENT_SIZE];
24
+ char request_uri[MAX_ELEMENT_SIZE];
25
+ char fragment[MAX_ELEMENT_SIZE];
26
+ char query_string[MAX_ELEMENT_SIZE];
27
+ char body[MAX_ELEMENT_SIZE];
28
+ int num_headers;
29
+ enum { NONE=0, FIELD, VALUE } last_header_element;
30
+ char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE];
31
+ int should_keep_alive;
32
+
33
+ int message_begin_cb_called;
34
+ int headers_complete_cb_called;
35
+ int message_complete_cb_called;
36
+ };
37
+
38
+ static struct message messages[5];
39
+ static int num_messages;
40
+
41
+ /* * R E Q U E S T S * */
42
+ const struct message requests[] =
43
+ #define CURL_GET 0
44
+ { {.name= "curl get"
45
+ ,.type= HTTP_REQUEST
46
+ ,.raw= "GET /test HTTP/1.1\r\n"
47
+ "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"
48
+ "Host: 0.0.0.0=5000\r\n"
49
+ "Accept: */*\r\n"
50
+ "\r\n"
51
+ ,.should_keep_alive= TRUE
52
+ ,.method= HTTP_GET
53
+ ,.query_string= ""
54
+ ,.fragment= ""
55
+ ,.request_path= "/test"
56
+ ,.request_uri= "/test"
57
+ ,.num_headers= 3
58
+ ,.headers=
59
+ { { "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" }
60
+ , { "Host", "0.0.0.0=5000" }
61
+ , { "Accept", "*/*" }
62
+ }
63
+ ,.body= ""
64
+ }
65
+
66
+ #define FIREFOX_GET 1
67
+ , {.name= "firefox get"
68
+ ,.type= HTTP_REQUEST
69
+ ,.raw= "GET /favicon.ico HTTP/1.1\r\n"
70
+ "Host: 0.0.0.0=5000\r\n"
71
+ "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n"
72
+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
73
+ "Accept-Language: en-us,en;q=0.5\r\n"
74
+ "Accept-Encoding: gzip,deflate\r\n"
75
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
76
+ "Keep-Alive: 300\r\n"
77
+ "Connection: keep-alive\r\n"
78
+ "\r\n"
79
+ ,.should_keep_alive= TRUE
80
+ ,.method= HTTP_GET
81
+ ,.query_string= ""
82
+ ,.fragment= ""
83
+ ,.request_path= "/favicon.ico"
84
+ ,.request_uri= "/favicon.ico"
85
+ ,.num_headers= 8
86
+ ,.headers=
87
+ { { "Host", "0.0.0.0=5000" }
88
+ , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" }
89
+ , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }
90
+ , { "Accept-Language", "en-us,en;q=0.5" }
91
+ , { "Accept-Encoding", "gzip,deflate" }
92
+ , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" }
93
+ , { "Keep-Alive", "300" }
94
+ , { "Connection", "keep-alive" }
95
+ }
96
+ ,.body= ""
97
+ }
98
+
99
+ #define DUMBFUCK 2
100
+ , {.name= "dumbfuck"
101
+ ,.type= HTTP_REQUEST
102
+ ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
103
+ "aaaaaaaaaaaaa:++++++++++\r\n"
104
+ "\r\n"
105
+ ,.should_keep_alive= TRUE
106
+ ,.method= HTTP_GET
107
+ ,.query_string= ""
108
+ ,.fragment= ""
109
+ ,.request_path= "/dumbfuck"
110
+ ,.request_uri= "/dumbfuck"
111
+ ,.num_headers= 1
112
+ ,.headers=
113
+ { { "aaaaaaaaaaaaa", "++++++++++" }
114
+ }
115
+ ,.body= ""
116
+ }
117
+
118
+ #define FRAGMENT_IN_URI 3
119
+ , {.name= "fragment in uri"
120
+ ,.type= HTTP_REQUEST
121
+ ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n"
122
+ "\r\n"
123
+ ,.should_keep_alive= TRUE
124
+ ,.method= HTTP_GET
125
+ ,.query_string= "page=1"
126
+ ,.fragment= "posts-17408"
127
+ ,.request_path= "/forums/1/topics/2375"
128
+ /* XXX request uri does not include fragment? */
129
+ ,.request_uri= "/forums/1/topics/2375?page=1"
130
+ ,.num_headers= 0
131
+ ,.body= ""
132
+ }
133
+
134
+ #define GET_NO_HEADERS_NO_BODY 4
135
+ , {.name= "get no headers no body"
136
+ ,.type= HTTP_REQUEST
137
+ ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n"
138
+ "\r\n"
139
+ ,.should_keep_alive= TRUE
140
+ ,.method= HTTP_GET
141
+ ,.query_string= ""
142
+ ,.fragment= ""
143
+ ,.request_path= "/get_no_headers_no_body/world"
144
+ ,.request_uri= "/get_no_headers_no_body/world"
145
+ ,.num_headers= 0
146
+ ,.body= ""
147
+ }
148
+
149
+ #define GET_ONE_HEADER_NO_BODY 5
150
+ , {.name= "get one header no body"
151
+ ,.type= HTTP_REQUEST
152
+ ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n"
153
+ "Accept: */*\r\n"
154
+ "\r\n"
155
+ ,.should_keep_alive= TRUE
156
+ ,.method= HTTP_GET
157
+ ,.query_string= ""
158
+ ,.fragment= ""
159
+ ,.request_path= "/get_one_header_no_body"
160
+ ,.request_uri= "/get_one_header_no_body"
161
+ ,.num_headers= 1
162
+ ,.headers=
163
+ { { "Accept" , "*/*" }
164
+ }
165
+ ,.body= ""
166
+ }
167
+
168
+ #define GET_FUNKY_CONTENT_LENGTH 6
169
+ , {.name= "get funky content length body hello"
170
+ ,.type= HTTP_REQUEST
171
+ ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n"
172
+ "conTENT-Length: 5\r\n"
173
+ "\r\n"
174
+ "HELLO"
175
+ ,.should_keep_alive= FALSE
176
+ ,.method= HTTP_GET
177
+ ,.query_string= ""
178
+ ,.fragment= ""
179
+ ,.request_path= "/get_funky_content_length_body_hello"
180
+ ,.request_uri= "/get_funky_content_length_body_hello"
181
+ ,.num_headers= 1
182
+ ,.headers=
183
+ { { "conTENT-Length" , "5" }
184
+ }
185
+ ,.body= "HELLO"
186
+ }
187
+
188
+ #define POST_IDENTITY_BODY_WORLD 7
189
+ , {.name= "post identity body world"
190
+ ,.type= HTTP_REQUEST
191
+ ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
192
+ "Accept: */*\r\n"
193
+ "Transfer-Encoding: identity\r\n"
194
+ "Content-Length: 5\r\n"
195
+ "\r\n"
196
+ "World"
197
+ ,.should_keep_alive= TRUE
198
+ ,.method= HTTP_POST
199
+ ,.query_string= "q=search"
200
+ ,.fragment= "hey"
201
+ ,.request_path= "/post_identity_body_world"
202
+ ,.request_uri= "/post_identity_body_world?q=search"
203
+ ,.num_headers= 3
204
+ ,.headers=
205
+ { { "Accept", "*/*" }
206
+ , { "Transfer-Encoding", "identity" }
207
+ , { "Content-Length", "5" }
208
+ }
209
+ ,.body= "World"
210
+ }
211
+
212
+ #define POST_CHUNKED_ALL_YOUR_BASE 8
213
+ , {.name= "post - chunked body: all your base are belong to us"
214
+ ,.type= HTTP_REQUEST
215
+ ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n"
216
+ "Transfer-Encoding: chunked\r\n"
217
+ "\r\n"
218
+ "1e\r\nall your base are belong to us\r\n"
219
+ "0\r\n"
220
+ "\r\n"
221
+ ,.should_keep_alive= TRUE
222
+ ,.method= HTTP_POST
223
+ ,.query_string= ""
224
+ ,.fragment= ""
225
+ ,.request_path= "/post_chunked_all_your_base"
226
+ ,.request_uri= "/post_chunked_all_your_base"
227
+ ,.num_headers= 1
228
+ ,.headers=
229
+ { { "Transfer-Encoding" , "chunked" }
230
+ }
231
+ ,.body= "all your base are belong to us"
232
+ }
233
+
234
+ #define TWO_CHUNKS_MULT_ZERO_END 9
235
+ , {.name= "two chunks ; triple zero ending"
236
+ ,.type= HTTP_REQUEST
237
+ ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n"
238
+ "Transfer-Encoding: chunked\r\n"
239
+ "\r\n"
240
+ "5\r\nhello\r\n"
241
+ "6\r\n world\r\n"
242
+ "000\r\n"
243
+ "\r\n"
244
+ ,.should_keep_alive= TRUE
245
+ ,.method= HTTP_POST
246
+ ,.query_string= ""
247
+ ,.fragment= ""
248
+ ,.request_path= "/two_chunks_mult_zero_end"
249
+ ,.request_uri= "/two_chunks_mult_zero_end"
250
+ ,.num_headers= 1
251
+ ,.headers=
252
+ { { "Transfer-Encoding", "chunked" }
253
+ }
254
+ ,.body= "hello world"
255
+ }
256
+
257
+ #define CHUNKED_W_TRAILING_HEADERS 10
258
+ , {.name= "chunked with trailing headers. blech."
259
+ ,.type= HTTP_REQUEST
260
+ ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n"
261
+ "Transfer-Encoding: chunked\r\n"
262
+ "\r\n"
263
+ "5\r\nhello\r\n"
264
+ "6\r\n world\r\n"
265
+ "0\r\n"
266
+ "Vary: *\r\n"
267
+ "Content-Type: text/plain\r\n"
268
+ "\r\n"
269
+ ,.should_keep_alive= TRUE
270
+ ,.method= HTTP_POST
271
+ ,.query_string= ""
272
+ ,.fragment= ""
273
+ ,.request_path= "/chunked_w_trailing_headers"
274
+ ,.request_uri= "/chunked_w_trailing_headers"
275
+ ,.num_headers= 1
276
+ ,.headers=
277
+ { { "Transfer-Encoding", "chunked" }
278
+ }
279
+ ,.body= "hello world"
280
+ }
281
+
282
+ #define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
283
+ , {.name= "with bullshit after the length"
284
+ ,.type= HTTP_REQUEST
285
+ ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
286
+ "Transfer-Encoding: chunked\r\n"
287
+ "\r\n"
288
+ "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
289
+ "6; blahblah; blah\r\n world\r\n"
290
+ "0\r\n"
291
+ "\r\n"
292
+ ,.should_keep_alive= TRUE
293
+ ,.method= HTTP_POST
294
+ ,.query_string= ""
295
+ ,.fragment= ""
296
+ ,.request_path= "/chunked_w_bullshit_after_length"
297
+ ,.request_uri= "/chunked_w_bullshit_after_length"
298
+ ,.num_headers= 1
299
+ ,.headers=
300
+ { { "Transfer-Encoding", "chunked" }
301
+ }
302
+ ,.body= "hello world"
303
+ }
304
+
305
+ , {.name= NULL } /* sentinel */
306
+ };
307
+
308
+ /* * R E S P O N S E S * */
309
+ const struct message responses[] =
310
+ { {.name= "google 301"
311
+ ,.type= HTTP_RESPONSE
312
+ ,.raw= "HTTP/1.1 301 Moved Permanently\r\n"
313
+ "Location: http://www.google.com/\r\n"
314
+ "Content-Type: text/html; charset=UTF-8\r\n"
315
+ "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n"
316
+ "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n"
317
+ "Cache-Control: public, max-age=2592000\r\n"
318
+ "Server: gws\r\n"
319
+ "Content-Length: 219\r\n"
320
+ "\r\n"
321
+ "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
322
+ "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
323
+ "<H1>301 Moved</H1>\n"
324
+ "The document has moved\n"
325
+ "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
326
+ "</BODY></HTML>\r\n"
327
+ ,.should_keep_alive= TRUE
328
+ ,.status_code= 301
329
+ ,.num_headers= 7
330
+ ,.headers=
331
+ { { "Location", "http://www.google.com/" }
332
+ , { "Content-Type", "text/html; charset=UTF-8" }
333
+ , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" }
334
+ , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" }
335
+ , { "Cache-Control", "public, max-age=2592000" }
336
+ , { "Server", "gws" }
337
+ , { "Content-Length", "219" }
338
+ }
339
+ ,.body= "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n"
340
+ "<TITLE>301 Moved</TITLE></HEAD><BODY>\n"
341
+ "<H1>301 Moved</H1>\n"
342
+ "The document has moved\n"
343
+ "<A HREF=\"http://www.google.com/\">here</A>.\r\n"
344
+ "</BODY></HTML>\r\n"
345
+ }
346
+
347
+ , {.name= "404 no headers no body"
348
+ ,.type= HTTP_RESPONSE
349
+ ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n"
350
+ ,.should_keep_alive= TRUE
351
+ ,.status_code= 404
352
+ ,.num_headers= 0
353
+ ,.headers= {}
354
+ ,.body= ""
355
+ }
356
+
357
+ , {.name= "301 no response phrase"
358
+ ,.type= HTTP_RESPONSE
359
+ ,.raw= "HTTP/1.1 301\r\n\r\n"
360
+ ,.should_keep_alive = TRUE
361
+ ,.status_code= 301
362
+ ,.num_headers= 0
363
+ ,.headers= {}
364
+ ,.body= ""
365
+ }
366
+
367
+ , {.name= NULL } /* sentinel */
368
+ };
369
+
370
+ int
371
+ request_path_cb (http_parser *parser, const char *p, size_t len)
372
+ {
373
+ assert(parser);
374
+ strncat(messages[num_messages].request_path, p, len);
375
+ return 0;
376
+ }
377
+
378
+ int
379
+ request_uri_cb (http_parser *parser, const char *p, size_t len)
380
+ {
381
+ assert(parser);
382
+ strncat(messages[num_messages].request_uri, p, len);
383
+ return 0;
384
+ }
385
+
386
+ int
387
+ query_string_cb (http_parser *parser, const char *p, size_t len)
388
+ {
389
+ assert(parser);
390
+ strncat(messages[num_messages].query_string, p, len);
391
+ return 0;
392
+ }
393
+
394
+ int
395
+ fragment_cb (http_parser *parser, const char *p, size_t len)
396
+ {
397
+ assert(parser);
398
+ strncat(messages[num_messages].fragment, p, len);
399
+ return 0;
400
+ }
401
+
402
+ int
403
+ header_field_cb (http_parser *parser, const char *p, size_t len)
404
+ {
405
+ assert(parser);
406
+ struct message *m = &messages[num_messages];
407
+
408
+ if (m->last_header_element != FIELD)
409
+ m->num_headers++;
410
+
411
+ strncat(m->headers[m->num_headers-1][0], p, len);
412
+
413
+ m->last_header_element = FIELD;
414
+
415
+ return 0;
416
+ }
417
+
418
+ int
419
+ header_value_cb (http_parser *parser, const char *p, size_t len)
420
+ {
421
+ assert(parser);
422
+ struct message *m = &messages[num_messages];
423
+
424
+ strncat(m->headers[m->num_headers-1][1], p, len);
425
+
426
+ m->last_header_element = VALUE;
427
+
428
+ return 0;
429
+ }
430
+
431
+ int
432
+ body_cb (http_parser *parser, const char *p, size_t len)
433
+ {
434
+ assert(parser);
435
+ strncat(messages[num_messages].body, p, len);
436
+ // printf("body_cb: '%s'\n", requests[num_messages].body);
437
+ return 0;
438
+ }
439
+
440
+ int
441
+ message_complete_cb (http_parser *parser)
442
+ {
443
+ messages[num_messages].method = parser->method;
444
+ messages[num_messages].status_code = parser->status_code;
445
+
446
+ messages[num_messages].message_complete_cb_called = TRUE;
447
+
448
+ num_messages++;
449
+ return 0;
450
+ }
451
+
452
+ int
453
+ message_begin_cb (http_parser *parser)
454
+ {
455
+ assert(parser);
456
+ messages[num_messages].message_begin_cb_called = TRUE;
457
+ return 0;
458
+ }
459
+
460
+ int
461
+ headers_complete_cb (http_parser *parser)
462
+ {
463
+ assert(parser);
464
+ messages[num_messages].headers_complete_cb_called = TRUE;
465
+ return 0;
466
+ }
467
+
468
+ void
469
+ parser_init (enum http_parser_type type)
470
+ {
471
+ num_messages = 0;
472
+
473
+ http_parser_init(&parser, type);
474
+
475
+ memset(&messages, 0, sizeof messages);
476
+
477
+ parser.on_message_begin = message_begin_cb;
478
+ parser.on_header_field = header_field_cb;
479
+ parser.on_header_value = header_value_cb;
480
+ parser.on_path = request_path_cb;
481
+ parser.on_uri = request_uri_cb;
482
+ parser.on_fragment = fragment_cb;
483
+ parser.on_query_string = query_string_cb;
484
+ parser.on_body = body_cb;
485
+ parser.on_headers_complete = headers_complete_cb;
486
+ parser.on_message_complete = message_complete_cb;
487
+ }
488
+
489
+ void
490
+ message_eq (int index, const struct message *expected)
491
+ {
492
+ int i;
493
+ struct message *m = &messages[index];
494
+
495
+ assert(m->method == expected->method);
496
+ assert(m->status_code == expected->status_code);
497
+
498
+ assert(m->message_begin_cb_called);
499
+ assert(m->headers_complete_cb_called);
500
+ assert(m->message_complete_cb_called);
501
+
502
+ assert(0 == strcmp(m->body, expected->body));
503
+ assert(0 == strcmp(m->fragment, expected->fragment));
504
+ assert(0 == strcmp(m->query_string, expected->query_string));
505
+ assert(0 == strcmp(m->request_path, expected->request_path));
506
+ assert(0 == strcmp(m->request_uri, expected->request_uri));
507
+ assert(m->num_headers == expected->num_headers);
508
+ for (i = 0; i < m->num_headers; i++) {
509
+ assert(0 == strcmp(m->headers[i][0], expected->headers[i][0]));
510
+ assert(0 == strcmp(m->headers[i][1], expected->headers[i][1]));
511
+ }
512
+ }
513
+
514
+ void
515
+ parse_messages (int message_count, const struct message *input_messages[])
516
+ {
517
+ // Concat the input messages
518
+ size_t length = 0;
519
+ int i;
520
+ for (i = 0; i < message_count; i++) {
521
+ length += strlen(input_messages[i]->raw);
522
+ }
523
+ char total[length + 1];
524
+ total[0] = '\0';
525
+
526
+ for (i = 0; i < message_count; i++) {
527
+ strcat(total, input_messages[i]->raw);
528
+ }
529
+
530
+ // Parse the stream
531
+ size_t traversed = 0;
532
+ parser_init(HTTP_REQUEST);
533
+
534
+ traversed = http_parser_execute(&parser, total, length);
535
+
536
+ assert(!http_parser_has_error(&parser));
537
+ assert(num_messages == message_count);
538
+
539
+ for (i = 0; i < message_count; i++) {
540
+ message_eq(i, input_messages[i]);
541
+ }
542
+ }
543
+
544
+
545
+ void
546
+ test_message (const struct message *message)
547
+ {
548
+ size_t traversed = 0;
549
+ parser_init(message->type);
550
+
551
+ traversed = http_parser_execute(&parser, message->raw, strlen(message->raw));
552
+ assert(!http_parser_has_error(&parser));
553
+ assert(num_messages == 1);
554
+
555
+ message_eq(0, message);
556
+ }
557
+
558
+ void
559
+ test_error (const char *buf)
560
+ {
561
+ size_t traversed = 0;
562
+ parser_init(HTTP_REQUEST);
563
+
564
+ traversed = http_parser_execute(&parser, buf, strlen(buf));
565
+
566
+ assert(http_parser_has_error(&parser));
567
+ }
568
+
569
+ void
570
+ test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3)
571
+ {
572
+ char total[ strlen(r1->raw)
573
+ + strlen(r2->raw)
574
+ + strlen(r3->raw)
575
+ + 1
576
+ ];
577
+ total[0] = '\0';
578
+
579
+ strcat(total, r1->raw);
580
+ strcat(total, r2->raw);
581
+ strcat(total, r3->raw);
582
+
583
+ size_t traversed = 0;
584
+ parser_init(HTTP_REQUEST);
585
+
586
+ traversed = http_parser_execute(&parser, total, strlen(total));
587
+
588
+ assert(! http_parser_has_error(&parser) );
589
+ assert(num_messages == 3);
590
+ message_eq(0, r1);
591
+ message_eq(1, r2);
592
+ message_eq(2, r3);
593
+ }
594
+
595
+ /* SCAN through every possible breaking to make sure the
596
+ * parser can handle getting the content in any chunks that
597
+ * might come from the socket
598
+ */
599
+ void
600
+ test_scan (const struct message *r1, const struct message *r2, const struct message *r3)
601
+ {
602
+ char total[80*1024] = "\0";
603
+ char buf1[80*1024] = "\0";
604
+ char buf2[80*1024] = "\0";
605
+ char buf3[80*1024] = "\0";
606
+
607
+ strcat(total, r1->raw);
608
+ strcat(total, r2->raw);
609
+ strcat(total, r3->raw);
610
+
611
+ int total_len = strlen(total);
612
+
613
+ int total_ops = (total_len - 1) * (total_len - 2) / 2;
614
+ int ops = 0 ;
615
+
616
+ int i,j;
617
+ for (j = 2; j < total_len; j ++ ) {
618
+ for (i = 1; i < j; i ++ ) {
619
+
620
+ if (ops % 1000 == 0) {
621
+ printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops);
622
+ fflush(stdout);
623
+ }
624
+ ops += 1;
625
+
626
+ parser_init(HTTP_REQUEST);
627
+
628
+ int buf1_len = i;
629
+ strncpy(buf1, total, buf1_len);
630
+ buf1[buf1_len] = 0;
631
+
632
+ int buf2_len = j - i;
633
+ strncpy(buf2, total+i, buf2_len);
634
+ buf2[buf2_len] = 0;
635
+
636
+ int buf3_len = total_len - j;
637
+ strncpy(buf3, total+j, buf3_len);
638
+ buf3[buf3_len] = 0;
639
+
640
+ /*
641
+ printf("buf1: %s - %d\n", buf1, buf1_len);
642
+ printf("buf2: %s - %d \n", buf2, buf2_len );
643
+ printf("buf3: %s - %d\n\n", buf3, buf3_len);
644
+ */
645
+
646
+ http_parser_execute(&parser, buf1, buf1_len);
647
+
648
+ assert(!http_parser_has_error(&parser));
649
+
650
+ http_parser_execute(&parser, buf2, buf2_len);
651
+
652
+ assert(!http_parser_has_error(&parser));
653
+
654
+ http_parser_execute(&parser, buf3, buf3_len);
655
+
656
+ assert(! http_parser_has_error(&parser));
657
+
658
+ assert(3 == num_messages);
659
+
660
+ message_eq(0, r1);
661
+ message_eq(1, r2);
662
+ message_eq(2, r3);
663
+ }
664
+ }
665
+ puts("\b\b\b\b100%");
666
+ }
667
+
668
+ int
669
+ main (void)
670
+ {
671
+ int i, j, k;
672
+
673
+ printf("sizeof(http_parser) = %d\n", sizeof(http_parser));
674
+
675
+ int request_count;
676
+ for (request_count = 0; requests[request_count].name; request_count++);
677
+
678
+ int response_count;
679
+ for (response_count = 0; responses[response_count].name; response_count++);
680
+
681
+
682
+ //// RESPONSES
683
+
684
+ for (i = 0; i < response_count; i++) {
685
+ test_message(&responses[i]);
686
+ }
687
+
688
+
689
+
690
+ puts("responses okay");
691
+
692
+
693
+
694
+ /// REQUESTS
695
+
696
+
697
+ test_error("hello world");
698
+ test_error("GET / HTP/1.1\r\n\r\n");
699
+
700
+ const char *dumbfuck2 =
701
+ "GET / HTTP/1.1\r\n"
702
+ "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n"
703
+ "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
704
+ "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
705
+ "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
706
+ "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n"
707
+ "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n"
708
+ "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n"
709
+ "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n"
710
+ "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n"
711
+ "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n"
712
+ "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n"
713
+ "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n"
714
+ "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n"
715
+ "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n"
716
+ "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n"
717
+ "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n"
718
+ "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n"
719
+ "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n"
720
+ "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n"
721
+ "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n"
722
+ "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n"
723
+ "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n"
724
+ "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n"
725
+ "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n"
726
+ "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n"
727
+ "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n"
728
+ "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n"
729
+ "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n"
730
+ "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n"
731
+ "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n"
732
+ "\tRA==\r\n"
733
+ "\t-----END CERTIFICATE-----\r\n"
734
+ "\r\n";
735
+ test_error(dumbfuck2);
736
+
737
+ // no content-length
738
+ // error if there is a body without content length
739
+ const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n"
740
+ "Accept: */*\r\n"
741
+ "\r\n"
742
+ "HELLO";
743
+ test_error(bad_get_no_headers_no_body);
744
+
745
+
746
+ /* TODO sending junk and large headers gets rejected */
747
+
748
+
749
+ /* check to make sure our predefined requests are okay */
750
+ for (i = 0; requests[i].name; i++) {
751
+ test_message(&requests[i]);
752
+ }
753
+
754
+ for (i = 0; i < request_count; i++) {
755
+ for (j = 0; j < request_count; j++) {
756
+ for (k = 0; k < request_count; k++) {
757
+ //printf("%d %d %d\n", i, j, k);
758
+ test_multiple3(&requests[i], &requests[j], &requests[k]);
759
+ }
760
+ }
761
+ }
762
+
763
+ printf("request scan 1/3 ");
764
+ test_scan( &requests[GET_NO_HEADERS_NO_BODY]
765
+ , &requests[GET_ONE_HEADER_NO_BODY]
766
+ , &requests[GET_NO_HEADERS_NO_BODY]
767
+ );
768
+
769
+ printf("request scan 2/3 ");
770
+ test_scan( &requests[GET_FUNKY_CONTENT_LENGTH]
771
+ , &requests[POST_IDENTITY_BODY_WORLD]
772
+ , &requests[POST_CHUNKED_ALL_YOUR_BASE]
773
+ );
774
+
775
+ printf("request scan 3/3 ");
776
+ test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
777
+ , &requests[CHUNKED_W_TRAILING_HEADERS]
778
+ , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
779
+ );
780
+
781
+ puts("requests okay");
782
+
783
+
784
+ return 0;
785
+ }