http_parser.rb 0.6.0.beta.1 → 0.8.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 (39) 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 +2 -2
  6. data/README.md +2 -2
  7. data/Rakefile +4 -2
  8. data/ext/ruby_http_parser/extconf.rb +1 -1
  9. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +86 -52
  10. data/ext/ruby_http_parser/ruby_http_parser.c +53 -7
  11. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +37 -1
  12. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +1 -5
  13. data/ext/ruby_http_parser/vendor/http-parser/Makefile +110 -8
  14. data/ext/ruby_http_parser/vendor/http-parser/README.md +105 -37
  15. data/ext/ruby_http_parser/vendor/http-parser/bench.c +128 -0
  16. data/ext/ruby_http_parser/vendor/http-parser/contrib/parsertrace.c +157 -0
  17. data/ext/ruby_http_parser/vendor/http-parser/contrib/url_parser.c +47 -0
  18. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +892 -510
  19. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +34 -2
  20. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +198 -77
  21. data/ext/ruby_http_parser/vendor/http-parser/test.c +1781 -201
  22. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +271 -154
  23. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +48 -61
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +5 -3
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +37 -104
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +116 -101
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +9 -5
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +1 -1
  29. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +579 -153
  30. data/http_parser.rb.gemspec +14 -9
  31. data/spec/parser_spec.rb +177 -99
  32. data/spec/support/requests.json +2 -2
  33. data/spec/support/responses.json +20 -0
  34. data/tasks/spec.rake +1 -1
  35. metadata +131 -162
  36. data/Gemfile.lock +0 -39
  37. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +0 -4
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPHeadersCompleteCallback.java +0 -13
  39. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPHeadersCompleteCallback.java +0 -12
@@ -2,15 +2,16 @@ package http_parser.lolevel;
2
2
  import java.nio.ByteBuffer;
3
3
  import http_parser.HTTPException;
