|
@ -400,6 +400,8 @@ enum http_host_state |
|
|
, s_http_host |
|
|
, s_http_host |
|
|
, s_http_host_v6 |
|
|
, s_http_host_v6 |
|
|
, s_http_host_v6_end |
|
|
, s_http_host_v6_end |
|
|
|
|
|
, s_http_host_v6_zone_start |
|
|
|
|
|
, s_http_host_v6_zone |
|
|
, s_http_host_port_start |
|
|
, s_http_host_port_start |
|
|
, s_http_host_port |
|
|
, s_http_host_port |
|
|
}; |
|
|
}; |
|
@ -957,21 +959,23 @@ reexecute: |
|
|
parser->method = (enum http_method) 0; |
|
|
parser->method = (enum http_method) 0; |
|
|
parser->index = 1; |
|
|
parser->index = 1; |
|
|
switch (ch) { |
|
|
switch (ch) { |
|
|
|
|
|
case 'A': parser->method = HTTP_ACL; break; |
|
|
|
|
|
case 'B': parser->method = HTTP_BIND; break; |
|
|
case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; |
|
|
case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; |
|
|
case 'D': parser->method = HTTP_DELETE; break; |
|
|
case 'D': parser->method = HTTP_DELETE; break; |
|
|
case 'G': parser->method = HTTP_GET; break; |
|
|
case 'G': parser->method = HTTP_GET; break; |
|
|
case 'H': parser->method = HTTP_HEAD; break; |
|
|
case 'H': parser->method = HTTP_HEAD; break; |
|
|
case 'L': parser->method = HTTP_LOCK; break; |
|
|
case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; |
|
|
case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; |
|
|
case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; |
|
|
case 'N': parser->method = HTTP_NOTIFY; break; |
|
|
case 'N': parser->method = HTTP_NOTIFY; break; |
|
|
case 'O': parser->method = HTTP_OPTIONS; break; |
|
|
case 'O': parser->method = HTTP_OPTIONS; break; |
|
|
case 'P': parser->method = HTTP_POST; |
|
|
case 'P': parser->method = HTTP_POST; |
|
|
/* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ |
|
|
/* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ |
|
|
break; |
|
|
break; |
|
|
case 'R': parser->method = HTTP_REPORT; break; |
|
|
case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; |
|
|
case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; |
|
|
case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; |
|
|
case 'T': parser->method = HTTP_TRACE; break; |
|
|
case 'T': parser->method = HTTP_TRACE; break; |
|
|
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; |
|
|
case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; |
|
|
default: |
|
|
default: |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
goto error; |
|
|
goto error; |
|
@ -1027,7 +1031,15 @@ reexecute: |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
goto error; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
} else if (parser->index == 1 && parser->method == HTTP_POST) { |
|
|
} else if (parser->method == HTTP_REPORT) { |
|
|
|
|
|
if (parser->index == 2 && ch == 'B') { |
|
|
|
|
|
parser->method = HTTP_REBIND; |
|
|
|
|
|
} else { |
|
|
|
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
|
|
|
goto error; |
|
|
|
|
|
} |
|
|
|
|
|
} else if (parser->index == 1) { |
|
|
|
|
|
if (parser->method == HTTP_POST) { |
|
|
if (ch == 'R') { |
|
|
if (ch == 'R') { |
|
|
parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ |
|
|
parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ |
|
|
} else if (ch == 'U') { |
|
|
} else if (ch == 'U') { |
|
@ -1038,6 +1050,14 @@ reexecute: |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
goto error; |
|
|
goto error; |
|
|
} |
|
|
} |
|
|
|
|
|
} else if (parser->method == HTTP_LOCK) { |
|
|
|
|
|
if (ch == 'I') { |
|
|
|
|
|
parser->method = HTTP_LINK; |
|
|
|
|
|
} else { |
|
|
|
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
|
|
|
goto error; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} else if (parser->index == 2) { |
|
|
} else if (parser->index == 2) { |
|
|
if (parser->method == HTTP_PUT) { |
|
|
if (parser->method == HTTP_PUT) { |
|
|
if (ch == 'R') { |
|
|
if (ch == 'R') { |
|
@ -1049,6 +1069,8 @@ reexecute: |
|
|
} else if (parser->method == HTTP_UNLOCK) { |
|
|
} else if (parser->method == HTTP_UNLOCK) { |
|
|
if (ch == 'S') { |
|
|
if (ch == 'S') { |
|
|
parser->method = HTTP_UNSUBSCRIBE; |
|
|
parser->method = HTTP_UNSUBSCRIBE; |
|
|
|
|
|
} else if(ch == 'B') { |
|
|
|
|
|
parser->method = HTTP_UNBIND; |
|
|
} else { |
|
|
} else { |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
goto error; |
|
|
goto error; |
|
@ -1059,6 +1081,8 @@ reexecute: |
|
|
} |
|
|
} |
|
|
} else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { |
|
|
} else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { |
|
|
parser->method = HTTP_PROPPATCH; |
|
|
parser->method = HTTP_PROPPATCH; |
|
|
|
|
|
} else if (parser->index == 3 && parser->method == HTTP_UNLOCK && ch == 'I') { |
|
|
|
|
|
parser->method = HTTP_UNLINK; |
|
|
} else { |
|
|
} else { |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
SET_ERRNO(HPE_INVALID_METHOD); |
|
|
goto error; |
|
|
goto error; |
|
@ -1828,11 +1852,12 @@ reexecute: |
|
|
|
|
|
|
|
|
case s_headers_done: |
|
|
case s_headers_done: |
|
|
{ |
|
|
{ |
|
|
|
|
|
int hasBody; |
|
|
STRICT_CHECK(ch != LF); |
|
|
STRICT_CHECK(ch != LF); |
|
|
|
|
|
|
|
|
parser->nread = 0; |
|
|
parser->nread = 0; |
|
|
|
|
|
|
|
|
int hasBody = parser->flags & F_CHUNKED || |
|
|
hasBody = parser->flags & F_CHUNKED || |
|
|
(parser->content_length > 0 && parser->content_length != ULLONG_MAX); |
|
|
(parser->content_length > 0 && parser->content_length != ULLONG_MAX); |
|
|
if (parser->upgrade && (parser->method == HTTP_CONNECT || |
|
|
if (parser->upgrade && (parser->method == HTTP_CONNECT || |
|
|
(parser->flags & F_SKIPBODY) || !hasBody)) { |
|
|
(parser->flags & F_SKIPBODY) || !hasBody)) { |
|
@ -1857,8 +1882,7 @@ reexecute: |
|
|
/* Content-Length header given and non-zero */ |
|
|
/* Content-Length header given and non-zero */ |
|
|
UPDATE_STATE(s_body_identity); |
|
|
UPDATE_STATE(s_body_identity); |
|
|
} else { |
|
|
} else { |
|
|
if (parser->type == HTTP_REQUEST || |
|
|
if (!http_message_needs_eof(parser)) { |
|
|
!http_message_needs_eof(parser)) { |
|
|
|
|
|
/* Assume content-length 0 - read the next */ |
|
|
/* Assume content-length 0 - read the next */ |
|
|
UPDATE_STATE(NEW_MESSAGE()); |
|
|
UPDATE_STATE(NEW_MESSAGE()); |
|
|
CALLBACK_NOTIFY(message_complete); |
|
|
CALLBACK_NOTIFY(message_complete); |
|
@ -2153,15 +2177,13 @@ http_parser_settings_init(http_parser_settings *settings) |
|
|
|
|
|
|
|
|
const char * |
|
|
const char * |
|
|
http_errno_name(enum http_errno err) { |
|
|
http_errno_name(enum http_errno err) { |
|
|
assert(((size_t) err) < |
|
|
assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); |
|
|
(sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); |
|
|
|
|
|
return http_strerror_tab[err].name; |
|
|
return http_strerror_tab[err].name; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const char * |
|
|
const char * |
|
|
http_errno_description(enum http_errno err) { |
|
|
http_errno_description(enum http_errno err) { |
|
|
assert(((size_t) err) < |
|
|
assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); |
|
|
(sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); |
|
|
|
|
|
return http_strerror_tab[err].description; |
|
|
return http_strerror_tab[err].description; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -2214,6 +2236,23 @@ http_parse_host_char(enum http_host_state s, const char ch) { |
|
|
return s_http_host_v6; |
|
|
return s_http_host_v6; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (s == s_http_host_v6 && ch == '%') { |
|
|
|
|
|
return s_http_host_v6_zone_start; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case s_http_host_v6_zone: |
|
|
|
|
|
if (ch == ']') { |
|
|
|
|
|
return s_http_host_v6_end; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* FALLTHROUGH */ |
|
|
|
|
|
case s_http_host_v6_zone_start: |
|
|
|
|
|
/* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ |
|
|
|
|
|
if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || |
|
|
|
|
|
ch == '~') { |
|
|
|
|
|
return s_http_host_v6_zone; |
|
|
|
|
|
} |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case s_http_host_port: |
|
|
case s_http_host_port: |
|
@ -2232,6 +2271,7 @@ http_parse_host_char(enum http_host_state s, const char ch) { |
|
|
|
|
|
|
|
|
static int |
|
|
static int |
|
|
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { |
|
|
http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { |
|
|
|
|
|
assert(u->field_set & (1 << UF_HOST)); |
|
|
enum http_host_state s; |
|
|
enum http_host_state s; |
|
|
|
|
|
|
|
|
const char *p; |
|
|
const char *p; |
|
@ -2263,6 +2303,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { |
|
|
u->field_data[UF_HOST].len++; |
|
|
u->field_data[UF_HOST].len++; |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case s_http_host_v6_zone_start: |
|
|
|
|
|
case s_http_host_v6_zone: |
|
|
|
|
|
u->field_data[UF_HOST].len++; |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
case s_http_host_port: |
|
|
case s_http_host_port: |
|
|
if (s != s_http_host_port) { |
|
|
if (s != s_http_host_port) { |
|
|
u->field_data[UF_PORT].off = p - buf; |
|
|
u->field_data[UF_PORT].off = p - buf; |
|
@ -2292,6 +2337,8 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { |
|
|
case s_http_host_start: |
|
|
case s_http_host_start: |
|
|
case s_http_host_v6_start: |
|
|
case s_http_host_v6_start: |
|
|
case s_http_host_v6: |
|
|
case s_http_host_v6: |
|
|
|
|
|
case s_http_host_v6_zone_start: |
|
|
|
|
|
case s_http_host_v6_zone: |
|
|
case s_http_host_port_start: |
|
|
case s_http_host_port_start: |
|
|
case s_http_userinfo: |
|
|
case s_http_userinfo: |
|
|
case s_http_userinfo_start: |
|
|
case s_http_userinfo_start: |
|
@ -2303,6 +2350,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
http_parser_url_init(struct http_parser_url *u) { |
|
|
|
|
|
memset(u, 0, sizeof(*u)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
int |
|
|
int |
|
|
http_parser_parse_url(const char *buf, size_t buflen, int is_connect, |
|
|
http_parser_parse_url(const char *buf, size_t buflen, int is_connect, |
|
|
struct http_parser_url *u) |
|
|
struct http_parser_url *u) |
|
@ -2376,7 +2428,12 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, |
|
|
|
|
|
|
|
|
/* host must be present if there is a schema */ |
|
|
/* host must be present if there is a schema */ |
|
|
/* parsing http:///toto will fail */ |
|
|
/* parsing http:///toto will fail */ |
|
|
if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { |
|
|
if ((u->field_set & (1 << UF_SCHEMA)) && |
|
|
|
|
|
(u->field_set & (1 << UF_HOST)) == 0) { |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (u->field_set & (1 << UF_HOST)) { |
|
|
if (http_parse_host(buf, u, found_at) != 0) { |
|
|
if (http_parse_host(buf, u, found_at) != 0) { |
|
|
return 1; |
|
|
return 1; |
|
|
} |
|
|
} |
|
|