From a0711188a47d8230013aaf38b694a8fb6fbde78e Mon Sep 17 00:00:00 2001 From: Martin Gabris Date: Fri, 16 Dec 2016 10:04:49 +0100 Subject: [PATCH 1/2] Add callback for chunked encoding extensions Added data callback to access data in chunked encoding extensions. --- http_parser.c | 11 +++++++++-- http_parser.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/http_parser.c b/http_parser.c index f9991c3e..182c6d96 100644 --- a/http_parser.c +++ b/http_parser.c @@ -642,6 +642,7 @@ size_t http_parser_execute (http_parser *parser, const char *url_mark = 0; const char *body_mark = 0; const char *status_mark = 0; + const char *chunk_extensions_mark = 0; enum state p_state = (enum state) parser->state; const unsigned int lenient = parser->lenient_http_headers; @@ -676,6 +677,8 @@ size_t http_parser_execute (http_parser *parser, header_field_mark = data; if (CURRENT_STATE() == s_header_value) header_value_mark = data; + if (CURRENT_STATE() == s_chunk_parameters) + chunk_extensions_mark = data; switch (CURRENT_STATE()) { case s_req_path: case s_req_schema: @@ -1917,10 +1920,11 @@ size_t http_parser_execute (http_parser *parser, if (unhex_val == -1) { if (ch == ';' || ch == ' ') { + /* Parse chunk extensions */ + MARK(chunk_extensions); UPDATE_STATE(s_chunk_parameters); break; } - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); goto error; } @@ -1945,6 +1949,7 @@ size_t http_parser_execute (http_parser *parser, /* just ignore this shit. TODO check for overflow */ if (ch == CR) { UPDATE_STATE(s_chunk_size_almost_done); + CALLBACK_DATA(chunk_extensions); break; } break; @@ -2027,13 +2032,15 @@ size_t http_parser_execute (http_parser *parser, (header_value_mark ? 1 : 0) + (url_mark ? 1 : 0) + (body_mark ? 1 : 0) + - (status_mark ? 1 : 0)) <= 1); + (status_mark ? 1 : 0) + + (chunk_extensions_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); + CALLBACK_DATA_NOADVANCE(chunk_extensions); RETURN(len); diff --git a/http_parser.h b/http_parser.h index a0de71e2..63e44271 100644 --- a/http_parser.h +++ b/http_parser.h @@ -247,6 +247,7 @@ enum flags XX(CB_status, "the on_status callback failed") \ XX(CB_chunk_header, "the on_chunk_header callback failed") \ XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ + XX(CB_chunk_extensions, "the on_chunk_extensions callback failed") \ \ /* Parsing-related errors */ \ XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ @@ -335,6 +336,7 @@ struct http_parser_settings { */ http_cb on_chunk_header; http_cb on_chunk_complete; + http_data_cb on_chunk_extensions; }; From 6c907c86f81684fea61c505317f73f786cf4c870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20G=C3=A1bri=C5=A1?= Date: Tue, 29 May 2018 16:10:39 +0200 Subject: [PATCH 2/2] Added chunk extension callbacks to tests --- test.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test.c b/test.c index df170e49..95d3303b 100644 --- a/test.c +++ b/test.c @@ -69,6 +69,7 @@ struct message { int num_chunks; int num_chunks_complete; int chunk_lengths[MAX_CHUNKS]; + char chunk_extensions[MAX_CHUNKS][MAX_ELEMENT_SIZE]; const char *upgrade; // upgraded body @@ -397,6 +398,10 @@ const struct message requests[] = ,.body= "hello world" ,.num_chunks_complete= 3 ,.chunk_lengths= { 5, 6 } + ,.chunk_extensions = + { "; ihatew3;whatthefuck=aretheseparametersfor" + , "; blahblah; blah" + } } #define WITH_QUOTES 12 @@ -1333,6 +1338,7 @@ const struct message responses[] = "and this is the second one\r\n" ,.num_chunks_complete= 3 ,.chunk_lengths= { 0x25, 0x1c } + ,.chunk_extensions = { " ", "" , " " } } #define NO_CARRIAGE_RET 5 @@ -2186,6 +2192,20 @@ chunk_complete_cb (http_parser *p) return 0; } +int +chunk_extensions_cb (http_parser *p, const char *buf, size_t len) +{ + assert(p == parser); + + struct message *m = &messages[num_messages]; + strlncat(m->chunk_extensions[m->num_chunks], + sizeof(m->chunk_extensions[m->num_chunks]), + buf, + len); + + return 0; +} + /* These dontcall_* callbacks exist so that we can verify that when we're * paused, no additional callbacks are invoked */ int @@ -2271,6 +2291,15 @@ dontcall_chunk_complete_cb (http_parser *p) exit(1); } +int +dontcall_chunk_extensions_cb (http_parser *p, const char *buf, size_t len) +{ + if (p || buf || len) { } // gcc + fprintf(stderr, "\n\n*** on_chunk_extensions() " + "called on paused parser ***\n\n"); + exit(1); +} + static http_parser_settings settings_dontcall = {.on_message_begin = dontcall_message_begin_cb ,.on_header_field = dontcall_header_field_cb @@ -2282,6 +2311,7 @@ static http_parser_settings settings_dontcall = ,.on_message_complete = dontcall_message_complete_cb ,.on_chunk_header = dontcall_chunk_header_cb ,.on_chunk_complete = dontcall_chunk_complete_cb + ,.on_chunk_extensions = dontcall_chunk_extensions_cb }; /* These pause_* callbacks always pause the parser and just invoke the regular @@ -2368,6 +2398,14 @@ pause_chunk_complete_cb (http_parser *p) return chunk_complete_cb(p); } +int +pause_chunk_extensions_cb (http_parser *p, const char *buf, size_t len) +{ + http_parser_pause(p, 1); + *current_pause_parser = settings_dontcall; + return chunk_extensions_cb(p, buf, len); +} + int connect_headers_complete_cb (http_parser *p) { @@ -2393,6 +2431,7 @@ static http_parser_settings settings_pause = ,.on_message_complete = pause_message_complete_cb ,.on_chunk_header = pause_chunk_header_cb ,.on_chunk_complete = pause_chunk_complete_cb + ,.on_chunk_extensions = pause_chunk_extensions_cb }; static http_parser_settings settings = @@ -2406,6 +2445,7 @@ static http_parser_settings settings = ,.on_message_complete = message_complete_cb ,.on_chunk_header = chunk_header_cb ,.on_chunk_complete = chunk_complete_cb + ,.on_chunk_extensions = chunk_extensions_cb }; static http_parser_settings settings_count_body = @@ -2419,6 +2459,7 @@ static http_parser_settings settings_count_body = ,.on_message_complete = message_complete_cb ,.on_chunk_header = chunk_header_cb ,.on_chunk_complete = chunk_complete_cb + ,.on_chunk_extensions = chunk_extensions_cb }; static http_parser_settings settings_connect = @@ -2432,6 +2473,7 @@ static http_parser_settings settings_connect = ,.on_message_complete = connect_message_complete_cb ,.on_chunk_header = chunk_header_cb ,.on_chunk_complete = chunk_complete_cb + ,.on_chunk_extensions = chunk_extensions_cb }; static http_parser_settings settings_null = @@ -2445,6 +2487,7 @@ static http_parser_settings settings_null = ,.on_message_complete = 0 ,.on_chunk_header = 0 ,.on_chunk_complete = 0 + ,.on_chunk_extensions = 0 }; void @@ -2633,6 +2676,7 @@ message_eq (int index, int connect, const struct message *expected) MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete); for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) { MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]); + MESSAGE_CHECK_STR_EQ(expected, m, chunk_extensions[i]); } }