4
4
  public class ParserSettings {
5
-
5
+
6
6
  public HTTPCallback on_message_begin;
7
7
  public HTTPDataCallback on_path;
8
8
  public HTTPDataCallback on_query_string;
9
9
  public HTTPDataCallback on_url;
10
10
  public HTTPDataCallback on_fragment;
11
+ public HTTPCallback on_status_complete;
11
12
  public HTTPDataCallback on_header_field;
12
13
  public HTTPDataCallback on_header_value;
13
- public HTTPHeadersCompleteCallback on_headers_complete;
14
+ public HTTPCallback on_headers_complete;
14
15
  public HTTPDataCallback on_body;
15
16
  public HTTPCallback on_message_complete;
16
17
  public HTTPErrorCallback on_error;
@@ -22,7 +23,7 @@ public class ParserSettings {
22
23
  void call_on_message_complete (HTTPParser p) {
23
24
  call_on(on_message_complete, p);
24
25
  }
25
-
26
+
26
27
  // this one is a little bit different:
27
28
  // the current `position` of the buffer is the location of the
28
29
  // error, `ini_pos` indicates where the position of
@@ -35,7 +36,7 @@ public class ParserSettings {
35
36
  on_error.cb(p, mes, buf, ini_pos);
36
37
  return;
37
38
  }
38
- // if on_error gets called it MUST throw an exception, else the parser
39
+ // if on_error gets called it MUST throw an exception, else the parser
39
40
  // will attempt to continue parsing, which it can't because it's
40
41
  // in an invalid state.
41
42
  throw new HTTPException(mes);
@@ -50,6 +51,9 @@ public class ParserSettings {
50
51
  void call_on_fragment (HTTPParser p, ByteBuffer buf, int pos, int len) {
51
52
  call_on(on_fragment, p, buf, pos, len);
52
53
  }
54
+ void call_on_status_complete(HTTPParser p) {
55
+ call_on(on_status_complete, p);
56
+ }
53
57
  void call_on_path (HTTPParser p, ByteBuffer buf, int pos, int len) {
54
58
  call_on(on_path, p, buf, pos, len);
55
59
  }
@@ -64,7 +68,7 @@ public class ParserSettings {
64
68
  }
65
69
  void call_on_headers_complete(HTTPParser p) {
66
70
  call_on(on_headers_complete, p);
67
- }
71
+ }
68
72
  void call_on (HTTPCallback cb, HTTPParser p) {
69
73
  // cf. CALLBACK2 macro
70
74
  if (null != cb) {
@@ -228,7 +228,7 @@ public class Message {
228
228
  return 0;
229
229
  }
230
230
  };
231
- s.on_headers_complete = new HTTPHeadersCompleteCallback() {
231
+ s.on_headers_complete = new HTTPCallback() {
232
232
  public int cb (HTTPParser p) {
233
233
  headers_complete_called = true;
234
234
  String parsed_path = null;
@@ -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,6 +50,8 @@ 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;
53
55
  uint16_t port;
54
56
  int num_headers;
55
57
  enum { NONE=0, FIELD, VALUE } last_header_element;
@@ -65,6 +67,7 @@ struct message {
65
67
  int headers_complete_cb_called;
66
68
  int message_complete_cb_called;
67
69
  int message_complete_on_eof;
70
+ int body_is_final;
68
71
  };
69
72
 
70
73
  static int currently_parsing_eof;
@@ -587,7 +590,7 @@ const struct message requests[] =
587
590
  ,.body= ""
588
591
  }
589
592
 
590
- #define LINE_FOLDING_IN_HEADER 20
593
+ #define LINE_FOLDING_IN_HEADER 21
591
594
  , {.name= "line folding in header value"
592
595
  ,.type= HTTP_REQUEST
593
596
  ,.raw= "GET / HTTP/1.1\r\n"
@@ -616,7 +619,7 @@ const struct message requests[] =
616
619
  }
617
620
 
618
621
 
619
- #define QUERY_TERMINATED_HOST 21
622
+ #define QUERY_TERMINATED_HOST 22
620
623
  , {.name= "host terminated by a query string"
621
624
  ,.type= HTTP_REQUEST
622
625
  ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n"
@@ -630,12 +633,13 @@ const struct message requests[] =
630
633
  ,.fragment= ""
631
634
  ,.request_path= ""
632
635
  ,.request_url= "http://hypnotoad.org?hail=all"
636
+ ,.host= "hypnotoad.org"
633
637
  ,.num_headers= 0
634
638
  ,.headers= { }
635
639
  ,.body= ""
636
640
  }
637
641
 
638
- #define QUERY_TERMINATED_HOSTPORT 22
642
+ #define QUERY_TERMINATED_HOSTPORT 23
639
643
  , {.name= "host:port terminated by a query string"
640
644
  ,.type= HTTP_REQUEST
641
645
  ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n"
@@ -649,13 +653,14 @@ const struct message requests[] =
649
653
  ,.fragment= ""
650
654
  ,.request_path= ""
651
655
  ,.request_url= "http://hypnotoad.org:1234?hail=all"
656
+ ,.host= "hypnotoad.org"
652
657
  ,.port= 1234
653
658
  ,.num_headers= 0
654
659
  ,.headers= { }
655
660
  ,.body= ""
656
661
  }
657
662
 
658
- #define SPACE_TERMINATED_HOSTPORT 23
663
+ #define SPACE_TERMINATED_HOSTPORT 24
659
664
  , {.name= "host:port terminated by a space"
660
665
  ,.type= HTTP_REQUEST
661
666
  ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n"
@@ -669,13 +674,14 @@ const struct message requests[] =
669
674
  ,.fragment= ""
670
675
  ,.request_path= ""
671
676
  ,.request_url= "http://hypnotoad.org:1234"
677
+ ,.host= "hypnotoad.org"
672
678
  ,.port= 1234
673
679
  ,.num_headers= 0
674
680
  ,.headers= { }
675
681
  ,.body= ""
676
682
  }
677
683
 
678
- #define PATCH_REQ 24
684
+ #define PATCH_REQ 25
679
685
  , {.name = "PATCH request"
680
686
  ,.type= HTTP_REQUEST
681
687
  ,.raw= "PATCH /file.txt HTTP/1.1\r\n"
@@ -703,7 +709,7 @@ const struct message requests[] =
703
709
  ,.body= "cccccccccc"
704
710
  }
705
711
 
706
- #define CONNECT_CAPS_REQUEST 25
712
+ #define CONNECT_CAPS_REQUEST 26
707
713
  , {.name = "connect caps request"
708
714
  ,.type= HTTP_REQUEST
709
715
  ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n"
@@ -728,7 +734,7 @@ const struct message requests[] =
728
734
  }
729
735
 
730
736
  #if !HTTP_PARSER_STRICT
731
- #define UTF8_PATH_REQ 26
737
+ #define UTF8_PATH_REQ 27
732
738
  , {.name= "utf-8 path request"
733
739
  ,.type= HTTP_REQUEST
734
740
  ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n"
@@ -749,7 +755,7 @@ const struct message requests[] =
749
755
  ,.body= ""
750
756
  }
751
757
 
752
- #define HOSTNAME_UNDERSCORE 27
758
+ #define HOSTNAME_UNDERSCORE 28
753
759
  , {.name = "hostname underscore"
754
760
  ,.type= HTTP_REQUEST
755
761
  ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n"
@@ -775,7 +781,7 @@ const struct message requests[] =
775
781
  #endif /* !HTTP_PARSER_STRICT */
776
782
 
777
783
  /* see https://github.com/ry/http-parser/issues/47 */
778
- #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 28
784
+ #define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29
779
785
  , {.name = "eat CRLF between requests, no \"Connection: close\" header"
780
786
  ,.raw= "POST / HTTP/1.1\r\n"
781
787
  "Host: www.example.com\r\n"
@@ -802,7 +808,7 @@ const struct message requests[] =
802
808
  }
803
809
 
804
810
  /* see https://github.com/ry/http-parser/issues/47 */
805
- #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 29
811
+ #define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30
806
812
  , {.name = "eat CRLF between requests even if \"Connection: close\" is set"
807
813
  ,.raw= "POST / HTTP/1.1\r\n"
808
814
  "Host: www.example.com\r\n"
@@ -830,7 +836,7 @@ const struct message requests[] =
830
836
  ,.body= "q=42"
831
837
  }
832
838
 
833
- #define PURGE_REQ 30
839
+ #define PURGE_REQ 31
834
840
  , {.name = "PURGE request"
835
841
  ,.type= HTTP_REQUEST
836
842
  ,.raw= "PURGE /file.txt HTTP/1.1\r\n"
@@ -850,6 +856,48 @@ const struct message requests[] =
850
856
  ,.body= ""
851
857
  }
852
858
 
859
+ #define SEARCH_REQ 32
860
+ , {.name = "SEARCH request"
861
+ ,.type= HTTP_REQUEST
862
+ ,.raw= "SEARCH / HTTP/1.1\r\n"
863
+ "Host: www.example.com\r\n"
864
+ "\r\n"
865
+ ,.should_keep_alive= TRUE
866
+ ,.message_complete_on_eof= FALSE
867
+ ,.http_major= 1
868
+ ,.http_minor= 1
869
+ ,.method= HTTP_SEARCH
870
+ ,.query_string= ""
871
+ ,.fragment= ""
872
+ ,.request_path= "/"
873
+ ,.request_url= "/"
874
+ ,.num_headers= 1
875
+ ,.headers= { { "Host", "www.example.com" } }
876
+ ,.body= ""
877
+ }
878
+
879
+ #define PROXY_WITH_BASIC_AUTH 33
880
+ , {.name= "host:port and basic_auth"
881
+ ,.type= HTTP_REQUEST
882
+ ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
883
+ "\r\n"
884
+ ,.should_keep_alive= TRUE
885
+ ,.message_complete_on_eof= FALSE
886
+ ,.http_major= 1
887
+ ,.http_minor= 1
888
+ ,.method= HTTP_GET
889
+ ,.fragment= ""
890
+ ,.request_path= "/toto"
891
+ ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
892
+ ,.host= "hypnotoad.org"
893
+ ,.userinfo= "a%12:b!&*$"
894
+ ,.port= 1234
895
+ ,.num_headers= 0
896
+ ,.headers= { }
897
+ ,.body= ""
898
+ }
899
+
900
+
853
901
  , {.name= NULL } /* sentinel */
854
902
  };
855
903
 
@@ -1365,11 +1413,88 @@ const struct message responses[] =
1365
1413
  , {.name= NULL } /* sentinel */
1366
1414
  };
1367
1415
 
1416
+ /* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
1417
+ * define it ourselves.
1418
+ */
1419
+ size_t
1420
+ strnlen(const char *s, size_t maxlen)
1421
+ {
1422
+ const char *p;
1423
+
1424
+ p = memchr(s, '\0', maxlen);
1425
+ if (p == NULL)
1426
+ return maxlen;
1427
+
1428
+ return p - s;
1429
+ }
1430
+
1431
+ size_t
1432
+ strlncat(char *dst, size_t len, const char *src, size_t n)
1433
+ {
1434
+ size_t slen;
1435
+ size_t dlen;
1436
+ size_t rlen;
1437
+ size_t ncpy;
1438
+
1439
+ slen = strnlen(src, n);
1440
+ dlen = strnlen(dst, len);
1441
+
1442
+ if (dlen < len) {
1443
+ rlen = len - dlen;
1444
+ ncpy = slen < rlen ? slen : (rlen - 1);
1445
+ memcpy(dst + dlen, src, ncpy);
1446
+ dst[dlen + ncpy] = '\0';
1447
+ }
1448
+
1449
+ assert(len > slen + dlen);
1450
+ return slen + dlen;
1451
+ }
1452
+
1453
+ size_t
1454
+ strlcat(char *dst, const char *src, size_t len)
1455
+ {
1456
+ return strlncat(dst, len, src, (size_t) -1);
1457
+ }
1458
+
1459
+ size_t
1460
+ strlncpy(char *dst, size_t len, const char *src, size_t n)
1461
+ {
1462
+ size_t slen;
1463
+ size_t ncpy;
1464
+
1465
+ slen = strnlen(src, n);
1466
+
1467
+ if (len > 0) {
1468
+ ncpy = slen < len ? slen : (len - 1);
1469
+ memcpy(dst, src, ncpy);
1470
+ dst[ncpy] = '\0';
1471
+ }
1472
+
1473
+ assert(len > slen);
1474
+ return slen;
1475
+ }
1476
+
1477
+ size_t
1478
+ strlcpy(char *dst, const char *src, size_t len)
1479
+ {
1480
+ return strlncpy(dst, len, src, (size_t) -1);
1481
+ }
1482
+
1368
1483
  int
1369
1484
  request_url_cb (http_parser *p, const char *buf, size_t len)
1370
1485
  {
1371
1486
  assert(p == parser);
1372
- strncat(messages[num_messages].request_url, buf, len);
1487
+ strlncat(messages[num_messages].request_url,
1488
+ sizeof(messages[num_messages].request_url),
1489
+ buf,
1490
+ len);
1491
+ return 0;
1492
+ }
1493
+
1494
+ int
1495
+ status_complete_cb (http_parser *p) {
1496
+ assert(p == parser);
1497
+ p->data++;
1373
1498
  return 0;
1374
1499
  }
1375
1500
 
@@ -1382,7 +1507,10 @@ header_field_cb (http_parser *p, const char *buf, size_t len)
1382
1507
  if (m->last_header_element != FIELD)
1383
1508
  m->num_headers++;
1384
1509
 
1385
- 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);
1386
1514
 
1387
1515
  m->last_header_element = FIELD;
1388
1516
 
@@ -1395,19 +1523,39 @@ header_value_cb (http_parser *p, const char *buf, size_t len)
1395
1523
  assert(p == parser);
1396
1524
  struct message *m = &messages[num_messages];
1397
1525
 
1398
- 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);
1399
1530
 
1400
1531
  m->last_header_element = VALUE;
1401
1532
 
1402
1533
  return 0;
1403
1534
  }
1404
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
+
1405
1549
  int
1406
1550
  body_cb (http_parser *p, const char *buf, size_t len)
1407
1551
  {
1408
1552
  assert(p == parser);
1409
- strncat(messages[num_messages].body, buf, len);
1553
+ strlncat(messages[num_messages].body,
1554
+ sizeof(messages[num_messages].body),
1555
+ buf,
1556
+ len);
1410
1557
  messages[num_messages].body_size += len;
1558
+ check_body_is_final(p);
1411
1559
  // printf("body_cb: '%s'\n", requests[num_messages].body);
1412
1560
  return 0;
1413
1561
  }
@@ -1418,6 +1566,7 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
1418
1566
  assert(p == parser);
1419
1567
  assert(buf);
1420
1568
  messages[num_messages].body_size += len;
1569
+ check_body_is_final(p);
1421
1570
  return 0;
1422
1571
  }
