diff --git a/http_parser.c b/http_parser.c index 48963853..c9fd6477 100644 --- a/http_parser.c +++ b/http_parser.c @@ -160,6 +160,25 @@ do { \ } \ } while (0) +#define APPLY_ON_HEADERS_COMPLETE_RESULT(V, DEFAULT) \ +do { \ + switch (V) { \ + case 0: \ + break; \ + \ + case 2: \ + parser->upgrade = 1; \ + \ + /* fall through */ \ + case 1: \ + parser->flags |= F_SKIPBODY; \ + break; \ + \ + default: \ + DEFAULT \ + } \ +} while (0) + #define PROXY_CONNECTION "proxy-connection" #define CONNECTION "connection" @@ -1798,22 +1817,10 @@ size_t http_parser_execute (http_parser *parser, * we have to simulate it by handling a change in errno below. */ if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 2: - parser->upgrade = 1; - - /* fall through */ - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: + APPLY_ON_HEADERS_COMPLETE_RESULT(settings->on_headers_complete(parser), SET_ERRNO(HPE_CB_headers_complete); RETURN(p - data); /* Error */ - } + ); } if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { @@ -2480,6 +2487,20 @@ http_parser_pause(http_parser *parser, int paused) { } } +void +http_parser_continue_after_on_headers_complete(http_parser *parser, int result) { + uint32_t nread; + assert(parser->state == s_headers_done && + (HTTP_PARSER_ERRNO(parser) == HPE_OK || + HTTP_PARSER_ERRNO(parser) == HPE_PAUSED)); + APPLY_ON_HEADERS_COMPLETE_RESULT(result, + ; + ); + nread = parser->nread; /* used by the SET_ERRNO macro */ + /* unpause the parser - after all, it says "continue", right? */ + SET_ERRNO(HPE_OK); +} + int http_body_is_final(const struct http_parser *parser) { return parser->state == s_message_done; diff --git a/http_parser.h b/http_parser.h index 16b5281d..72b8f295 100644 --- a/http_parser.h +++ b/http_parser.h @@ -427,6 +427,14 @@ int http_parser_parse_url(const char *buf, size_t buflen, /* Pause or un-pause the parser; a nonzero value pauses */ void http_parser_pause(http_parser *parser, int paused); +/* Change the parser state as if the on_headers_complete callback + * returned `result` and un-pause the parser - only makes sense + * between two consecutive invocations of http_parser_execute + * when the first one returned due to the on_headers_complete pausing + * the parser and returning 0. + */ +void http_parser_continue_after_on_headers_complete(http_parser *parser, int result); + /* Checks if this is the final chunk of the body. */ int http_body_is_final(const http_parser *parser);