http_parser.rb 0.5.2 → 0.7.0

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