1423
1572
 
@@ -1454,6 +1603,18 @@ message_complete_cb (http_parser *p)
1454
1603
  assert(0);
1455
1604
  abort();
1456
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
+
1457
1618
  messages[num_messages].message_complete_cb_called = TRUE;
1458
1619
 
1459
1620
  messages[num_messages].message_complete_on_eof = currently_parsing_eof;
@@ -1774,6 +1935,14 @@ message_eq (int index, const struct message *expected)
1774
1935
  abort();
1775
1936
  }
1776
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
+
1777
1946
  m->port = (u.field_set & (1 << UF_PORT)) ?
1778
1947
  u.port : 0;
1779
1948
 
@@ -1836,7 +2005,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
1836
2005
  va_list ap;
1837
2006
  size_t i;
1838
2007
  size_t off = 0;
1839
-
2008
+
1840
2009
  va_start(ap, nmsgs);
1841
2010
 
1842
2011
  for (i = 0; i < nmsgs; i++) {
@@ -1871,8 +2040,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) {
1871
2040
  static void
1872
2041
  print_error (const char *raw, size_t error_location)
1873
2042
  {
1874
- fprintf(stderr, "\n*** %s:%d -- %s ***\n\n",
1875
- "http_parser.c", HTTP_PARSER_ERRNO_LINE(parser),
2043
+ fprintf(stderr, "\n*** %s ***\n\n",
1876
2044
  http_errno_description(HTTP_PARSER_ERRNO(parser)));
1877
2045
 
1878
2046
  int this_line = 0, char_len = 0;
@@ -1946,6 +2114,26 @@ const struct url_test url_tests[] =
1946
2114
  ,{ 15, 1 } /* UF_PATH */
1947
2115
  ,{ 0, 0 } /* UF_QUERY */
1948
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 */
1949
2137
  }
1950
2138
  }
1951
2139
  ,.rv=0
@@ -1964,11 +2152,18 @@ const struct url_test url_tests[] =
1964
2152
  ,{ 0, 0 } /* UF_PATH */
1965
2153
  ,{ 0, 0 } /* UF_QUERY */
1966
2154
  ,{ 0, 0 } /* UF_FRAGMENT */
2155
+ ,{ 0, 0 } /* UF_USERINFO */
1967
2156
  }
