Update http-parser to 8d9e5db981b623fffc93657abacdc80270cbee58
This commit is contained in:
parent
694cd07f1d
commit
3b5b5ce254
|
@ -972,7 +972,7 @@ int htp_msg_begincb(http_parser *htp)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
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);
|
auto client = static_cast<HttpClient*>(htp->data);
|
||||||
client->upgrade_response_status_code = htp->status_code;
|
client->upgrade_response_status_code = htp->status_code;
|
||||||
|
@ -993,7 +993,7 @@ namespace {
|
||||||
http_parser_settings htp_hooks = {
|
http_parser_settings htp_hooks = {
|
||||||
htp_msg_begincb, // http_cb on_message_begin;
|
htp_msg_begincb, // http_cb on_message_begin;
|
||||||
nullptr, // http_data_cb on_url;
|
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_field;
|
||||||
nullptr, // http_data_cb on_header_value;
|
nullptr, // http_data_cb on_header_value;
|
||||||
nullptr, // http_cb on_headers_complete;
|
nullptr, // http_cb on_headers_complete;
|
||||||
|
|
|
@ -529,7 +529,7 @@ namespace {
|
||||||
http_parser_settings htp_hooks = {
|
http_parser_settings htp_hooks = {
|
||||||
nullptr, // http_cb on_message_begin;
|
nullptr, // http_cb on_message_begin;
|
||||||
nullptr, // http_data_cb on_url;
|
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_field;
|
||||||
nullptr, // http_data_cb on_header_value;
|
nullptr, // http_data_cb on_header_value;
|
||||||
htp_hdrs_completecb, // http_cb on_headers_complete;
|
htp_hdrs_completecb, // http_cb on_headers_complete;
|
||||||
|
|
|
@ -490,7 +490,7 @@ namespace {
|
||||||
http_parser_settings htp_hooks = {
|
http_parser_settings htp_hooks = {
|
||||||
nullptr, // http_cb on_message_begin;
|
nullptr, // http_cb on_message_begin;
|
||||||
nullptr, // http_data_cb on_url;
|
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_keycb, // http_data_cb on_header_field;
|
||||||
htp_hdr_valcb, // http_data_cb on_header_value;
|
htp_hdr_valcb, // http_data_cb on_header_value;
|
||||||
htp_hdrs_completecb, // http_cb on_headers_complete;
|
htp_hdrs_completecb, // http_cb on_headers_complete;
|
||||||
|
|
|
@ -248,7 +248,7 @@ namespace {
|
||||||
http_parser_settings htp_hooks = {
|
http_parser_settings htp_hooks = {
|
||||||
htp_msg_begin, // http_cb on_message_begin;
|
htp_msg_begin, // http_cb on_message_begin;
|
||||||
htp_uricb, // http_data_cb on_url;
|
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_keycb, // http_data_cb on_header_field;
|
||||||
htp_hdr_valcb, // http_data_cb on_header_value;
|
htp_hdr_valcb, // http_data_cb on_header_value;
|
||||||
htp_hdrs_completecb, // http_cb on_headers_complete;
|
htp_hdrs_completecb, // http_cb on_headers_complete;
|
||||||
|
|
|
@ -39,3 +39,12 @@ BogDan Vatra <bogdan@kde.org>
|
||||||
Peter Faiman <peter@thepicard.org>
|
Peter Faiman <peter@thepicard.org>
|
||||||
Corey Richardson <corey@octayn.net>
|
Corey Richardson <corey@octayn.net>
|
||||||
Tóth Tamás <tomika_nospam@freemail.hu>
|
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.
|
/* 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);
|
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||||
|
|
||||||
|
|
|
@ -111,14 +111,14 @@ int main(int argc, char* argv[]) {
|
||||||
FILE* file = fopen(filename, "r");
|
FILE* file = fopen(filename, "r");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
perror("fopen");
|
perror("fopen");
|
||||||
return EXIT_FAILURE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
long file_length = ftell(file);
|
long file_length = ftell(file);
|
||||||
if (file_length == -1) {
|
if (file_length == -1) {
|
||||||
perror("ftell");
|
perror("ftell");
|
||||||
return EXIT_FAILURE;
|
goto fail;
|
||||||
}
|
}
|
||||||
fseek(file, 0, SEEK_SET);
|
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) {
|
if (fread(data, 1, file_length, file) != (size_t)file_length) {
|
||||||
fprintf(stderr, "couldn't read entire file\n");
|
fprintf(stderr, "couldn't read entire file\n");
|
||||||
free(data);
|
free(data);
|
||||||
return EXIT_FAILURE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
http_parser_settings settings;
|
http_parser_settings settings;
|
||||||
|
@ -149,8 +149,12 @@ int main(int argc, char* argv[]) {
|
||||||
"Error: %s (%s)\n",
|
"Error: %s (%s)\n",
|
||||||
http_errno_description(HTTP_PARSER_ERRNO(&parser)),
|
http_errno_description(HTTP_PARSER_ERRNO(&parser)),
|
||||||
http_errno_name(HTTP_PARSER_ERRNO(&parser)));
|
http_errno_name(HTTP_PARSER_ERRNO(&parser)));
|
||||||
return EXIT_FAILURE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
fclose(file);
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,6 +248,7 @@ enum state
|
||||||
, s_res_http_minor
|
, s_res_http_minor
|
||||||
, s_res_first_status_code
|
, s_res_first_status_code
|
||||||
, s_res_status_code
|
, s_res_status_code
|
||||||
|
, s_res_status_start
|
||||||
, s_res_status
|
, s_res_status
|
||||||
, s_res_line_almost_done
|
, s_res_line_almost_done
|
||||||
|
|
||||||
|
@ -279,6 +280,9 @@ enum state
|
||||||
|
|
||||||
, s_header_field_start
|
, s_header_field_start
|
||||||
, s_header_field
|
, 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_start
|
||||||
, s_header_value
|
, s_header_value
|
||||||
, s_header_value_lws
|
, s_header_value_lws
|
||||||
|
@ -581,6 +585,7 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
const char *header_value_mark = 0;
|
const char *header_value_mark = 0;
|
||||||
const char *url_mark = 0;
|
const char *url_mark = 0;
|
||||||
const char *body_mark = 0;
|
const char *body_mark = 0;
|
||||||
|
const char *status_mark = 0;
|
||||||
|
|
||||||
/* We're in an error state. Don't bother doing anything. */
|
/* We're in an error state. Don't bother doing anything. */
|
||||||
if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
|
if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
|
||||||
|
@ -627,6 +632,9 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
case s_req_fragment:
|
case s_req_fragment:
|
||||||
url_mark = data;
|
url_mark = data;
|
||||||
break;
|
break;
|
||||||
|
case s_res_status:
|
||||||
|
status_mark = data;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p=data; p != data + len; p++) {
|
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
|
* than any reasonable request or response so this should never affect
|
||||||
* day-to-day operation.
|
* day-to-day operation.
|
||||||
*/
|
*/
|
||||||
if (parser->nread > HTTP_MAX_HEADER_SIZE) {
|
if (parser->nread > (HTTP_MAX_HEADER_SIZE)) {
|
||||||
SET_ERRNO(HPE_HEADER_OVERFLOW);
|
SET_ERRNO(HPE_HEADER_OVERFLOW);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -833,7 +841,7 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
if (!IS_NUM(ch)) {
|
if (!IS_NUM(ch)) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case ' ':
|
case ' ':
|
||||||
parser->state = s_res_status;
|
parser->state = s_res_status_start;
|
||||||
break;
|
break;
|
||||||
case CR:
|
case CR:
|
||||||
parser->state = s_res_line_almost_done;
|
parser->state = s_res_line_almost_done;
|
||||||
|
@ -859,9 +867,8 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case s_res_status:
|
case s_res_status_start:
|
||||||
/* the human readable status. e.g. "NOT FOUND"
|
{
|
||||||
* we are not humans so just ignore this */
|
|
||||||
if (ch == CR) {
|
if (ch == CR) {
|
||||||
parser->state = s_res_line_almost_done;
|
parser->state = s_res_line_almost_done;
|
||||||
break;
|
break;
|
||||||
|
@ -871,12 +878,31 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
parser->state = s_header_field_start;
|
parser->state = s_header_field_start;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MARK(status);
|
||||||
|
parser->state = s_res_status;
|
||||||
|
parser->index = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case s_res_status:
|
||||||
|
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;
|
break;
|
||||||
|
|
||||||
case s_res_line_almost_done:
|
case s_res_line_almost_done:
|
||||||
STRICT_CHECK(ch != LF);
|
STRICT_CHECK(ch != LF);
|
||||||
parser->state = s_header_field_start;
|
parser->state = s_header_field_start;
|
||||||
CALLBACK_NOTIFY(status_complete);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case s_start_req:
|
case s_start_req:
|
||||||
|
@ -1357,7 +1383,7 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == ':') {
|
if (ch == ':') {
|
||||||
parser->state = s_header_value_start;
|
parser->state = s_header_value_discard_ws;
|
||||||
CALLBACK_DATA(header_field);
|
CALLBACK_DATA(header_field);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1378,28 +1404,28 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
case s_header_value_start:
|
case s_header_value_discard_ws:
|
||||||
{
|
|
||||||
if (ch == ' ' || ch == '\t') break;
|
if (ch == ' ' || ch == '\t') break;
|
||||||
|
|
||||||
MARK(header_value);
|
|
||||||
|
|
||||||
parser->state = s_header_value;
|
|
||||||
parser->index = 0;
|
|
||||||
|
|
||||||
if (ch == CR) {
|
if (ch == CR) {
|
||||||
parser->header_state = h_general;
|
parser->state = s_header_value_discard_ws_almost_done;
|
||||||
parser->state = s_header_almost_done;
|
|
||||||
CALLBACK_DATA(header_value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == LF) {
|
if (ch == LF) {
|
||||||
parser->state = s_header_field_start;
|
parser->state = s_header_value_discard_lws;
|
||||||
CALLBACK_DATA(header_value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
|
case s_header_value_start:
|
||||||
|
{
|
||||||
|
MARK(header_value);
|
||||||
|
|
||||||
|
parser->state = s_header_value;
|
||||||
|
parser->index = 0;
|
||||||
|
|
||||||
c = LOWER(ch);
|
c = LOWER(ch);
|
||||||
|
|
||||||
switch (parser->header_state) {
|
switch (parser->header_state) {
|
||||||
|
@ -1486,8 +1512,8 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
t *= 10;
|
t *= 10;
|
||||||
t += ch - '0';
|
t += ch - '0';
|
||||||
|
|
||||||
/* Overflow? */
|
/* Overflow? Test against a conservative limit for simplicity. */
|
||||||
if (t < parser->content_length || t == ULLONG_MAX) {
|
if ((ULLONG_MAX - 10) / 10 < parser->content_length) {
|
||||||
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -1547,7 +1573,17 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
STRICT_CHECK(ch != LF);
|
STRICT_CHECK(ch != LF);
|
||||||
|
|
||||||
parser->state = s_header_value_lws;
|
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) {
|
switch (parser->header_state) {
|
||||||
case h_connection_keep_alive:
|
case h_connection_keep_alive:
|
||||||
parser->flags |= F_CONNECTION_KEEP_ALIVE;
|
parser->flags |= F_CONNECTION_KEEP_ALIVE;
|
||||||
|
@ -1562,19 +1598,29 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case s_header_value_lws:
|
case s_header_value_discard_lws:
|
||||||
{
|
{
|
||||||
if (ch == ' ' || ch == '\t')
|
if (ch == ' ' || ch == '\t') {
|
||||||
parser->state = s_header_value_start;
|
parser->state = s_header_value_discard_ws;
|
||||||
else
|
break;
|
||||||
{
|
} else {
|
||||||
|
/* header value was empty */
|
||||||
|
MARK(header_value);
|
||||||
parser->state = s_header_field_start;
|
parser->state = s_header_field_start;
|
||||||
|
CALLBACK_DATA_NOADVANCE(header_value);
|
||||||
goto reexecute_byte;
|
goto reexecute_byte;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case s_headers_almost_done:
|
case s_headers_almost_done:
|
||||||
|
@ -1759,8 +1805,8 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
t *= 16;
|
t *= 16;
|
||||||
t += unhex_val;
|
t += unhex_val;
|
||||||
|
|
||||||
/* Overflow? */
|
/* Overflow? Test against a conservative limit for simplicity. */
|
||||||
if (t < parser->content_length || t == ULLONG_MAX) {
|
if ((ULLONG_MAX - 16) / 16 < parser->content_length) {
|
||||||
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -1854,12 +1900,14 @@ size_t http_parser_execute (http_parser *parser,
|
||||||
assert(((header_field_mark ? 1 : 0) +
|
assert(((header_field_mark ? 1 : 0) +
|
||||||
(header_value_mark ? 1 : 0) +
|
(header_value_mark ? 1 : 0) +
|
||||||
(url_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_field);
|
||||||
CALLBACK_DATA_NOADVANCE(header_value);
|
CALLBACK_DATA_NOADVANCE(header_value);
|
||||||
CALLBACK_DATA_NOADVANCE(url);
|
CALLBACK_DATA_NOADVANCE(url);
|
||||||
CALLBACK_DATA_NOADVANCE(body);
|
CALLBACK_DATA_NOADVANCE(body);
|
||||||
|
CALLBACK_DATA_NOADVANCE(status);
|
||||||
|
|
||||||
return len;
|
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;
|
u->port = u->field_set = 0;
|
||||||
s = is_connect ? s_req_server_start : s_req_spaces_before_url;
|
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++) {
|
for (p = buf; p < buf + buflen; p++) {
|
||||||
s = parse_url_char(s, *p);
|
s = parse_url_char(s, *p);
|
||||||
|
|
|
@ -26,7 +26,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 1
|
#define HTTP_PARSER_VERSION_MINOR 3
|
||||||
#define HTTP_PARSER_VERSION_PATCH 0
|
#define HTTP_PARSER_VERSION_PATCH 0
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -52,9 +52,16 @@ typedef unsigned __int64 uint64_t;
|
||||||
# define HTTP_PARSER_STRICT 1
|
# define HTTP_PARSER_STRICT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Maximium header size allowed */
|
/* Maximium header size allowed. If the macro is not defined
|
||||||
#define HTTP_MAX_HEADER_SIZE (80*1024)
|
* 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 http_parser;
|
||||||
typedef struct http_parser_settings http_parser_settings;
|
typedef struct http_parser_settings http_parser_settings;
|
||||||
|
@ -143,13 +150,13 @@ enum flags
|
||||||
\
|
\
|
||||||
/* Callback-related errors */ \
|
/* Callback-related errors */ \
|
||||||
XX(CB_message_begin, "the on_message_begin callback failed") \
|
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_url, "the on_url callback failed") \
|
||||||
XX(CB_header_field, "the on_header_field callback failed") \
|
XX(CB_header_field, "the on_header_field callback failed") \
|
||||||
XX(CB_header_value, "the on_header_value callback failed") \
|
XX(CB_header_value, "the on_header_value callback failed") \
|
||||||
XX(CB_headers_complete, "the on_headers_complete callback failed") \
|
XX(CB_headers_complete, "the on_headers_complete callback failed") \
|
||||||
XX(CB_body, "the on_body callback failed") \
|
XX(CB_body, "the on_body callback failed") \
|
||||||
XX(CB_message_complete, "the on_message_complete callback failed") \
|
XX(CB_message_complete, "the on_message_complete callback failed") \
|
||||||
|
XX(CB_status, "the on_status callback failed") \
|
||||||
\
|
\
|
||||||
/* Parsing-related errors */ \
|
/* Parsing-related errors */ \
|
||||||
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
||||||
|
@ -193,11 +200,11 @@ enum http_errno {
|
||||||
|
|
||||||
struct http_parser {
|
struct http_parser {
|
||||||
/** PRIVATE **/
|
/** PRIVATE **/
|
||||||
unsigned char type : 2; /* enum http_parser_type */
|
unsigned int type : 2; /* enum http_parser_type */
|
||||||
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
|
unsigned int flags : 6; /* F_* values from 'flags' enum; semi-public */
|
||||||
unsigned char state; /* enum state from http_parser.c */
|
unsigned int state : 8; /* enum state from http_parser.c */
|
||||||
unsigned char header_state; /* enum header_state from http_parser.c */
|
unsigned int header_state : 8; /* enum header_state from http_parser.c */
|
||||||
unsigned char index; /* index into current matcher */
|
unsigned int index : 8; /* index into current matcher */
|
||||||
|
|
||||||
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) */
|
||||||
|
@ -205,16 +212,16 @@ struct http_parser {
|
||||||
/** READ-ONLY **/
|
/** READ-ONLY **/
|
||||||
unsigned short http_major;
|
unsigned short http_major;
|
||||||
unsigned short http_minor;
|
unsigned short http_minor;
|
||||||
unsigned short status_code; /* responses only */
|
unsigned int status_code : 16; /* responses only */
|
||||||
unsigned char method; /* requests only */
|
unsigned int method : 8; /* requests only */
|
||||||
unsigned char http_errno : 7;
|
unsigned int http_errno : 7;
|
||||||
|
|
||||||
/* 1 = Upgrade header was present and the parser has exited because of that.
|
/* 1 = Upgrade header was present and the parser has exited because of that.
|
||||||
* 0 = No upgrade header present.
|
* 0 = No upgrade header present.
|
||||||
* Should be checked when http_parser_execute() returns in addition to
|
* Should be checked when http_parser_execute() returns in addition to
|
||||||
* error checking.
|
* error checking.
|
||||||
*/
|
*/
|
||||||
unsigned char upgrade : 1;
|
unsigned int upgrade : 1;
|
||||||
|
|
||||||
/** PUBLIC **/
|
/** PUBLIC **/
|
||||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||||
|
@ -224,7 +231,7 @@ struct http_parser {
|
||||||
struct http_parser_settings {
|
struct http_parser_settings {
|
||||||
http_cb on_message_begin;
|
http_cb on_message_begin;
|
||||||
http_data_cb on_url;
|
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_field;
|
||||||
http_data_cb on_header_value;
|
http_data_cb on_header_value;
|
||||||
http_cb on_headers_complete;
|
http_cb on_headers_complete;
|
||||||
|
|
|
@ -26,6 +26,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
# undef strlcat
|
||||||
|
# undef strlncpy
|
||||||
|
# undef strlcpy
|
||||||
|
#endif /* defined(__APPLE__) */
|
||||||
|
|
||||||
#undef TRUE
|
#undef TRUE
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#undef FALSE
|
#undef FALSE
|
||||||
|
@ -44,6 +50,7 @@ struct message {
|
||||||
enum http_parser_type type;
|
enum http_parser_type type;
|
||||||
enum http_method method;
|
enum http_method method;
|
||||||
int status_code;
|
int status_code;
|
||||||
|
char response_status[MAX_ELEMENT_SIZE];
|
||||||
char request_path[MAX_ELEMENT_SIZE];
|
char request_path[MAX_ELEMENT_SIZE];
|
||||||
char request_url[MAX_ELEMENT_SIZE];
|
char request_url[MAX_ELEMENT_SIZE];
|
||||||
char fragment[MAX_ELEMENT_SIZE];
|
char fragment[MAX_ELEMENT_SIZE];
|
||||||
|
@ -601,8 +608,14 @@ const struct message requests[] =
|
||||||
" mno \r\n"
|
" mno \r\n"
|
||||||
"\t \tqrs\r\n"
|
"\t \tqrs\r\n"
|
||||||
"Line2: \t line2\t\r\n"
|
"Line2: \t line2\t\r\n"
|
||||||
|
"Line3:\r\n"
|
||||||
|
" line3\r\n"
|
||||||
|
"Line4: \r\n"
|
||||||
|
" \r\n"
|
||||||
|
"Connection:\r\n"
|
||||||
|
" close\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
,.should_keep_alive= TRUE
|
,.should_keep_alive= FALSE
|
||||||
,.message_complete_on_eof= FALSE
|
,.message_complete_on_eof= FALSE
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
|
@ -611,9 +624,12 @@ const struct message requests[] =
|
||||||
,.fragment= ""
|
,.fragment= ""
|
||||||
,.request_path= "/"
|
,.request_path= "/"
|
||||||
,.request_url= "/"
|
,.request_url= "/"
|
||||||
,.num_headers= 2
|
,.num_headers= 5
|
||||||
,.headers= { { "Line1", "abcdefghijklmno qrs" }
|
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
|
||||||
, { "Line2", "line2\t" }
|
, { "Line2", "line2\t" }
|
||||||
|
, { "Line3", "line3" }
|
||||||
|
, { "Line4", "" }
|
||||||
|
, { "Connection", "close" },
|
||||||
}
|
}
|
||||||
,.body= ""
|
,.body= ""
|
||||||
}
|
}
|
||||||
|
@ -897,6 +913,43 @@ const struct message requests[] =
|
||||||
,.body= ""
|
,.body= ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LINE_FOLDING_IN_HEADER_WITH_LF 34
|
||||||
|
, {.name= "line folding in header value"
|
||||||
|
,.type= HTTP_REQUEST
|
||||||
|
,.raw= "GET / HTTP/1.1\n"
|
||||||
|
"Line1: abc\n"
|
||||||
|
"\tdef\n"
|
||||||
|
" ghi\n"
|
||||||
|
"\t\tjkl\n"
|
||||||
|
" mno \n"
|
||||||
|
"\t \tqrs\n"
|
||||||
|
"Line2: \t line2\t\n"
|
||||||
|
"Line3:\n"
|
||||||
|
" line3\n"
|
||||||
|
"Line4: \n"
|
||||||
|
" \n"
|
||||||
|
"Connection:\n"
|
||||||
|
" close\n"
|
||||||
|
"\n"
|
||||||
|
,.should_keep_alive= FALSE
|
||||||
|
,.message_complete_on_eof= FALSE
|
||||||
|
,.http_major= 1
|
||||||
|
,.http_minor= 1
|
||||||
|
,.method= HTTP_GET
|
||||||
|
,.query_string= ""
|
||||||
|
,.fragment= ""
|
||||||
|
,.request_path= "/"
|
||||||
|
,.request_url= "/"
|
||||||
|
,.num_headers= 5
|
||||||
|
,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" }
|
||||||
|
, { "Line2", "line2\t" }
|
||||||
|
, { "Line3", "line3" }
|
||||||
|
, { "Line4", "" }
|
||||||
|
, { "Connection", "close" },
|
||||||
|
}
|
||||||
|
,.body= ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
, {.name= NULL } /* sentinel */
|
, {.name= NULL } /* sentinel */
|
||||||
};
|
};
|
||||||
|
@ -927,6 +980,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 301
|
,.status_code= 301
|
||||||
|
,.response_status= "Moved Permanently"
|
||||||
,.num_headers= 8
|
,.num_headers= 8
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Location", "http://www.google.com/" }
|
{ { "Location", "http://www.google.com/" }
|
||||||
|
@ -975,6 +1029,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 5
|
,.num_headers= 5
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
|
{ { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" }
|
||||||
|
@ -1003,6 +1058,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 404
|
,.status_code= 404
|
||||||
|
,.response_status= "Not Found"
|
||||||
,.num_headers= 0
|
,.num_headers= 0
|
||||||
,.headers= {}
|
,.headers= {}
|
||||||
,.body_size= 0
|
,.body_size= 0
|
||||||
|
@ -1018,6 +1074,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 301
|
,.status_code= 301
|
||||||
|
,.response_status= ""
|
||||||
,.num_headers= 0
|
,.num_headers= 0
|
||||||
,.headers= {}
|
,.headers= {}
|
||||||
,.body= ""
|
,.body= ""
|
||||||
|
@ -1043,6 +1100,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 2
|
,.num_headers= 2
|
||||||
,.headers=
|
,.headers=
|
||||||
{ {"Content-Type", "text/plain" }
|
{ {"Content-Type", "text/plain" }
|
||||||
|
@ -1068,6 +1126,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 2
|
,.num_headers= 2
|
||||||
,.headers=
|
,.headers=
|
||||||
{ {"Content-Type", "text/html; charset=utf-8" }
|
{ {"Content-Type", "text/html; charset=utf-8" }
|
||||||
|
@ -1091,6 +1150,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 4
|
,.num_headers= 4
|
||||||
,.headers=
|
,.headers=
|
||||||
{ {"Content-Type", "text/html; charset=UTF-8" }
|
{ {"Content-Type", "text/html; charset=UTF-8" }
|
||||||
|
@ -1116,6 +1176,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 4
|
,.num_headers= 4
|
||||||
,.headers=
|
,.headers=
|
||||||
{ {"Server", "DCLK-AdSvr" }
|
{ {"Server", "DCLK-AdSvr" }
|
||||||
|
@ -1148,6 +1209,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.status_code= 301
|
,.status_code= 301
|
||||||
|
,.response_status= "Moved Permanently"
|
||||||
,.num_headers= 9
|
,.num_headers= 9
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
|
{ { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" }
|
||||||
|
@ -1186,6 +1248,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 11
|
,.num_headers= 11
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
|
{ { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" }
|
||||||
|
@ -1217,6 +1280,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 500
|
,.status_code= 500
|
||||||
|
,.response_status= "Oriëntatieprobleem"
|
||||||
,.num_headers= 3
|
,.num_headers= 3
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
|
{ { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" }
|
||||||
|
@ -1237,6 +1301,7 @@ const struct message responses[] =
|
||||||
,.http_major= 0
|
,.http_major= 0
|
||||||
,.http_minor= 9
|
,.http_minor= 9
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 0
|
,.num_headers= 0
|
||||||
,.headers=
|
,.headers=
|
||||||
{}
|
{}
|
||||||
|
@ -1259,6 +1324,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 1
|
,.num_headers= 1
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Content-Type", "text/plain" }
|
{ { "Content-Type", "text/plain" }
|
||||||
|
@ -1277,6 +1343,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 1
|
,.num_headers= 1
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Connection", "keep-alive" }
|
{ { "Connection", "keep-alive" }
|
||||||
|
@ -1296,6 +1363,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.status_code= 204
|
,.status_code= 204
|
||||||
|
,.response_status= "No content"
|
||||||
,.num_headers= 1
|
,.num_headers= 1
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Connection", "keep-alive" }
|
{ { "Connection", "keep-alive" }
|
||||||
|
@ -1314,6 +1382,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 0
|
,.num_headers= 0
|
||||||
,.headers={}
|
,.headers={}
|
||||||
,.body_size= 0
|
,.body_size= 0
|
||||||
|
@ -1330,6 +1399,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 204
|
,.status_code= 204
|
||||||
|
,.response_status= "No content"
|
||||||
,.num_headers= 0
|
,.num_headers= 0
|
||||||
,.headers={}
|
,.headers={}
|
||||||
,.body_size= 0
|
,.body_size= 0
|
||||||
|
@ -1347,6 +1417,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 204
|
,.status_code= 204
|
||||||
|
,.response_status= "No content"
|
||||||
,.num_headers= 1
|
,.num_headers= 1
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Connection", "close" }
|
{ { "Connection", "close" }
|
||||||
|
@ -1368,6 +1439,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 1
|
,.num_headers= 1
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Transfer-Encoding", "chunked" }
|
{ { "Transfer-Encoding", "chunked" }
|
||||||
|
@ -1396,6 +1468,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 7
|
,.num_headers= 7
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Server", "Microsoft-IIS/6.0" }
|
{ { "Server", "Microsoft-IIS/6.0" }
|
||||||
|
@ -1433,6 +1506,7 @@ const struct message responses[] =
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 1
|
,.http_minor= 1
|
||||||
,.status_code= 301
|
,.status_code= 301
|
||||||
|
,.response_status= "MovedPermanently"
|
||||||
,.num_headers= 9
|
,.num_headers= 9
|
||||||
,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
|
,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" }
|
||||||
, { "Server", "Server" }
|
, { "Server", "Server" }
|
||||||
|
@ -1447,6 +1521,22 @@ const struct message responses[] =
|
||||||
,.body= "\n"
|
,.body= "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EMPTY_REASON_PHRASE_AFTER_SPACE 20
|
||||||
|
, {.name= "empty reason phrase after space"
|
||||||
|
,.type= HTTP_RESPONSE
|
||||||
|
,.raw= "HTTP/1.1 200 \r\n"
|
||||||
|
"\r\n"
|
||||||
|
,.should_keep_alive= FALSE
|
||||||
|
,.message_complete_on_eof= TRUE
|
||||||
|
,.http_major= 1
|
||||||
|
,.http_minor= 1
|
||||||
|
,.status_code= 200
|
||||||
|
,.response_status= ""
|
||||||
|
,.num_headers= 0
|
||||||
|
,.headers= {}
|
||||||
|
,.body= ""
|
||||||
|
}
|
||||||
|
|
||||||
, {.name= NULL } /* sentinel */
|
, {.name= NULL } /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1528,13 +1618,6 @@ request_url_cb (http_parser *p, const char *buf, size_t len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
status_complete_cb (http_parser *p) {
|
|
||||||
assert(p == parser);
|
|
||||||
p->data++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
header_field_cb (http_parser *p, const char *buf, size_t len)
|
header_field_cb (http_parser *p, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -1660,6 +1743,17 @@ message_complete_cb (http_parser *p)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
response_status_cb (http_parser *p, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
assert(p == parser);
|
||||||
|
strlncat(messages[num_messages].response_status,
|
||||||
|
sizeof(messages[num_messages].response_status),
|
||||||
|
buf,
|
||||||
|
len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* These dontcall_* callbacks exist so that we can verify that when we're
|
/* These dontcall_* callbacks exist so that we can verify that when we're
|
||||||
* paused, no additional callbacks are invoked */
|
* paused, no additional callbacks are invoked */
|
||||||
int
|
int
|
||||||
|
@ -1720,11 +1814,20 @@ dontcall_message_complete_cb (http_parser *p)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dontcall_response_status_cb (http_parser *p, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (p || buf || len) { } // gcc
|
||||||
|
fprintf(stderr, "\n\n*** on_status() called on paused parser ***\n\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
static http_parser_settings settings_dontcall =
|
static http_parser_settings settings_dontcall =
|
||||||
{.on_message_begin = dontcall_message_begin_cb
|
{.on_message_begin = dontcall_message_begin_cb
|
||||||
,.on_header_field = dontcall_header_field_cb
|
,.on_header_field = dontcall_header_field_cb
|
||||||
,.on_header_value = dontcall_header_value_cb
|
,.on_header_value = dontcall_header_value_cb
|
||||||
,.on_url = dontcall_request_url_cb
|
,.on_url = dontcall_request_url_cb
|
||||||
|
,.on_status = dontcall_response_status_cb
|
||||||
,.on_body = dontcall_body_cb
|
,.on_body = dontcall_body_cb
|
||||||
,.on_headers_complete = dontcall_headers_complete_cb
|
,.on_headers_complete = dontcall_headers_complete_cb
|
||||||
,.on_message_complete = dontcall_message_complete_cb
|
,.on_message_complete = dontcall_message_complete_cb
|
||||||
|
@ -1790,11 +1893,20 @@ pause_message_complete_cb (http_parser *p)
|
||||||
return message_complete_cb(p);
|
return message_complete_cb(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pause_response_status_cb (http_parser *p, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
http_parser_pause(p, 1);
|
||||||
|
*current_pause_parser = settings_dontcall;
|
||||||
|
return response_status_cb(p, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
static http_parser_settings settings_pause =
|
static http_parser_settings settings_pause =
|
||||||
{.on_message_begin = pause_message_begin_cb
|
{.on_message_begin = pause_message_begin_cb
|
||||||
,.on_header_field = pause_header_field_cb
|
,.on_header_field = pause_header_field_cb
|
||||||
,.on_header_value = pause_header_value_cb
|
,.on_header_value = pause_header_value_cb
|
||||||
,.on_url = pause_request_url_cb
|
,.on_url = pause_request_url_cb
|
||||||
|
,.on_status = pause_response_status_cb
|
||||||
,.on_body = pause_body_cb
|
,.on_body = pause_body_cb
|
||||||
,.on_headers_complete = pause_headers_complete_cb
|
,.on_headers_complete = pause_headers_complete_cb
|
||||||
,.on_message_complete = pause_message_complete_cb
|
,.on_message_complete = pause_message_complete_cb
|
||||||
|
@ -1805,6 +1917,7 @@ static http_parser_settings settings =
|
||||||
,.on_header_field = header_field_cb
|
,.on_header_field = header_field_cb
|
||||||
,.on_header_value = header_value_cb
|
,.on_header_value = header_value_cb
|
||||||
,.on_url = request_url_cb
|
,.on_url = request_url_cb
|
||||||
|
,.on_status = response_status_cb
|
||||||
,.on_body = body_cb
|
,.on_body = body_cb
|
||||||
,.on_headers_complete = headers_complete_cb
|
,.on_headers_complete = headers_complete_cb
|
||||||
,.on_message_complete = message_complete_cb
|
,.on_message_complete = message_complete_cb
|
||||||
|
@ -1815,6 +1928,7 @@ static http_parser_settings settings_count_body =
|
||||||
,.on_header_field = header_field_cb
|
,.on_header_field = header_field_cb
|
||||||
,.on_header_value = header_value_cb
|
,.on_header_value = header_value_cb
|
||||||
,.on_url = request_url_cb
|
,.on_url = request_url_cb
|
||||||
|
,.on_status = response_status_cb
|
||||||
,.on_body = count_body_cb
|
,.on_body = count_body_cb
|
||||||
,.on_headers_complete = headers_complete_cb
|
,.on_headers_complete = headers_complete_cb
|
||||||
,.on_message_complete = message_complete_cb
|
,.on_message_complete = message_complete_cb
|
||||||
|
@ -1825,6 +1939,7 @@ static http_parser_settings settings_null =
|
||||||
,.on_header_field = 0
|
,.on_header_field = 0
|
||||||
,.on_header_value = 0
|
,.on_header_value = 0
|
||||||
,.on_url = 0
|
,.on_url = 0
|
||||||
|
,.on_status = 0
|
||||||
,.on_body = 0
|
,.on_body = 0
|
||||||
,.on_headers_complete = 0
|
,.on_headers_complete = 0
|
||||||
,.on_message_complete = 0
|
,.on_message_complete = 0
|
||||||
|
@ -1948,6 +2063,7 @@ message_eq (int index, const struct message *expected)
|
||||||
MESSAGE_CHECK_NUM_EQ(expected, m, method);
|
MESSAGE_CHECK_NUM_EQ(expected, m, method);
|
||||||
} else {
|
} else {
|
||||||
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
|
MESSAGE_CHECK_NUM_EQ(expected, m, status_code);
|
||||||
|
MESSAGE_CHECK_STR_EQ(expected, m, response_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
|
MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive);
|
||||||
|
@ -2868,7 +2984,7 @@ test_header_content_length_overflow_error (void)
|
||||||
"HTTP/1.1 200 OK\r\n" \
|
"HTTP/1.1 200 OK\r\n" \
|
||||||
"Content-Length: " #size "\r\n" \
|
"Content-Length: " #size "\r\n" \
|
||||||
"\r\n"
|
"\r\n"
|
||||||
const char a[] = X(18446744073709551614); /* 2^64-2 */
|
const char a[] = X(1844674407370955160); /* 2^64 / 10 - 1 */
|
||||||
const char b[] = X(18446744073709551615); /* 2^64-1 */
|
const char b[] = X(18446744073709551615); /* 2^64-1 */
|
||||||
const char c[] = X(18446744073709551616); /* 2^64 */
|
const char c[] = X(18446744073709551616); /* 2^64 */
|
||||||
#undef X
|
#undef X
|
||||||
|
@ -2886,7 +3002,7 @@ test_chunk_content_length_overflow_error (void)
|
||||||
"\r\n" \
|
"\r\n" \
|
||||||
#size "\r\n" \
|
#size "\r\n" \
|
||||||
"..."
|
"..."
|
||||||
const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */
|
const char a[] = X(FFFFFFFFFFFFFFE); /* 2^64 / 16 - 1 */
|
||||||
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
|
const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */
|
||||||
const char c[] = X(10000000000000000); /* 2^64 */
|
const char c[] = X(10000000000000000); /* 2^64 */
|
||||||
#undef X
|
#undef X
|
||||||
|
@ -3133,20 +3249,6 @@ create_large_chunked_message (int body_size_in_kb, const char* headers)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
test_status_complete (void)
|
|
||||||
{
|
|
||||||
parser_init(HTTP_RESPONSE);
|
|
||||||
parser->data = 0;
|
|
||||||
http_parser_settings settings = settings_null;
|
|
||||||
settings.on_status_complete = status_complete_cb;
|
|
||||||
|
|
||||||
char *response = "don't mind me, just a simple response";
|
|
||||||
http_parser_execute(parser, &settings, response, strlen(response));
|
|
||||||
assert(parser->data == (void*)0); // the status_complete callback was never called
|
|
||||||
assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify that we can pause parsing at any of the bytes in the
|
/* Verify that we can pause parsing at any of the bytes in the
|
||||||
* message and still get the result that we're expecting. */
|
* message and still get the result that we're expecting. */
|
||||||
void
|
void
|
||||||
|
@ -3280,6 +3382,7 @@ main (void)
|
||||||
,.http_major= 1
|
,.http_major= 1
|
||||||
,.http_minor= 0
|
,.http_minor= 0
|
||||||
,.status_code= 200
|
,.status_code= 200
|
||||||
|
,.response_status= "OK"
|
||||||
,.num_headers= 2
|
,.num_headers= 2
|
||||||
,.headers=
|
,.headers=
|
||||||
{ { "Transfer-Encoding", "chunked" }
|
{ { "Transfer-Encoding", "chunked" }
|
||||||
|
@ -3468,8 +3571,6 @@ main (void)
|
||||||
, &requests[CONNECT_REQUEST]
|
, &requests[CONNECT_REQUEST]
|
||||||
);
|
);
|
||||||
|
|
||||||
test_status_complete();
|
|
||||||
|
|
||||||
puts("requests okay");
|
puts("requests okay");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue