http_parser.rb 0.6.0.beta.1 → 0.6.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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;