1968
2157
  }
1969
2158
  ,.rv=0
1970
2159
  }
1971
2160
 
2161
+ , {.name="CONNECT request but not connect"
2162
+ ,.url="hostname:443"
2163
+ ,.is_connect=0
2164
+ ,.rv=1
2165
+ }
2166
+
1972
2167
  , {.name="proxy ipv6 request"
1973
2168
  ,.url="http://[1:2::3:4]/"
1974
2169
  ,.is_connect=0
@@ -1982,6 +2177,26 @@ const struct url_test url_tests[] =
1982
2177
  ,{ 17, 1 } /* UF_PATH */
1983
2178
  ,{ 0, 0 } /* UF_QUERY */
1984
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 */
1985
2200
  }
1986
2201
  }
1987
2202
  ,.rv=0
@@ -2000,13 +2215,35 @@ const struct url_test url_tests[] =
2000
2215
  ,{ 0, 0 } /* UF_PATH */
2001
2216
  ,{ 0, 0 } /* UF_QUERY */
2002
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 */
2003
2238
  }
2004
2239
  }
2005
2240
  ,.rv=0
2006
2241
  }
2007
2242
 
2008
2243
  , {.name="extra ? in query string"
2009
- ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
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"
2010
2247
  ,.is_connect=0
2011
2248
  ,.u=
2012
2249
  {.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
@@ -2018,11 +2255,118 @@ const struct url_test url_tests[] =
2018
2255
  ,{ 17, 12 } /* UF_PATH */
2019
2256
  ,{ 30,187 } /* UF_QUERY */
2020
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 */
2021
2319
  }
2022
2320
  }
2023
2321
  ,.rv=0
2024
2322
  }
2025
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
+
2026
2370
  , {.name="proxy empty host"
2027
2371
  ,.url="http://:443/"
2028
2372
  ,.is_connect=0
@@ -2035,6 +2379,12 @@ const struct url_test url_tests[] =
2035
2379
  ,.rv=1
2036
2380
  }
2037
2381
 
2382
+ , {.name="CONNECT with basic auth"
2383
+ ,.url="a:b@hostname:443"
2384
+ ,.is_connect=1
2385
+ ,.rv=1
2386
+ }
2387
+
2038
2388
  , {.name="CONNECT empty host"
2039
2389
  ,.url=":443"
2040
2390
  ,.is_connect=1
@@ -2052,12 +2402,189 @@ const struct url_test url_tests[] =
2052
2402
  ,.is_connect=1
2053
2403
  ,.rv=1
2054
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
2055
2583
  };
2056
2584
 
2057
2585
  void
2058
2586
  dump_url (const char *url, const struct http_parser_url *u)
2059
2587
  {
2060
- char part[512];
2061
2588
  unsigned int i;
2062
2589
 
2063
2590
  printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
@@ -2067,14 +2594,12 @@ dump_url (const char *url, const struct http_parser_url *u)
2067
2594
  continue;
2068
2595
  }
