http-parser updated to latest version.
This commit is contained in:
parent
c80ef54b60
commit
b0dda2b5b3
2 changed files with 101 additions and 34 deletions
128
src/3rdparty/http-parser/http_parser.c
vendored
128
src/3rdparty/http-parser/http_parser.c
vendored
|
@ -381,7 +381,10 @@ enum header_states
|
||||||
, h_transfer_encoding
|
, h_transfer_encoding
|
||||||
, h_upgrade
|
, h_upgrade
|
||||||
|
|
||||||
|
, h_matching_transfer_encoding_token_start
|
||||||
, h_matching_transfer_encoding_chunked
|
, h_matching_transfer_encoding_chunked
|
||||||
|
, h_matching_transfer_encoding_token
|
||||||
|
|
||||||
, h_matching_connection_token_start
|
, h_matching_connection_token_start
|
||||||
, h_matching_connection_keep_alive
|
, h_matching_connection_keep_alive
|
||||||
, h_matching_connection_close
|
, h_matching_connection_close
|
||||||
|
@ -1257,9 +1260,9 @@ reexecute:
|
||||||
|
|
||||||
switch (parser->header_state) {
|
switch (parser->header_state) {
|
||||||
case h_general: {
|
case h_general: {
|
||||||
size_t limit = data + len - p;
|
size_t left = data + len - p;
|
||||||
limit = MIN(limit, max_header_size);
|
const char* pe = p + MIN(left, max_header_size);
|
||||||
while (p+1 < data + limit && TOKEN(p[1])) {
|
while (p+1 < pe && TOKEN(p[1])) {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1335,6 +1338,7 @@ reexecute:
|
||||||
parser->header_state = h_general;
|
parser->header_state = h_general;
|
||||||
} else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
|
} else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
|
||||||
parser->header_state = h_transfer_encoding;
|
parser->header_state = h_transfer_encoding;
|
||||||
|
parser->flags |= F_TRANSFER_ENCODING;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1416,10 +1420,14 @@ reexecute:
|
||||||
if ('c' == c) {
|
if ('c' == c) {
|
||||||
parser->header_state = h_matching_transfer_encoding_chunked;
|
parser->header_state = h_matching_transfer_encoding_chunked;
|
||||||
} else {
|
} else {
|
||||||
parser->header_state = h_general;
|
parser->header_state = h_matching_transfer_encoding_token;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Multi-value `Transfer-Encoding` header */
|
||||||
|
case h_matching_transfer_encoding_token_start:
|
||||||
|
break;
|
||||||
|
|
||||||
case h_content_length:
|
case h_content_length:
|
||||||
if (UNLIKELY(!IS_NUM(ch))) {
|
if (UNLIKELY(!IS_NUM(ch))) {
|
||||||
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
||||||
|
@ -1496,28 +1504,25 @@ reexecute:
|
||||||
|
|
||||||
switch (h_state) {
|
switch (h_state) {
|
||||||
case h_general:
|
case h_general:
|
||||||
{
|
{
|
||||||
const char* p_cr;
|
size_t left = data + len - p;
|
||||||
const char* p_lf;
|
const char* pe = p + MIN(left, max_header_size);
|
||||||
size_t limit = data + len - p;
|
|
||||||
|
|
||||||
limit = MIN(limit, max_header_size);
|
for (; p != pe; p++) {
|
||||||
|
ch = *p;
|
||||||
p_cr = (const char*) memchr(p, CR, limit);
|
if (ch == CR || ch == LF) {
|
||||||
p_lf = (const char*) memchr(p, LF, limit);
|
--p;
|
||||||
if (p_cr != NULL) {
|
break;
|
||||||
if (p_lf != NULL && p_cr >= p_lf)
|
}
|
||||||
p = p_lf;
|
if (!lenient && !IS_HEADER_CHAR(ch)) {
|
||||||
else
|
SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
|
||||||
p = p_cr;
|
goto error;
|
||||||
} else if (UNLIKELY(p_lf != NULL)) {
|
}
|
||||||
p = p_lf;
|
}
|
||||||
} else {
|
if (p == data + len)
|
||||||
p = data + len;
|
--p;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
--p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case h_connection:
|
case h_connection:
|
||||||
case h_transfer_encoding:
|
case h_transfer_encoding:
|
||||||
|
@ -1566,16 +1571,41 @@ reexecute:
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Transfer-Encoding: chunked */
|
/* Transfer-Encoding: chunked */
|
||||||
|
case h_matching_transfer_encoding_token_start:
|
||||||
|
/* looking for 'Transfer-Encoding: chunked' */
|
||||||
|
if ('c' == c) {
|
||||||
|
h_state = h_matching_transfer_encoding_chunked;
|
||||||
|
} else if (STRICT_TOKEN(c)) {
|
||||||
|
/* TODO(indutny): similar code below does this, but why?
|
||||||
|
* At the very least it seems to be inconsistent given that
|
||||||
|
* h_matching_transfer_encoding_token does not check for
|
||||||
|
* `STRICT_TOKEN`
|
||||||
|
*/
|
||||||
|
h_state = h_matching_transfer_encoding_token;
|
||||||
|
} else if (c == ' ' || c == '\t') {
|
||||||
|
/* Skip lws */
|
||||||
|
} else {
|
||||||
|
h_state = h_general;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case h_matching_transfer_encoding_chunked:
|
case h_matching_transfer_encoding_chunked:
|
||||||
parser->index++;
|
parser->index++;
|
||||||
if (parser->index > sizeof(CHUNKED)-1
|
if (parser->index > sizeof(CHUNKED)-1
|
||||||
|| c != CHUNKED[parser->index]) {
|
|| c != CHUNKED[parser->index]) {
|
||||||
h_state = h_general;
|
h_state = h_matching_transfer_encoding_token;
|
||||||
} else if (parser->index == sizeof(CHUNKED)-2) {
|
} else if (parser->index == sizeof(CHUNKED)-2) {
|
||||||
h_state = h_transfer_encoding_chunked;
|
h_state = h_transfer_encoding_chunked;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case h_matching_transfer_encoding_token:
|
||||||
|
if (ch == ',') {
|
||||||
|
h_state = h_matching_transfer_encoding_token_start;
|
||||||
|
parser->index = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case h_matching_connection_token_start:
|
case h_matching_connection_token_start:
|
||||||
/* looking for 'Connection: keep-alive' */
|
/* looking for 'Connection: keep-alive' */
|
||||||
if (c == 'k') {
|
if (c == 'k') {
|
||||||
|
@ -1634,7 +1664,7 @@ reexecute:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case h_transfer_encoding_chunked:
|
case h_transfer_encoding_chunked:
|
||||||
if (ch != ' ') h_state = h_general;
|
if (ch != ' ') h_state = h_matching_transfer_encoding_token;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case h_connection_keep_alive:
|
case h_connection_keep_alive:
|
||||||
|
@ -1768,12 +1798,17 @@ reexecute:
|
||||||
REEXECUTE();
|
REEXECUTE();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cannot use chunked encoding and a content-length header together
|
/* Cannot us transfer-encoding and a content-length header together
|
||||||
per the HTTP specification. */
|
per the HTTP specification. (RFC 7230 Section 3.3.3) */
|
||||||
if ((parser->flags & F_CHUNKED) &&
|
if ((parser->flags & F_TRANSFER_ENCODING) &&
|
||||||
(parser->flags & F_CONTENTLENGTH)) {
|
(parser->flags & F_CONTENTLENGTH)) {
|
||||||
SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
|
/* Allow it for lenient parsing as long as `Transfer-Encoding` is
|
||||||
goto error;
|
* not `chunked`
|
||||||
|
*/
|
||||||
|
if (!lenient || (parser->flags & F_CHUNKED)) {
|
||||||
|
SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UPDATE_STATE(s_headers_done);
|
UPDATE_STATE(s_headers_done);
|
||||||
|
@ -1848,8 +1883,31 @@ reexecute:
|
||||||
UPDATE_STATE(NEW_MESSAGE());
|
UPDATE_STATE(NEW_MESSAGE());
|
||||||
CALLBACK_NOTIFY(message_complete);
|
CALLBACK_NOTIFY(message_complete);
|
||||||
} else if (parser->flags & F_CHUNKED) {
|
} else if (parser->flags & F_CHUNKED) {
|
||||||
/* chunked encoding - ignore Content-Length header */
|
/* chunked encoding - ignore Content-Length header,
|
||||||
|
* prepare for a chunk */
|
||||||
UPDATE_STATE(s_chunk_size_start);
|
UPDATE_STATE(s_chunk_size_start);
|
||||||
|
} else if (parser->flags & F_TRANSFER_ENCODING) {
|
||||||
|
if (parser->type == HTTP_REQUEST && !lenient) {
|
||||||
|
/* RFC 7230 3.3.3 */
|
||||||
|
|
||||||
|
/* If a Transfer-Encoding header field
|
||||||
|
* is present in a request and the chunked transfer coding is not
|
||||||
|
* the final encoding, the message body length cannot be determined
|
||||||
|
* reliably; the server MUST respond with the 400 (Bad Request)
|
||||||
|
* status code and then close the connection.
|
||||||
|
*/
|
||||||
|
SET_ERRNO(HPE_INVALID_TRANSFER_ENCODING);
|
||||||
|
RETURN(p - data); /* Error */
|
||||||
|
} else {
|
||||||
|
/* RFC 7230 3.3.3 */
|
||||||
|
|
||||||
|
/* If a Transfer-Encoding header field is present in a response and
|
||||||
|
* the chunked transfer coding is not the final encoding, the
|
||||||
|
* message body length is determined by reading the connection until
|
||||||
|
* it is closed by the server.
|
||||||
|
*/
|
||||||
|
UPDATE_STATE(s_body_identity_eof);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (parser->content_length == 0) {
|
if (parser->content_length == 0) {
|
||||||
/* Content-Length header given but zero: Content-Length: 0\r\n */
|
/* Content-Length header given but zero: Content-Length: 0\r\n */
|
||||||
|
@ -2103,6 +2161,12 @@ http_message_needs_eof (const http_parser *parser)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RFC 7230 3.3.3, see `s_headers_almost_done` */
|
||||||
|
if ((parser->flags & F_TRANSFER_ENCODING) &&
|
||||||
|
(parser->flags & F_CHUNKED) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
|
if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
7
src/3rdparty/http-parser/http_parser.h
vendored
7
src/3rdparty/http-parser/http_parser.h
vendored
|
@ -27,7 +27,7 @@ extern "C" {
|
||||||
/* Also update SONAME in the Makefile whenever you change these. */
|
/* Also update SONAME in the Makefile whenever you change these. */
|
||||||
#define HTTP_PARSER_VERSION_MAJOR 2
|
#define HTTP_PARSER_VERSION_MAJOR 2
|
||||||
#define HTTP_PARSER_VERSION_MINOR 9
|
#define HTTP_PARSER_VERSION_MINOR 9
|
||||||
#define HTTP_PARSER_VERSION_PATCH 0
|
#define HTTP_PARSER_VERSION_PATCH 3
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__) && \
|
#if defined(_WIN32) && !defined(__MINGW32__) && \
|
||||||
|
@ -225,6 +225,7 @@ enum flags
|
||||||
, F_UPGRADE = 1 << 5
|
, F_UPGRADE = 1 << 5
|
||||||
, F_SKIPBODY = 1 << 6
|
, F_SKIPBODY = 1 << 6
|
||||||
, F_CONTENTLENGTH = 1 << 7
|
, F_CONTENTLENGTH = 1 << 7
|
||||||
|
, F_TRANSFER_ENCODING = 1 << 8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -271,6 +272,8 @@ enum flags
|
||||||
"unexpected content-length header") \
|
"unexpected content-length header") \
|
||||||
XX(INVALID_CHUNK_SIZE, \
|
XX(INVALID_CHUNK_SIZE, \
|
||||||
"invalid character in chunk size header") \
|
"invalid character in chunk size header") \
|
||||||
|
XX(INVALID_TRANSFER_ENCODING, \
|
||||||
|
"request has invalid transfer-encoding") \
|
||||||
XX(INVALID_CONSTANT, "invalid constant string") \
|
XX(INVALID_CONSTANT, "invalid constant string") \
|
||||||
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
|
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
|
||||||
XX(STRICT, "strict mode assertion failed") \
|
XX(STRICT, "strict mode assertion failed") \
|
||||||
|
@ -293,11 +296,11 @@ enum http_errno {
|
||||||
struct http_parser {
|
struct http_parser {
|
||||||
/** PRIVATE **/
|
/** PRIVATE **/
|
||||||
unsigned int type : 2; /* enum http_parser_type */
|
unsigned int type : 2; /* enum http_parser_type */
|
||||||
unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
|
|
||||||
unsigned int state : 7; /* enum state from http_parser.c */
|
unsigned int state : 7; /* enum state from http_parser.c */
|
||||||
unsigned int header_state : 7; /* enum header_state from http_parser.c */
|
unsigned int header_state : 7; /* enum header_state from http_parser.c */
|
||||||
unsigned int index : 7; /* index into current matcher */
|
unsigned int index : 7; /* index into current matcher */
|
||||||
unsigned int lenient_http_headers : 1;
|
unsigned int lenient_http_headers : 1;
|
||||||
|
unsigned int flags : 16; /* F_* values from 'flags' enum; semi-public */
|
||||||
|
|
||||||
uint32_t nread; /* # bytes read in various scenarios */
|
uint32_t nread; /* # bytes read in various scenarios */
|
||||||
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
|
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue