diff --git a/http_parser.c b/http_parser.c index 98e0b9f2..d888b27d 100644 --- a/http_parser.c +++ b/http_parser.c @@ -56,11 +56,37 @@ 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 +107,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))) { \ @@ -639,6 +676,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; @@ -1847,6 +1885,18 @@ size_t http_parser_execute (http_parser *parser, (F_UPGRADE | F_CONNECTION_UPGRADE) || parser->method == HTTP_CONNECT); + /* 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 diff --git a/http_parser.h b/http_parser.h index e33c0620..7d0d1fe0 100644 --- a/http_parser.h +++ b/http_parser.h @@ -244,6 +244,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; @@ -251,8 +265,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.