From: Stephan Bosch Date: Sun, 15 Sep 2013 00:31:51 +0000 (+0300) Subject: lib-http: Fixed handling of non-standard CRLF at end of request. X-Git-Tag: 2.2.6~90 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=188297bee5a2fb1bd5130019da4cd1955b753e15;p=thirdparty%2Fdovecot%2Fcore.git lib-http: Fixed handling of non-standard CRLF at end of request. --- diff --git a/src/lib-http/http-request-parser.c b/src/lib-http/http-request-parser.c index a06b34cf24..7151edec24 100644 --- a/src/lib-http/http-request-parser.c +++ b/src/lib-http/http-request-parser.c @@ -8,6 +8,7 @@ enum http_request_parser_state { HTTP_REQUEST_PARSE_STATE_INIT = 0, + HTTP_REQUEST_PARSE_STATE_SKIP_LINE, HTTP_REQUEST_PARSE_STATE_METHOD, HTTP_REQUEST_PARSE_STATE_SP1, HTTP_REQUEST_PARSE_STATE_TARGET, @@ -23,6 +24,8 @@ struct http_request_parser { enum http_request_parser_state state; struct http_request request; + + unsigned int skipping_line:1; }; struct http_request_parser *http_request_parser_init(struct istream *input) @@ -105,15 +108,24 @@ static int http_request_parse(struct http_request_parser *parser, switch (parser->state) { case HTTP_REQUEST_PARSE_STATE_INIT: http_request_parser_restart(parser); - parser->state = HTTP_REQUEST_PARSE_STATE_VERSION; + parser->state = HTTP_REQUEST_PARSE_STATE_SKIP_LINE; if (_parser->cur == _parser->end) return 0; + case HTTP_REQUEST_PARSE_STATE_SKIP_LINE: if (*_parser->cur == '\r' || *_parser->cur == '\n') { - /* HTTP/1.0 client sent a CRLF after body. + if (parser->skipping_line) { + /* second extra CRLF; not allowed */ + *error_r = "Empty request line"; + return -1; + } + /* HTTP/1.0 client sent one extra CRLF after body. ignore it. */ + parser->skipping_line = TRUE; parser->state = HTTP_REQUEST_PARSE_STATE_CR; - return http_request_parse(parser, error_r); + break; } + parser->state = HTTP_REQUEST_PARSE_STATE_METHOD; + parser->skipping_line = FALSE; /* fall through */ case HTTP_REQUEST_PARSE_STATE_METHOD: if ((ret=http_request_parse_method(parser)) <= 0) { @@ -184,11 +196,15 @@ static int http_request_parse(struct http_request_parser *parser, return -1; } _parser->cur++; - parser->state = HTTP_REQUEST_PARSE_STATE_HEADER; - return 1; - case HTTP_REQUEST_PARSE_STATE_HEADER: - default: - i_unreached(); + if (!parser->skipping_line) { + parser->state = HTTP_REQUEST_PARSE_STATE_HEADER; + return 1; + } + parser->state = HTTP_REQUEST_PARSE_STATE_INIT; + break; + case HTTP_REQUEST_PARSE_STATE_HEADER: + default: + i_unreached(); } }