shrpx: Update http-parser
This commit is contained in:
parent
b0f155eebc
commit
427b9ebfdb
|
@ -30,3 +30,8 @@ James McLaughlin <jamie@lacewing-project.org>
|
|||
David Gwynne <loki@animata.net>
|
||||
LE ROUX Thomas <thomas@procheo.fr>
|
||||
Randy Rizun <rrizun@ortivawireless.com>
|
||||
Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
|
||||
Simon Zimmermann <simonz05@gmail.com>
|
||||
Erik Dubbelboer <erik@dubbelboer.com>
|
||||
Martell Malone <martellmalone@gmail.com>
|
||||
Bertrand Paquet <bpaquet@octo.com>
|
||||
|
|
|
@ -37,6 +37,19 @@
|
|||
# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef BIT_AT
|
||||
# define BIT_AT(a, i) \
|
||||
(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
|
||||
(1 << ((unsigned int) (i) & 7))))
|
||||
#endif
|
||||
|
||||
#ifndef ELEM_AT
|
||||
# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
|
||||
#endif
|
||||
|
||||
#if HTTP_PARSER_DEBUG
|
||||
#define SET_ERRNO(e) \
|
||||
|
@ -185,45 +198,45 @@ static const int8_t unhex[256] =
|
|||
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
# define T 0
|
||||
# define T(v) 0
|
||||
#else
|
||||
# define T 1
|
||||
# define T(v) v
|
||||
#endif
|
||||
|
||||
|
||||
static const uint8_t normal_url_char[256] = {
|
||||
static const uint8_t normal_url_char[32] = {
|
||||
/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
|
||||
0, T, 0, 0, T, 0, 0, 0,
|
||||
0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
|
||||
/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
|
||||
/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
|
||||
0, 1, 1, 0, 1, 1, 1, 1,
|
||||
0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
|
||||
/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
|
||||
1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
|
||||
/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
|
||||
/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
|
||||
1, 1, 1, 1, 1, 1, 1, 0, };
|
||||
1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
|
||||
|
||||
#undef T
|
||||
|
||||
|
@ -253,13 +266,9 @@ enum state
|
|||
, s_req_schema
|
||||
, s_req_schema_slash
|
||||
, s_req_schema_slash_slash
|
||||
, s_req_host_start
|
||||
, s_req_host_v6_start
|
||||
, s_req_host_v6
|
||||
, s_req_host_v6_end
|
||||
, s_req_host
|
||||
, s_req_port_start
|
||||
, s_req_port
|
||||
, s_req_server_start
|
||||
, s_req_server
|
||||
, s_req_server_with_at
|
||||
, s_req_path
|
||||
, s_req_query_string_start
|
||||
, s_req_query_string
|
||||
|
@ -337,6 +346,19 @@ enum header_states
|
|||
, h_connection_close
|
||||
};
|
||||
|
||||
enum http_host_state
|
||||
{
|
||||
s_http_host_dead = 1
|
||||
, s_http_userinfo_start
|
||||
, s_http_userinfo
|
||||
, s_http_host_start
|
||||
, s_http_host_v6_start
|
||||
, s_http_host
|
||||
, s_http_host_v6
|
||||
, s_http_host_v6_end
|
||||
, s_http_host_port_start
|
||||
, s_http_host_port
|
||||
};
|
||||
|
||||
/* Macros for character classes; depends on strict-mode */
|
||||
#define CR '\r'
|
||||
|
@ -346,15 +368,21 @@ enum header_states
|
|||
#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
|
||||
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
|
||||
#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
|
||||
#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
|
||||
(c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
|
||||
(c) == ')')
|
||||
#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
|
||||
(c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
|
||||
(c) == '$' || (c) == ',')
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
#define TOKEN(c) (tokens[(unsigned char)c])
|
||||
#define IS_URL_CHAR(c) (normal_url_char[(unsigned char) (c)])
|
||||
#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
|
||||
#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
|
||||
#else
|
||||
#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
|
||||
#define IS_URL_CHAR(c) \
|
||||
(normal_url_char[(unsigned char) (c)] || ((c) & 0x80))
|
||||
(BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
|
||||
#define IS_HOST_CHAR(c) \
|
||||
(IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
|
||||
#endif
|
||||
|
@ -388,7 +416,7 @@ static struct {
|
|||
};
|
||||
#undef HTTP_STRERROR_GEN
|
||||
|
||||
int http_message_needs_eof(http_parser *parser);
|
||||
int http_message_needs_eof(const http_parser *parser);
|
||||
|
||||
/* Our URL parser.
|
||||
*
|
||||
|
@ -450,67 +478,33 @@ parse_url_char(enum state s, const char ch)
|
|||
|
||||
case s_req_schema_slash_slash:
|
||||
if (ch == '/') {
|
||||
return s_req_host_start;
|
||||
return s_req_server_start;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_host_start:
|
||||
if (ch == '[') {
|
||||
return s_req_host_v6_start;
|
||||
case s_req_server_with_at:
|
||||
if (ch == '@') {
|
||||
return s_dead;
|
||||
}
|
||||
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return s_req_host;
|
||||
/* FALLTHROUGH */
|
||||
case s_req_server_start:
|
||||
case s_req_server:
|
||||
if (ch == '/') {
|
||||
return s_req_path;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_host:
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return s_req_host;
|
||||
if (ch == '?') {
|
||||
return s_req_query_string_start;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_req_host_v6_end:
|
||||
switch (ch) {
|
||||
case ':':
|
||||
return s_req_port_start;
|
||||
|
||||
case '/':
|
||||
return s_req_path;
|
||||
|
||||
case '?':
|
||||
return s_req_query_string_start;
|
||||
if (ch == '@') {
|
||||
return s_req_server_with_at;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_req_host_v6:
|
||||
if (ch == ']') {
|
||||
return s_req_host_v6_end;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_req_host_v6_start:
|
||||
if (IS_HEX(ch) || ch == ':') {
|
||||
return s_req_host_v6;
|
||||
}
|
||||
break;
|
||||
|
||||
case s_req_port:
|
||||
switch (ch) {
|
||||
case '/':
|
||||
return s_req_path;
|
||||
|
||||
case '?':
|
||||
return s_req_query_string_start;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_req_port_start:
|
||||
if (IS_NUM(ch)) {
|
||||
return s_req_port;
|
||||
if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
|
||||
return s_req_server;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -632,13 +626,9 @@ size_t http_parser_execute (http_parser *parser,
|
|||
case s_req_schema:
|
||||
case s_req_schema_slash:
|
||||
case s_req_schema_slash_slash:
|
||||
case s_req_host_start:
|
||||
case s_req_host_v6_start:
|
||||
case s_req_host_v6:
|
||||
case s_req_host_v6_end:
|
||||
case s_req_host:
|
||||
case s_req_port_start:
|
||||
case s_req_port:
|
||||
case s_req_server_start:
|
||||
case s_req_server:
|
||||
case s_req_server_with_at:
|
||||
case s_req_query_string_start:
|
||||
case s_req_query_string:
|
||||
case s_req_fragment_start:
|
||||
|
@ -999,7 +989,7 @@ size_t http_parser_execute (http_parser *parser,
|
|||
|
||||
MARK(url);
|
||||
if (parser->method == HTTP_CONNECT) {
|
||||
parser->state = s_req_host_start;
|
||||
parser->state = s_req_server_start;
|
||||
}
|
||||
|
||||
parser->state = parse_url_char((enum state)parser->state, ch);
|
||||
|
@ -1014,10 +1004,7 @@ size_t http_parser_execute (http_parser *parser,
|
|||
case s_req_schema:
|
||||
case s_req_schema_slash:
|
||||
case s_req_schema_slash_slash:
|
||||
case s_req_host_start:
|
||||
case s_req_host_v6_start:
|
||||
case s_req_host_v6:
|
||||
case s_req_port_start:
|
||||
case s_req_server_start:
|
||||
{
|
||||
switch (ch) {
|
||||
/* No whitespace allowed here */
|
||||
|
@ -1037,9 +1024,8 @@ size_t http_parser_execute (http_parser *parser,
|
|||
break;
|
||||
}
|
||||
|
||||
case s_req_host:
|
||||
case s_req_host_v6_end:
|
||||
case s_req_port:
|
||||
case s_req_server:
|
||||
case s_req_server_with_at:
|
||||
case s_req_path:
|
||||
case s_req_query_string_start:
|
||||
case s_req_query_string:
|
||||
|
@ -1873,7 +1859,7 @@ error:
|
|||
|
||||
/* Does the parser need to see an EOF to find the end of the message? */
|
||||
int
|
||||
http_message_needs_eof (http_parser *parser)
|
||||
http_message_needs_eof (const http_parser *parser)
|
||||
{
|
||||
if (parser->type == HTTP_REQUEST) {
|
||||
return 0;
|
||||
|
@ -1896,7 +1882,7 @@ http_message_needs_eof (http_parser *parser)
|
|||
|
||||
|
||||
int
|
||||
http_should_keep_alive (http_parser *parser)
|
||||
http_should_keep_alive (const http_parser *parser)
|
||||
{
|
||||
if (parser->http_major > 0 && parser->http_minor > 0) {
|
||||
/* HTTP/1.1 */
|
||||
|
@ -1914,9 +1900,10 @@ http_should_keep_alive (http_parser *parser)
|
|||
}
|
||||
|
||||
|
||||
const char * http_method_str (enum http_method m)
|
||||
const char *
|
||||
http_method_str (enum http_method m)
|
||||
{
|
||||
return method_strings[m];
|
||||
return ELEM_AT(method_strings, m, "<unknown>");
|
||||
}
|
||||
|
||||
|
||||
|
@ -1943,6 +1930,144 @@ http_errno_description(enum http_errno err) {
|
|||
return http_strerror_tab[err].description;
|
||||
}
|
||||
|
||||
static enum http_host_state
|
||||
http_parse_host_char(enum http_host_state s, const char ch) {
|
||||
switch(s) {
|
||||
case s_http_userinfo:
|
||||
case s_http_userinfo_start:
|
||||
if (ch == '@') {
|
||||
return s_http_host_start;
|
||||
}
|
||||
|
||||
if (IS_USERINFO_CHAR(ch)) {
|
||||
return s_http_userinfo;
|
||||
}
|
||||
break;
|
||||
|
||||
case s_http_host_start:
|
||||
if (ch == '[') {
|
||||
return s_http_host_v6_start;
|
||||
}
|
||||
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return s_http_host;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host:
|
||||
if (IS_HOST_CHAR(ch)) {
|
||||
return s_http_host;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_end:
|
||||
if (ch == ':') {
|
||||
return s_http_host_port_start;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host_v6:
|
||||
if (ch == ']') {
|
||||
return s_http_host_v6_end;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
case s_http_host_v6_start:
|
||||
if (IS_HEX(ch) || ch == ':') {
|
||||
return s_http_host_v6;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case s_http_host_port:
|
||||
case s_http_host_port_start:
|
||||
if (IS_NUM(ch)) {
|
||||
return s_http_host_port;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return s_http_host_dead;
|
||||
}
|
||||
|
||||
static int
|
||||
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
|
||||
enum http_host_state s;
|
||||
|
||||
const char *p;
|
||||
size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
|
||||
|
||||
u->field_data[UF_HOST].len = 0;
|
||||
|
||||
s = found_at ? s_http_userinfo_start : s_http_host_start;
|
||||
|
||||
for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
|
||||
enum http_host_state new_s = http_parse_host_char(s, *p);
|
||||
|
||||
if (new_s == s_http_host_dead) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch(new_s) {
|
||||
case s_http_host:
|
||||
if (s != s_http_host) {
|
||||
u->field_data[UF_HOST].off = p - buf;
|
||||
}
|
||||
u->field_data[UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_v6:
|
||||
if (s != s_http_host_v6) {
|
||||
u->field_data[UF_HOST].off = p - buf;
|
||||
}
|
||||
u->field_data[UF_HOST].len++;
|
||||
break;
|
||||
|
||||
case s_http_host_port:
|
||||
if (s != s_http_host_port) {
|
||||
u->field_data[UF_PORT].off = p - buf;
|
||||
u->field_data[UF_PORT].len = 0;
|
||||
u->field_set |= (1 << UF_PORT);
|
||||
}
|
||||
u->field_data[UF_PORT].len++;
|
||||
break;
|
||||
|
||||
case s_http_userinfo:
|
||||
if (s != s_http_userinfo) {
|
||||
u->field_data[UF_USERINFO].off = p - buf ;
|
||||
u->field_data[UF_USERINFO].len = 0;
|
||||
u->field_set |= (1 << UF_USERINFO);
|
||||
}
|
||||
u->field_data[UF_USERINFO].len++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s = new_s;
|
||||
}
|
||||
|
||||
/* Make sure we don't end somewhere unexpected */
|
||||
switch (s) {
|
||||
case s_http_host_start:
|
||||
case s_http_host_v6_start:
|
||||
case s_http_host_v6:
|
||||
case s_http_host_port_start:
|
||||
case s_http_userinfo:
|
||||
case s_http_userinfo_start:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
||||
struct http_parser_url *u)
|
||||
|
@ -1950,9 +2075,10 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
|||
enum state s;
|
||||
const char *p;
|
||||
enum http_parser_url_fields uf, old_uf;
|
||||
int found_at = 0;
|
||||
|
||||
u->port = u->field_set = 0;
|
||||
s = is_connect ? s_req_host_start : s_req_spaces_before_url;
|
||||
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
|
||||
uf = old_uf = UF_MAX;
|
||||
|
||||
for (p = buf; p < buf + buflen; p++) {
|
||||
|
@ -1966,10 +2092,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
|||
/* Skip delimeters */
|
||||
case s_req_schema_slash:
|
||||
case s_req_schema_slash_slash:
|
||||
case s_req_host_start:
|
||||
case s_req_host_v6_start:
|
||||
case s_req_host_v6_end:
|
||||
case s_req_port_start:
|
||||
case s_req_server_start:
|
||||
case s_req_query_string_start:
|
||||
case s_req_fragment_start:
|
||||
continue;
|
||||
|
@ -1978,13 +2101,12 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
|||
uf = UF_SCHEMA;
|
||||
break;
|
||||
|
||||
case s_req_host:
|
||||
case s_req_host_v6:
|
||||
uf = UF_HOST;
|
||||
break;
|
||||
case s_req_server_with_at:
|
||||
found_at = 1;
|
||||
|
||||
case s_req_port:
|
||||
uf = UF_PORT;
|
||||
/* FALLTROUGH */
|
||||
case s_req_server:
|
||||
uf = UF_HOST;
|
||||
break;
|
||||
|
||||
case s_req_path:
|
||||
|
@ -2017,23 +2139,19 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
|
|||
old_uf = uf;
|
||||
}
|
||||
|
||||
/* host must be present if there is a schema */
|
||||
/* parsing http:///toto will fail */
|
||||
if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) {
|
||||
if (http_parse_host(buf, u, found_at) != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* CONNECT requests can only contain "hostname:port" */
|
||||
if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make sure we don't end somewhere unexpected */
|
||||
switch (s) {
|
||||
case s_req_host_v6_start:
|
||||
case s_req_host_v6:
|
||||
case s_req_host_v6_end:
|
||||
case s_req_host:
|
||||
case s_req_port_start:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (u->field_set & (1 << UF_PORT)) {
|
||||
/* Don't bother with endp; we've already validated the string */
|
||||
unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
|
||||
|
@ -2062,3 +2180,8 @@ http_parser_pause(http_parser *parser, int paused) {
|
|||
assert(0 && "Attempting to pause parser in error state");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
http_body_is_final(const struct http_parser *parser) {
|
||||
return parser->state == s_message_done;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ extern "C" {
|
|||
|
||||
#include <sys/types.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
|
||||
#include <BaseTsd.h>
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
|
@ -37,9 +38,8 @@ typedef __int32 int32_t;
|
|||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
typedef unsigned int size_t;
|
||||
typedef int ssize_t;
|
||||
typedef SIZE_T size_t;
|
||||
typedef SSIZE_T ssize_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
@ -256,7 +256,8 @@ enum http_parser_url_fields
|
|||
, UF_PATH = 3
|
||||
, UF_QUERY = 4
|
||||
, UF_FRAGMENT = 5
|
||||
, UF_MAX = 6
|
||||
, UF_USERINFO = 6
|
||||
, UF_MAX = 7
|
||||
};
|
||||
|
||||
|
||||
|
@ -288,12 +289,12 @@ size_t http_parser_execute(http_parser *parser,
|
|||
|
||||
|
||||
/* If http_should_keep_alive() in the on_headers_complete or
|
||||
* on_message_complete callback returns true, then this will be should be
|
||||
* on_message_complete callback returns 0, then this should be
|
||||
* the last message on the connection.
|
||||
* If you are the server, respond with the "Connection: close" header.
|
||||
* If you are the client, close the connection.
|
||||
*/
|
||||
int http_should_keep_alive(http_parser *parser);
|
||||
int http_should_keep_alive(const http_parser *parser);
|
||||
|
||||
/* Returns a string version of the HTTP method. */
|
||||
const char *http_method_str(enum http_method m);
|
||||
|
@ -312,6 +313,9 @@ int http_parser_parse_url(const char *buf, size_t buflen,
|
|||
/* Pause or un-pause the parser; a nonzero value pauses */
|
||||
void http_parser_pause(http_parser *parser, int paused);
|
||||
|
||||
/* Checks if this is the final chunk of the body. */
|
||||
int http_body_is_final(const http_parser *parser);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -50,6 +50,8 @@ struct message {
|
|||
char query_string[MAX_ELEMENT_SIZE];
|
||||
char body[MAX_ELEMENT_SIZE];
|
||||
size_t body_size;
|
||||
const char *host;
|
||||
const char *userinfo;
|
||||
uint16_t port;
|
||||
int num_headers;
|
||||
enum { NONE=0, FIELD, VALUE } last_header_element;
|
||||
|
@ -65,6 +67,7 @@ struct message {
|
|||
int headers_complete_cb_called;
|
||||
int message_complete_cb_called;
|
||||
int message_complete_on_eof;
|
||||
int body_is_final;
|
||||
};
|
||||
|
||||
static int currently_parsing_eof;
|
||||
|
@ -630,6 +633,7 @@ const struct message requests[] =
|
|||
,.fragment= ""
|
||||
,.request_path= ""
|
||||
,.request_url= "http://hypnotoad.org?hail=all"
|
||||
,.host= "hypnotoad.org"
|
||||
,.num_headers= 0
|
||||
,.headers= { }
|
||||
,.body= ""
|
||||
|
@ -649,6 +653,7 @@ const struct message requests[] =
|
|||
,.fragment= ""
|
||||
,.request_path= ""
|
||||
,.request_url= "http://hypnotoad.org:1234?hail=all"
|
||||
,.host= "hypnotoad.org"
|
||||
,.port= 1234
|
||||
,.num_headers= 0
|
||||
,.headers= { }
|
||||
|
@ -669,6 +674,7 @@ const struct message requests[] =
|
|||
,.fragment= ""
|
||||
,.request_path= ""
|
||||
,.request_url= "http://hypnotoad.org:1234"
|
||||
,.host= "hypnotoad.org"
|
||||
,.port= 1234
|
||||
,.num_headers= 0
|
||||
,.headers= { }
|
||||
|
@ -870,6 +876,28 @@ const struct message requests[] =
|
|||
,.body= ""
|
||||
}
|
||||
|
||||
#define PROXY_WITH_BASIC_AUTH 33
|
||||
, {.name= "host:port and basic_auth"
|
||||
,.type= HTTP_REQUEST
|
||||
,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n"
|
||||
"\r\n"
|
||||
,.should_keep_alive= TRUE
|
||||
,.message_complete_on_eof= FALSE
|
||||
,.http_major= 1
|
||||
,.http_minor= 1
|
||||
,.method= HTTP_GET
|
||||
,.fragment= ""
|
||||
,.request_path= "/toto"
|
||||
,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto"
|
||||
,.host= "hypnotoad.org"
|
||||
,.userinfo= "a%12:b!&*$"
|
||||
,.port= 1234
|
||||
,.num_headers= 0
|
||||
,.headers= { }
|
||||
,.body= ""
|
||||
}
|
||||
|
||||
|
||||
, {.name= NULL } /* sentinel */
|
||||
};
|
||||
|
||||
|
@ -1422,12 +1450,26 @@ header_value_cb (http_parser *p, const char *buf, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
check_body_is_final (const http_parser *p)
|
||||
{
|
||||
if (messages[num_messages].body_is_final) {
|
||||
fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
|
||||
"on last on_body callback call "
|
||||
"but it doesn't! ***\n\n");
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
messages[num_messages].body_is_final = http_body_is_final(p);
|
||||
}
|
||||
|
||||
int
|
||||
body_cb (http_parser *p, const char *buf, size_t len)
|
||||
{
|
||||
assert(p == parser);
|
||||
strncat(messages[num_messages].body, buf, len);
|
||||
messages[num_messages].body_size += len;
|
||||
check_body_is_final(p);
|
||||
// printf("body_cb: '%s'\n", requests[num_messages].body);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1438,6 +1480,7 @@ count_body_cb (http_parser *p, const char *buf, size_t len)
|
|||
assert(p == parser);
|
||||
assert(buf);
|
||||
messages[num_messages].body_size += len;
|
||||
check_body_is_final(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1474,6 +1517,18 @@ message_complete_cb (http_parser *p)
|
|||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (messages[num_messages].body_size &&
|
||||
http_body_is_final(p) &&
|
||||
!messages[num_messages].body_is_final)
|
||||
{
|
||||
fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 "
|
||||
"on last on_body callback call "
|
||||
"but it doesn't! ***\n\n");
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
messages[num_messages].message_complete_cb_called = TRUE;
|
||||
|
||||
messages[num_messages].message_complete_on_eof = currently_parsing_eof;
|
||||
|
@ -1794,6 +1849,14 @@ message_eq (int index, const struct message *expected)
|
|||
abort();
|
||||
}
|
||||
|
||||
if (expected->host) {
|
||||
MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST);
|
||||
}
|
||||
|
||||
if (expected->userinfo) {
|
||||
MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO);
|
||||
}
|
||||
|
||||
m->port = (u.field_set & (1 << UF_PORT)) ?
|
||||
u.port : 0;
|
||||
|
||||
|
@ -1966,6 +2029,26 @@ const struct url_test url_tests[] =
|
|||
,{ 15, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="proxy request with port"
|
||||
,.url="http://hostname:444/"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
|
||||
,.port=444
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 7, 8 } /* UF_HOST */
|
||||
,{ 16, 3 } /* UF_PORT */
|
||||
,{ 19, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
|
@ -1984,11 +2067,18 @@ const struct url_test url_tests[] =
|
|||
,{ 0, 0 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="CONNECT request but not connect"
|
||||
,.url="hostname:443"
|
||||
,.is_connect=0
|
||||
,.rv=1
|
||||
}
|
||||
|
||||
, {.name="proxy ipv6 request"
|
||||
,.url="http://[1:2::3:4]/"
|
||||
,.is_connect=0
|
||||
|
@ -2002,6 +2092,26 @@ const struct url_test url_tests[] =
|
|||
,{ 17, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="proxy ipv6 request with port"
|
||||
,.url="http://[1:2::3:4]:67/"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH)
|
||||
,.port=67
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 8, 8 } /* UF_HOST */
|
||||
,{ 18, 2 } /* UF_PORT */
|
||||
,{ 20, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
|
@ -2020,13 +2130,16 @@ const struct url_test url_tests[] =
|
|||
,{ 0, 0 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="extra ? in query string"
|
||||
,.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"
|
||||
,.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"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set=(1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY)
|
||||
|
@ -2038,11 +2151,118 @@ const struct url_test url_tests[] =
|
|||
,{ 17, 12 } /* UF_PATH */
|
||||
,{ 30,187 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="space URL encoded"
|
||||
,.url="/toto.html?toto=a%20b"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_PATH) | (1<<UF_QUERY)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 0 } /* UF_SCHEMA */
|
||||
,{ 0, 0 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 0, 10 } /* UF_PATH */
|
||||
,{ 11, 10 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
|
||||
, {.name="URL fragment"
|
||||
,.url="/toto.html#titi"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_PATH) | (1<<UF_FRAGMENT)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 0 } /* UF_SCHEMA */
|
||||
,{ 0, 0 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 0, 10 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 11, 4 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="complex URL fragment"
|
||||
,.url="http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
|
||||
"http://www.example.com/index.html?foo=bar&hello=world#midpage"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_QUERY) |\
|
||||
(1<<UF_FRAGMENT)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 7, 22 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 29, 6 } /* UF_PATH */
|
||||
,{ 36, 69 } /* UF_QUERY */
|
||||
,{106, 7 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="complex URL from node js url parser doc"
|
||||
,.url="http://host.com:8080/p/a/t/h?query=string#hash"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
|
||||
(1<<UF_QUERY) | (1<<UF_FRAGMENT)
|
||||
,.port=8080
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 7, 8 } /* UF_HOST */
|
||||
,{ 16, 4 } /* UF_PORT */
|
||||
,{ 20, 8 } /* UF_PATH */
|
||||
,{ 29, 12 } /* UF_QUERY */
|
||||
,{ 42, 4 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="complex URL with basic auth from node js url parser doc"
|
||||
,.url="http://a:b@host.com:8080/p/a/t/h?query=string#hash"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) | (1<<UF_PATH) |\
|
||||
(1<<UF_QUERY) | (1<<UF_FRAGMENT) | (1<<UF_USERINFO)
|
||||
,.port=8080
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 11, 8 } /* UF_HOST */
|
||||
,{ 20, 4 } /* UF_PORT */
|
||||
,{ 24, 8 } /* UF_PATH */
|
||||
,{ 33, 12 } /* UF_QUERY */
|
||||
,{ 46, 4 } /* UF_FRAGMENT */
|
||||
,{ 7, 3 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="double @"
|
||||
,.url="http://a:b@@hostname:443/"
|
||||
,.is_connect=0
|
||||
,.rv=1
|
||||
}
|
||||
|
||||
, {.name="proxy empty host"
|
||||
,.url="http://:443/"
|
||||
,.is_connect=0
|
||||
|
@ -2055,6 +2275,12 @@ const struct url_test url_tests[] =
|
|||
,.rv=1
|
||||
}
|
||||
|
||||
, {.name="CONNECT with basic auth"
|
||||
,.url="a:b@hostname:443"
|
||||
,.is_connect=1
|
||||
,.rv=1
|
||||
}
|
||||
|
||||
, {.name="CONNECT empty host"
|
||||
,.url=":443"
|
||||
,.is_connect=1
|
||||
|
@ -2078,16 +2304,130 @@ const struct url_test url_tests[] =
|
|||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy basic auth with space url encoded"
|
||||
,.url="http://a%20:b@host.com/"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 14, 8 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 22, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 7, 6 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="carriage return in URL"
|
||||
,.url="/foo\rbar/"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy double : in URL"
|
||||
,.url="http://hostname::443/"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy basic auth with double :"
|
||||
,.url="http://a::b@host.com/"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 12, 8 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 20, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 7, 4 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="line feed in URL"
|
||||
,.url="/foo\nbar/"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy empty basic auth"
|
||||
,.url="http://@hostname/fo"
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 8, 8 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 16, 3 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
, {.name="proxy line feed in hostname"
|
||||
,.url="http://host\name/fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy % in hostname"
|
||||
,.url="http://host%name/fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy ; in hostname"
|
||||
,.url="http://host;ame/fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy basic auth with unreservedchars"
|
||||
,.url="http://a!;-_!=+$@host.com/"
|
||||
,.is_connect=0
|
||||
,.u=
|
||||
{.field_set= (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) | (1<<UF_USERINFO)
|
||||
,.port=0
|
||||
,.field_data=
|
||||
{{ 0, 4 } /* UF_SCHEMA */
|
||||
,{ 17, 8 } /* UF_HOST */
|
||||
,{ 0, 0 } /* UF_PORT */
|
||||
,{ 25, 1 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 7, 9 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
}
|
||||
|
||||
, {.name="proxy only empty basic auth"
|
||||
,.url="http://@/fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy only basic auth"
|
||||
,.url="http://toto@/fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy emtpy hostname"
|
||||
,.url="http:///fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
, {.name="proxy = in URL"
|
||||
,.url="http://host=ame/fo"
|
||||
,.rv=1 /* s_dead */
|
||||
}
|
||||
|
||||
#if HTTP_PARSER_STRICT
|
||||
|
||||
, {.name="tab in URL"
|
||||
|
@ -2113,6 +2453,7 @@ const struct url_test url_tests[] =
|
|||
,{ 0, 9 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
|
@ -2129,6 +2470,7 @@ const struct url_test url_tests[] =
|
|||
,{ 0, 9 } /* UF_PATH */
|
||||
,{ 0, 0 } /* UF_QUERY */
|
||||
,{ 0, 0 } /* UF_FRAGMENT */
|
||||
,{ 0, 0 } /* UF_USERINFO */
|
||||
}
|
||||
}
|
||||
,.rv=0
|
||||
|
@ -2139,7 +2481,6 @@ const struct url_test url_tests[] =
|
|||
void
|
||||
dump_url (const char *url, const struct http_parser_url *u)
|
||||
{
|
||||
char part[512];
|
||||
unsigned int i;
|
||||
|
||||
printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
|
||||
|
@ -2149,14 +2490,12 @@ dump_url (const char *url, const struct http_parser_url *u)
|
|||
continue;
|
||||
}
|
||||
|
||||
memcpy(part, url + u->field_data[i].off, u->field_data[i].len);
|
||||
part[u->field_data[i].len] = '\0';
|
||||
|
||||
printf("\tfield_data[%u]: off: %u len: %u part: \"%s\"\n",
|
||||
printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n",
|
||||
i,
|
||||
u->field_data[i].off,
|
||||
u->field_data[i].len,
|
||||
part);
|
||||
u->field_data[i].len,
|
||||
url + u->field_data[i].off);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2206,6 +2545,13 @@ test_parse_url (void)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
test_method_str (void)
|
||||
{
|
||||
assert(0 == strcmp("GET", http_method_str(HTTP_GET)));
|
||||
assert(0 == strcmp("<unknown>", http_method_str(1337)));
|
||||
}
|
||||
|
||||
void
|
||||
test_message (const struct message *message)
|
||||
{
|
||||
|
@ -2715,6 +3061,7 @@ main (void)
|
|||
//// API
|
||||
test_preserve_data();
|
||||
test_parse_url();
|
||||
test_method_str();
|
||||
|
||||
//// OVERFLOW CONDITIONS
|
||||
|
||||
|
|
Loading…
Reference in New Issue