2069
2596
 
2070
- memcpy(part, url + u->field_data[i].off, u->field_data[i].len);
2071
- part[u->field_data[i].len] = '\0';
2072
-
2073
- printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n",
2597
+ printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"",
2074
2598
  i,
2075
2599
  u->field_data[i].off,
2076
2600
  u->field_data[i].len,
2077
- part);
2601
+ u->field_data[i].len,
2602
+ url + u->field_data[i].off);
2078
2603
  }
2079
2604
  }
2080
2605
 
@@ -2124,6 +2649,13 @@ test_parse_url (void)
2124
2649
  }
2125
2650
  }
2126
2651
 
2652
+ void
2653
+ test_method_str (void)
2654
+ {
2655
+ assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
2656
+ assert(0 == strcmp("<unknown>", http_method_str(1337)));
2657
+ }
2658
+
2127
2659
  void
2128
2660
  test_message (const struct message *message)
2129
2661
  {
@@ -2334,8 +2866,8 @@ test_no_overflow_long_body (int req, size_t length)
2334
2866
  size_t parsed;
2335
2867
  size_t i;
2336
2868
  char buf1[3000];
2337
- size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %zu\r\n\r\n",
2338
- 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);
2339
2871
  parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len);
2340
2872
  if (parsed != buf1len)
2341
2873
  goto err;
@@ -2353,9 +2885,9 @@ test_no_overflow_long_body (int req, size_t length)
2353
2885
 
2354
2886
  err:
2355
2887
  fprintf(stderr,
2356
- "\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",
2357
2889
  req ? "REQUEST" : "RESPONSE",
2358
- length);
2890
+ (unsigned long)length);
2359
2891
  abort();
2360
2892
  }
2361
2893
 
@@ -2452,15 +2984,15 @@ test_scan (const struct message *r1, const struct message *r2, const struct mess
2452
2984
  parser_init(type_both ? HTTP_BOTH : r1->type);
2453
2985
 
2454
2986
  buf1_len = i;
2455
- strncpy(buf1, total, buf1_len);
2987
+ strlncpy(buf1, sizeof(buf1), total, buf1_len);
2456
2988
  buf1[buf1_len] = 0;
2457
2989
 
2458
2990
  buf2_len = j - i;
2459
- strncpy(buf2, total+i, buf2_len);
2991
+ strlncpy(buf2, sizeof(buf1), total+i, buf2_len);
2460
2992
  buf2[buf2_len] = 0;
2461
2993
 
2462
2994
  buf3_len = total_len - j;
2463
- strncpy(buf3, total+j, buf3_len);
2995
+ strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
2464
2996
  buf3[buf3_len] = 0;
2465
2997
 
2466
2998
  read = parse(buf1, buf1_len);
@@ -2564,119 +3096,18 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
2564
3096
  return buf;
2565
3097
  }
2566
3098
 
2567
- char *
2568
- quote(const char * orig) {
2569
- if (!orig) return NULL;
2570
- size_t j, i, len = strlen(orig);
2571
- char * quoted = malloc(len == 0 ? 1 : len*2); // hm..
2572
- bzero(quoted, len == 0 ? 1 : len*2);
2573
- for (i=0, j=0; i!=len; ++i) {
2574
- switch (orig[i]){
2575
- case '\n':
2576
- quoted[j++] = '\\';
2577
- quoted[j++] = 'n';
2578
- break;
2579
- case '\r':
2580
- quoted[j++] = '\\';
2581
- quoted[j++] = 'r';
2582
- break;
2583
- case '"':
2584
- quoted[j++] = '\\';
2585
- quoted[j++] = '"';
2586
- break;
2587
- default :
2588
- quoted[j++] = orig[i];
2589
- }
2590
- }
2591
- return quoted;
2592
- }
2593
-
2594
- void
2595
- dump_message(const struct message * m)
2596
- {
2597
- int i;
2598
- printf("name :%s\n", m->name);
2599
- char * bla = quote(m->raw);
2600
- printf("raw :\"%s\"\n", bla);
2601
- free(bla);
2602
- switch (m->type){
2603
- case HTTP_REQUEST:
2604
- printf("type :HTTP_REQUEST\n");break;
2605
- case HTTP_RESPONSE:
2606
- printf("type :HTTP_RESPONSE\n"); break;
2607
- case HTTP_BOTH:
2608
- printf("type :HTTP_BOTH\n");
2609
- }
2610
- switch (m->method) {
2611
- case HTTP_DELETE: printf("method: HTTP_DELETE\n");break;
2612
- case HTTP_GET: printf("method: HTTP_GET\n");break;
2613
- case HTTP_HEAD: printf("method: HTTP_HEAD\n");break;
2614
- case HTTP_POST: printf("method: HTTP_POST\n");break;
2615
- case HTTP_PUT: printf("method: HTTP_PUT\n");break;
2616
- case HTTP_CONNECT: printf("method: HTTP_CONNECT\n");break;
2617
- case HTTP_OPTIONS: printf("method: HTTP_OPTIONS\n");break;
2618
- case HTTP_TRACE: printf("method: HTTP_TRACE\n");break;
2619
- case HTTP_COPY: printf("method: HTTP_COPY\n");break;
2620
- case HTTP_LOCK: printf("method: HTTP_LOCK\n");break;
2621
- case HTTP_MKCOL: printf("method: HTTP_MKCOL\n");break;
2622
- case HTTP_MOVE: printf("method: HTTP_MOVE\n");break;
2623
- case HTTP_PROPFIND: printf("method: HTTP_PROPFIND\n");break;
2624
- case HTTP_PROPPATCH: printf("method: HTTP_PROPPATCH\n");break;
2625
- case HTTP_UNLOCK: printf("method: HTTP_UNLOCK\n");break;
2626
- /* subversion */
2627
- case HTTP_REPORT: printf("method: HTTP_REPORT\n"); break;
2628
- case HTTP_MKACTIVITY: printf("method: HTTP_MKACTIVITY\n"); break;
2629
- case HTTP_CHECKOUT: printf("method: HTTP_CHECKOUT\n"); break;
2630
- case HTTP_MERGE: printf("method: HTTP_MERGE\n"); break;
2631
-
2632
- case HTTP_MSEARCH: printf("method: HTTP_MSEARCH\n"); break;
2633
- case HTTP_NOTIFY: printf("method: HTTP_NOTIFY\n"); break;
2634
- case HTTP_SUBSCRIBE: printf("method: HTTP_SUBSCRIBE\n"); break;
2635
- case HTTP_UNSUBSCRIBE: printf("method: HTTP_UNSUBSCRIBE\n"); break;
2636
- default:
2637
- printf("method: UNKNOWN\n"); break;
2638
- break;
2639
- }
2640
- printf("status_code :%d\n", m->status_code);
2641
- printf("request_path:%s\n", m->request_path);
2642
- printf("request_url :%s\n", m->request_url);
2643
- printf("fragment :%s\n", m->fragment);
2644
- printf("query_string:%s\n", m->query_string);
2645
-
2646
- bla = quote(m->body);
2647
- printf("body :\"%s\"\n", bla);
2648
- free(bla);
2649
- printf("body_size :%zu\n", m->body_size);
2650
-
2651
- for (i=0; i!=m->num_headers; ++i){
2652
- printf("header_%d :{ \"%s\": \"%s\"}\n", i, m->headers[i][0], m->headers[i][1]);
2653
- }
2654
-
2655
- printf("should_keep_alive :%d\n", m->should_keep_alive);
2656
- bla = quote(m->upgrade);
2657
- if (bla) {
2658
- printf("upgrade :\"%s\"\n", bla);
2659
- }
2660
- free(bla);
2661
- printf("http_major :%d\n", m->http_major);
2662
- printf("http_minor :%d\n", m->http_minor);
2663
- // printf("message_begin_cb_called :%d\n", m->message_begin_cb_called);
2664
- // printf("headers_complete_cb_called:%d\n", m->headers_complete_cb_called);
2665
- // printf("message_complete_cb_called:%d\n", m->message_complete_cb_called);
2666
- // printf("message_complete_on_eof :%d\n", m->message_complete_on_eof);
2667
- printf("\n");
2668
- }
2669
-
2670
3099
  void
