From 5c65ed9b4c0af7485d468d91a9dbc3b13adeaece Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Sat, 20 Feb 2016 11:51:57 +0600 Subject: [PATCH 1/2] Add raw data callbacks --- http_parser.c | 41 ++++++++++++++++++++++++++++++++++++++++- http_parser.h | 16 ++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/http_parser.c b/http_parser.c index b3037d7e..5b0b07a2 100644 --- a/http_parser.c +++ b/http_parser.c @@ -56,11 +56,30 @@ do { \ parser->http_errno = (e); \ } while(0) +#define CALLBACK_RAW_ON_RETURN(V) \ + do { \ + if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { \ + if ((p >= raw_mark) && (raw_mark < data + len) && ((ptrdiff_t)(V) == (ptrdiff_t)(len))) { \ + if (p_state <= s_header_almost_done) { \ + if (settings->on_header_raw) { \ + settings->on_header_raw(parser, raw_mark, len - (raw_mark - data)); \ + } \ + } else { \ + if (settings->on_body_raw) { \ + settings->on_body_raw(parser, raw_mark, len - (raw_mark - data)); \ + } \ + } \ + } \ + } \ + } \ + while (0); + #define CURRENT_STATE() p_state #define UPDATE_STATE(V) p_state = (enum state) (V); #define RETURN(V) \ do { \ parser->state = CURRENT_STATE(); \ + CALLBACK_RAW_ON_RETURN(V); \ return (V); \ } while (0); #define REEXECUTE() \ @@ -81,6 +100,17 @@ do { \ do { \ assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ \ + if (e_on_##FOR == e_on_message_complete) { \ + if ((HTTP_PARSER_ERRNO(parser) == HPE_OK) && \ + (settings->on_body_raw) && \ + (p >= raw_mark) && \ + (raw_mark < data + len)) \ + { \ + settings->on_body_raw(parser, raw_mark, p - raw_mark + 1); \ + raw_mark = p + 1; \ + } \ + } \ + \ if (LIKELY(settings->on_##FOR)) { \ parser->state = CURRENT_STATE(); \ if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ @@ -633,6 +663,7 @@ size_t http_parser_execute (http_parser *parser, char c, ch; int8_t unhex_val; const char *p = data; + const char *raw_mark = data; const char *header_field_mark = 0; const char *header_value_mark = 0; const char *url_mark = 0; @@ -1819,7 +1850,15 @@ size_t http_parser_execute (http_parser *parser, (F_UPGRADE | F_CONNECTION_UPGRADE) || parser->method == HTTP_CONNECT); - /* Here we call the headers_complete callback. This is somewhat + /* Here we call final headers_raw. It's based on different variables, + * so we can't use CALLBACK_DATA. + */ + if ((HTTP_PARSER_ERRNO(parser) == HPE_OK) && (settings->on_header_raw) && (p >= raw_mark) && (raw_mark < data + len)) { + settings->on_header_raw(parser, raw_mark, p - raw_mark + 1); + raw_mark = p + 1; + } + + /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This * is needed for the annoying case of recieving a response to a HEAD diff --git a/http_parser.h b/http_parser.h index 34bebf3d..9ffacabb 100644 --- a/http_parser.h +++ b/http_parser.h @@ -240,6 +240,20 @@ struct http_parser { void *data; /* A pointer to get hook to the "connection" or "socket" object */ }; +enum { + e_on_message_begin, + e_on_url, + e_on_status, + e_on_header_field, + e_on_header_value, + e_on_header_raw, + e_on_headers_complete, + e_on_body, + e_on_body_raw, + e_on_message_complete, + e_on_chunk_header, + e_on_chunk_complete, +}; struct http_parser_settings { http_cb on_message_begin; @@ -247,8 +261,10 @@ struct http_parser_settings { http_data_cb on_status; http_data_cb on_header_field; http_data_cb on_header_value; + http_data_cb on_header_raw; http_cb on_headers_complete; http_data_cb on_body; + http_data_cb on_body_raw; http_cb on_message_complete; /* When on_chunk_header is called, the current chunk length is stored * in parser->content_length. From 0d34b0569e42f0008fa777f0ebbe594b3de26085 Mon Sep 17 00:00:00 2001 From: Sergey Kovalev Date: Sat, 20 Feb 2016 22:34:21 +0600 Subject: [PATCH 2/2] Fix style errors --- http_parser.c | 37 ++++++++++++++++++++++++------------- http_parser.h | 24 ++++++++++++------------ 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/http_parser.c b/http_parser.c index c858b5bc..d888b27d 100644 --- a/http_parser.c +++ b/http_parser.c @@ -59,16 +59,23 @@ do { \ #define CALLBACK_RAW_ON_RETURN(V) \ do { \ if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { \ - if ((p >= raw_mark) && (raw_mark < data + len) && ((ptrdiff_t)(V) == (ptrdiff_t)(len))) { \ - if (p_state <= s_header_almost_done) { \ - if (settings->on_header_raw) { \ - settings->on_header_raw(parser, raw_mark, len - (raw_mark - data)); \ - } \ - } else { \ - if (settings->on_body_raw) { \ - settings->on_body_raw(parser, raw_mark, len - (raw_mark - data)); \ - } \ - } \ + if ((p >= raw_mark) && \ + (raw_mark < data + len) && \ + ((ptrdiff_t)(V) == (ptrdiff_t)(len))) \ + { \ + if (p_state <= s_header_almost_done) { \ + if (settings->on_header_raw) { \ + settings->on_header_raw(parser, \ + raw_mark, \ + len - (raw_mark - data)); \ + } \ + } else { \ + if (settings->on_body_raw) { \ + settings->on_body_raw(parser, \ + raw_mark, \ + len - (raw_mark - data)); \ + } \ + } \ } \ } \ } \ @@ -1881,12 +1888,16 @@ size_t http_parser_execute (http_parser *parser, /* Here we call final headers_raw. It's based on different variables, * so we can't use CALLBACK_DATA. */ - if ((HTTP_PARSER_ERRNO(parser) == HPE_OK) && (settings->on_header_raw) && (p >= raw_mark) && (raw_mark < data + len)) { + if ((HTTP_PARSER_ERRNO(parser) == HPE_OK) && + (settings->on_header_raw) && + (p >= raw_mark) && + (raw_mark < data + len)) + { settings->on_header_raw(parser, raw_mark, p - raw_mark + 1); raw_mark = p + 1; - } + } - /* Here we call the headers_complete callback. This is somewhat + /* Here we call the headers_complete callback. This is somewhat * different than other callbacks because if the user returns 1, we * will interpret that as saying that this message has no body. This * is needed for the annoying case of recieving a response to a HEAD diff --git a/http_parser.h b/http_parser.h index 501a274d..7d0d1fe0 100644 --- a/http_parser.h +++ b/http_parser.h @@ -245,18 +245,18 @@ struct http_parser { }; enum { - e_on_message_begin, - e_on_url, - e_on_status, - e_on_header_field, - e_on_header_value, - e_on_header_raw, - e_on_headers_complete, - e_on_body, - e_on_body_raw, - e_on_message_complete, - e_on_chunk_header, - e_on_chunk_complete, + e_on_message_begin, + e_on_url, + e_on_status, + e_on_header_field, + e_on_header_value, + e_on_header_raw, + e_on_headers_complete, + e_on_body, + e_on_body_raw, + e_on_message_complete, + e_on_chunk_header, + e_on_chunk_complete, }; struct http_parser_settings {