Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 50 additions & 8 deletions test/bench/parser/nodejs-parser/http_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,10 @@ enum header_states
, h_transfer_encoding
, h_upgrade

, h_matching_transfer_encoding_token_start
, h_matching_transfer_encoding_chunked
, h_matching_transfer_encoding_token

, h_matching_connection_token_start
, h_matching_connection_keep_alive
, h_matching_connection_close
Expand Down Expand Up @@ -1384,6 +1387,7 @@ size_t http_parser_execute (http_parser *parser,
parser->header_state = h_general;
} else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
parser->header_state = h_transfer_encoding;
parser->flags |= F_TRANSFER_ENCODING;
}
break;

Expand Down Expand Up @@ -1464,10 +1468,14 @@ size_t http_parser_execute (http_parser *parser,
if ('c' == c) {
parser->header_state = h_matching_transfer_encoding_chunked;
} else {
parser->header_state = h_general;
parser->header_state = h_matching_transfer_encoding_token;
}
break;

/* Multi-value `Transfer-Encoding` header */
case h_matching_transfer_encoding_token_start:
break;

case h_content_length:
if (UNLIKELY(!IS_NUM(ch))) {
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
Expand Down Expand Up @@ -1657,7 +1665,7 @@ size_t http_parser_execute (http_parser *parser,
break;

case h_transfer_encoding_chunked:
if (ch != ' ') h_state = h_general;
if (ch != ' ') h_state = h_matching_transfer_encoding_token;
break;

case h_connection_keep_alive:
Expand Down Expand Up @@ -1782,12 +1790,17 @@ size_t http_parser_execute (http_parser *parser,
REEXECUTE();
}

/* Cannot use chunked encoding and a content-length header together
per the HTTP specification. */
if ((parser->flags & F_CHUNKED) &&
/* Cannot us transfer-encoding and a content-length header together
per the HTTP specification. (RFC 7230 Section 3.3.3) */
if ((parser->flags & F_TRANSFER_ENCODING) &&
(parser->flags & F_CONTENTLENGTH)) {
SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
goto error;
/* Allow it for lenient parsing as long as `Transfer-Encoding` is
* not `chunked`
*/
if (!lenient || (parser->flags & F_CHUNKED)) {
SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
goto error;
}
}

UPDATE_STATE(s_headers_done);
Expand Down Expand Up @@ -1853,8 +1866,31 @@ size_t http_parser_execute (http_parser *parser,
UPDATE_STATE(NEW_MESSAGE());
CALLBACK_NOTIFY(message_complete);
} 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);
} 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 {
if (parser->content_length == 0) {
/* Content-Length header given but zero: Content-Length: 0\r\n */
Expand Down Expand Up @@ -2106,6 +2142,12 @@ http_message_needs_eof (const http_parser *parser)
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) {
return 0;
}
Expand Down