2671
- dump_messages(void)
3100
+ test_status_complete (void)
2672
3101
  {
2673
- int request_count;
2674
- for (request_count = 0; requests[request_count].name; request_count++){
2675
- dump_message(&requests[request_count]);
2676
- }
2677
- for (request_count = 0; responses[request_count].name; request_count++){
2678
- dump_message(&responses[request_count]);
2679
- }
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
2680
3111
  }
2681
3112
 
2682
3113
  /* Verify that we can pause parsing at any of the bytes in the
@@ -2730,23 +3161,15 @@ test:
2730
3161
  if(!message_eq(0, msg)) abort();
2731
3162
 
2732
3163
  parser_free();
2733
-
2734
3164
  }
2735
3165
 
2736
3166
  int
2737
- main (int argc, char * argv[])
3167
+ main (void)
2738
3168
  {
2739
3169
  parser = NULL;
2740
3170
  int i, j, k;
2741
3171
  int request_count;
2742
3172
  int response_count;
2743
-
2744
- if (1 != argc) {
2745
- if (0 == (strncmp("-dump", argv[1], sizeof("-dump")))) {
2746
- dump_messages();
2747
- exit(0);
2748
- }
2749
- }
2750
3173
 
2751
3174
  printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
2752
3175
 
@@ -2756,6 +3179,7 @@ main (int argc, char * argv[])
2756
3179
  //// API
2757
3180
  test_preserve_data();
2758
3181
  test_parse_url();
3182
+ test_method_str();
2759
3183
 
2760
3184
  //// OVERFLOW CONDITIONS
2761
3185
 
@@ -2993,6 +3417,8 @@ main (int argc, char * argv[])
2993
3417
  , &requests[CONNECT_REQUEST]
2994
3418
  );
2995
3419
 
3420
+ test_status_complete();
3421
+
2996
3422
  puts("requests okay");
2997
3423
 
2998
3424
  return 0;