Commit 3b5b5ce2 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Update http-parser to 8d9e5db981b623fffc93657abacdc80270cbee58

parent 694cd07f
......@@ -972,7 +972,7 @@ int htp_msg_begincb(http_parser *htp)
} // namespace
namespace {
int htp_status_completecb(http_parser *htp)
int htp_statuscb(http_parser *htp, const char *at, size_t length)
{
auto client = static_cast<HttpClient*>(htp->data);
client->upgrade_response_status_code = htp->status_code;
......@@ -993,7 +993,7 @@ namespace {
http_parser_settings htp_hooks = {
htp_msg_begincb, // http_cb on_message_begin;
nullptr, // http_data_cb on_url;
htp_status_completecb, // http_cb on_status_complete;
htp_statuscb, // http_data_cb on_status;
nullptr, // http_data_cb on_header_field;
nullptr, // http_data_cb on_header_value;
nullptr, // http_cb on_headers_complete;
......
......@@ -529,7 +529,7 @@ namespace {
http_parser_settings htp_hooks = {
nullptr, // http_cb on_message_begin;
nullptr, // http_data_cb on_url;
nullptr, // http_cb on_status_complete;
nullptr, // http_data_cb on_status;
nullptr, // http_data_cb on_header_field;
nullptr, // http_data_cb on_header_value;
htp_hdrs_completecb, // http_cb on_headers_complete;
......
......@@ -490,7 +490,7 @@ namespace {
http_parser_settings htp_hooks = {
nullptr, // http_cb on_message_begin;
nullptr, // http_data_cb on_url;
nullptr, // http_cb on_status_complete;
nullptr, // http_data_cb on_status;
htp_hdr_keycb, // http_data_cb on_header_field;
htp_hdr_valcb, // http_data_cb on_header_value;
htp_hdrs_completecb, // http_cb on_headers_complete;
......
......@@ -248,7 +248,7 @@ namespace {
http_parser_settings htp_hooks = {
htp_msg_begin, // http_cb on_message_begin;
htp_uricb, // http_data_cb on_url;
nullptr, // http_cb on_status_complete;
nullptr, // http_data_cb on_status;
htp_hdr_keycb, // http_data_cb on_header_field;
htp_hdr_valcb, // http_data_cb on_header_value;
htp_hdrs_completecb, // http_cb on_headers_complete;
......
......@@ -39,3 +39,12 @@ BogDan Vatra <bogdan@kde.org>
Peter Faiman <peter@thepicard.org>
Corey Richardson <corey@octayn.net>
Tóth Tamás <tomika_nospam@freemail.hu>
Patrik Stutz <patrik.stutz@gmail.com>
Cam Swords <cam.swords@gmail.com>
Chris Dickinson <christopher.s.dickinson@gmail.com>
Uli Köhler <ukoehler@btronik.de>
Charlie Somerville <charlie@charliesomerville.com>
Fedor Indutny <fedor.indutny@gmail.com>
runner <runner.mei@gmail.com>
Alexis Campailla <alexis@janeasystems.com>
David Wragg <david@wragg.org>
......@@ -61,7 +61,7 @@ if (recved < 0) {
}
/* Start up / continue the parser.
* Note we pass recved==0 to signal that EOF has been recieved.
* Note we pass recved==0 to signal that EOF has been received.
*/
nparsed = http_parser_execute(parser, &settings, buf, recved);
......
......@@ -111,14 +111,14 @@ int main(int argc, char* argv[]) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
perror("fopen");
return EXIT_FAILURE;
goto fail;
}
fseek(file, 0, SEEK_END);
long file_length = ftell(file);
if (file_length == -1) {
perror("ftell");
return EXIT_FAILURE;
goto fail;
}
fseek(file, 0, SEEK_SET);
......@@ -126,7 +126,7 @@ int main(int argc, char* argv[]) {
if (fread(data, 1, file_length, file) != (size_t)file_length) {
fprintf(stderr, "couldn't read entire file\n");
free(data);
return EXIT_FAILURE;
goto fail;
}
http_parser_settings settings;
......@@ -149,8 +149,12 @@ int main(int argc, char* argv[]) {
"Error: %s (%s)\n",
http_errno_description(HTTP_PARSER_ERRNO(&parser)),
http_errno_name(HTTP_PARSER_ERRNO(&parser)));
return EXIT_FAILURE;
goto fail;
}
return EXIT_SUCCESS;
fail:
fclose(file);
return EXIT_FAILURE;
}
......@@ -248,6 +248,7 @@ enum state
, s_res_http_minor
, s_res_first_status_code
, s_res_status_code
, s_res_status_start
, s_res_status
, s_res_line_almost_done
......@@ -279,6 +280,9 @@ enum state
, s_header_field_start
, s_header_field
, s_header_value_discard_ws
, s_header_value_discard_ws_almost_done
, s_header_value_discard_lws
, s_header_value_start
, s_header_value
, s_header_value_lws
......@@ -581,6 +585,7 @@ size_t http_parser_execute (http_parser *parser,
const char *header_value_mark = 0;
const char *url_mark = 0;
const char *body_mark = 0;
const char *status_mark = 0;
/* We're in an error state. Don't bother doing anything. */
if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
......@@ -627,6 +632,9 @@ size_t http_parser_execute (http_parser *parser,
case s_req_fragment:
url_mark = data;
break;
case s_res_status:
status_mark = data;
break;
}
for (p=data; p != data + len; p++) {
......@@ -645,7 +653,7 @@ size_t http_parser_execute (http_parser *parser,
* than any reasonable request or response so this should never affect
* day-to-day operation.
*/
if (parser->nread > HTTP_MAX_HEADER_SIZE) {
if (parser->nread > (HTTP_MAX_HEADER_SIZE)) {
SET_ERRNO(HPE_HEADER_OVERFLOW);
goto error;
}
......@@ -833,7 +841,7 @@ size_t http_parser_execute (http_parser *parser,
if (!IS_NUM(ch)) {
switch (ch) {
case ' ':
parser->state = s_res_status;
parser->state = s_res_status_start;
break;
case CR:
parser->state = s_res_line_almost_done;
......@@ -859,24 +867,42 @@ size_t http_parser_execute (http_parser *parser,
break;
}
case s_res_status_start:
{
if (ch == CR) {
parser->state = s_res_line_almost_done;
break;
}
if (ch == LF) {
parser->state = s_header_field_start;
break;
}
MARK(status);
parser->state = s_res_status;
parser->index = 0;
break;
}
case s_res_status:
/* the human readable status. e.g. "NOT FOUND"
* we are not humans so just ignore this */
if (ch == CR) {
parser->state = s_res_line_almost_done;
CALLBACK_DATA(status);
break;
}
if (ch == LF) {
parser->state = s_header_field_start;
CALLBACK_DATA(status);
break;
}
break;
case s_res_line_almost_done:
STRICT_CHECK(ch != LF);
parser->state = s_header_field_start;
CALLBACK_NOTIFY(status_complete);
break;
case s_start_req:
......@@ -1357,7 +1383,7 @@ size_t http_parser_execute (http_parser *parser,
}
if (ch == ':') {
parser->state = s_header_value_start;
parser->state = s_header_value_discard_ws;
CALLBACK_DATA(header_field);
break;
}
......@@ -1378,28 +1404,28 @@ size_t http_parser_execute (http_parser *parser,
goto error;
}
case s_header_value_start:
{
case s_header_value_discard_ws:
if (ch == ' ' || ch == '\t') break;
MARK(header_value);
parser->state = s_header_value;
parser->index = 0;
if (ch == CR) {
parser->header_state = h_general;
parser->state = s_header_almost_done;
CALLBACK_DATA(header_value);
parser->state = s_header_value_discard_ws_almost_done;
break;
}
if (ch == LF) {
parser->state = s_header_field_start;
CALLBACK_DATA(header_value);
parser->state = s_header_value_discard_lws;
break;
}
/* FALLTHROUGH */
case s_header_value_start:
{
MARK(header_value);
parser->state = s_header_value;
parser->index = 0;
c = LOWER(ch);
switch (parser->header_state) {
......@@ -1486,8 +1512,8 @@ size_t http_parser_execute (http_parser *parser,
t *= 10;
t += ch - '0';
/* Overflow? */
if (t < parser->content_length || t == ULLONG_MAX) {
/* Overflow? Test against a conservative limit for simplicity. */
if ((ULLONG_MAX - 10) / 10 < parser->content_length) {
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
......@@ -1547,7 +1573,17 @@ size_t http_parser_execute (http_parser *parser,
STRICT_CHECK(ch != LF);
parser->state = s_header_value_lws;
break;
}
case s_header_value_lws:
{
if (ch == ' ' || ch == '\t') {
parser->state = s_header_value_start;
goto reexecute_byte;
}
/* finished the header */
switch (parser->header_state) {
case h_connection_keep_alive:
parser->flags |= F_CONNECTION_KEEP_ALIVE;
......@@ -1562,19 +1598,29 @@ size_t http_parser_execute (http_parser *parser,
break;
}
parser->state = s_header_field_start;
goto reexecute_byte;
}
case s_header_value_discard_ws_almost_done:
{
STRICT_CHECK(ch != LF);
parser->state = s_header_value_discard_lws;
break;
}
case s_header_value_lws:
case s_header_value_discard_lws:
{
if (ch == ' ' || ch == '\t')
parser->state = s_header_value_start;
else
{
if (ch == ' ' || ch == '\t') {
parser->state = s_header_value_discard_ws;
break;
} else {
/* header value was empty */
MARK(header_value);
parser->state = s_header_field_start;
CALLBACK_DATA_NOADVANCE(header_value);
goto reexecute_byte;
}
break;
}
case s_headers_almost_done:
......@@ -1759,8 +1805,8 @@ size_t http_parser_execute (http_parser *parser,
t *= 16;
t += unhex_val;
/* Overflow? */
if (t < parser->content_length || t == ULLONG_MAX) {
/* Overflow? Test against a conservative limit for simplicity. */
if ((ULLONG_MAX - 16) / 16 < parser->content_length) {
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
goto error;
}
......@@ -1854,12 +1900,14 @@ size_t http_parser_execute (http_parser *parser,
assert(((header_field_mark ? 1 : 0) +
(header_value_mark ? 1 : 0) +
(url_mark ? 1 : 0) +
(body_mark ? 1 : 0)) <= 1);
(body_mark ? 1 : 0) +
(status_mark ? 1 : 0)) <= 1);
CALLBACK_DATA_NOADVANCE(header_field);
CALLBACK_DATA_NOADVANCE(header_value);
CALLBACK_DATA_NOADVANCE(url);
CALLBACK_DATA_NOADVANCE(body);
CALLBACK_DATA_NOADVANCE(status);
return len;
......@@ -2094,7 +2142,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
u->port = u->field_set = 0;
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
old_uf = UF_MAX;
uf = old_uf = UF_MAX;
for (p = buf; p < buf + buflen; p++) {
s = parse_url_char(s, *p);
......
......@@ -26,7 +26,7 @@ extern "C" {
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 1
#define HTTP_PARSER_VERSION_MINOR 3
#define HTTP_PARSER_VERSION_PATCH 0
#include <sys/types.h>
......@@ -52,9 +52,16 @@ typedef unsigned __int64 uint64_t;
# define HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed */
#define HTTP_MAX_HEADER_SIZE (80*1024)
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
......@@ -143,13 +150,13 @@ enum flags
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_status_complete, "the on_status_complete callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
......@@ -193,11 +200,11 @@ enum http_errno {
struct http_parser {
/** PRIVATE **/
unsigned char type : 2; /* enum http_parser_type */
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned char state; /* enum state from http_parser.c */
unsigned char header_state; /* enum header_state from http_parser.c */
unsigned char index; /* index into current matcher */
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 8; /* enum state from http_parser.c */
unsigned int header_state : 8; /* enum header_state from http_parser.c */
unsigned int index : 8; /* index into current matcher */
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
......@@ -205,16 +212,16 @@ struct http_parser {
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned short status_code; /* responses only */
unsigned char method; /* requests only */
unsigned char http_errno : 7;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned char upgrade : 1;
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
......@@ -224,7 +231,7 @@ struct http_parser {
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_cb on_status_complete;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment