bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "lib.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "istream.h"
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch#include "http-url.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-parser.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-message-parser.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-request-parser.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch#define HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH 32
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenenum http_request_parser_state {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_INIT = 0,
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch HTTP_REQUEST_PARSE_STATE_SKIP_LINE,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_METHOD,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_SP1,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_TARGET,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_SP2,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_VERSION,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_CR,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_LF,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP_REQUEST_PARSE_STATE_HEADER
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen};
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstruct http_request_parser {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_message_parser parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen enum http_request_parser_state state;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch uoff_t max_target_length;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch enum http_request_parse_error error_code;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch const char *request_method;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch const char *request_target;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool skipping_line:1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen};
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Boschstruct http_request_parser *
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Boschhttp_request_parser_init(struct istream *input,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch const struct http_request_limits *limits,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch enum http_request_parse_flags flags)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_request_parser *parser;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch struct http_header_limits hdr_limits;
e74d62011e66ec205159869f3fc16d6ffd92a421Stephan Bosch uoff_t max_payload_size;
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch enum http_message_parse_flags msg_flags = 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser = i_new(struct http_request_parser, 1);
e74d62011e66ec205159869f3fc16d6ffd92a421Stephan Bosch if (limits != NULL) {
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch hdr_limits = limits->header;
e74d62011e66ec205159869f3fc16d6ffd92a421Stephan Bosch max_payload_size = limits->max_payload_size;
e74d62011e66ec205159869f3fc16d6ffd92a421Stephan Bosch } else {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&hdr_limits);
e74d62011e66ec205159869f3fc16d6ffd92a421Stephan Bosch max_payload_size = 0;
e74d62011e66ec205159869f3fc16d6ffd92a421Stephan Bosch }
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch /* substitute default limits */
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if (parser->max_target_length == 0)
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch parser->max_target_length = HTTP_REQUEST_DEFAULT_MAX_TARGET_LENGTH;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if (hdr_limits.max_size == 0)
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch hdr_limits.max_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_SIZE;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if (hdr_limits.max_field_size == 0)
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch hdr_limits.max_field_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELD_SIZE;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if (hdr_limits.max_fields == 0)
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch hdr_limits.max_fields = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELDS;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if (max_payload_size == 0)
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch max_payload_size = HTTP_REQUEST_DEFAULT_MAX_PAYLOAD_SIZE;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch if ((flags & HTTP_REQUEST_PARSE_FLAG_STRICT) != 0)
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch msg_flags |= HTTP_MESSAGE_PARSE_FLAG_STRICT;
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch http_message_parser_init(&parser->parser, input,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch &hdr_limits, max_payload_size, msg_flags);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenvoid http_request_parser_deinit(struct http_request_parser **_parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_request_parser *parser = *_parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
da300472555d9afdb0bcb767456f731cf5c2f6aaStephan Bosch *_parser = NULL;
f9d2a1f21ad65262bc630f0834d7eead06a1bac3Timo Sirainen
f9d2a1f21ad65262bc630f0834d7eead06a1bac3Timo Sirainen http_message_parser_deinit(&parser->parser);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_free(parser);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic void
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Boschhttp_request_parser_restart(struct http_request_parser *parser,
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch pool_t pool)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch http_message_parser_restart(&parser->parser, pool);
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->request_method = NULL;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->request_target = NULL;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic int http_request_parse_method(struct http_request_parser *parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *p = parser->parser.cur;
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool_t pool;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* method = token
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen while (p < parser->parser.end && http_char_is_token(*p))
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen p++;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if ((p - parser->parser.cur) > HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH) {
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch parser->parser.error = "HTTP request method is too long";
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch return -1;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (p == parser->parser.end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool = http_message_parser_get_pool(&parser->parser);
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch parser->request_method =
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch p_strdup_until(pool, parser->parser.cur, p);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->parser.cur = p;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic int http_request_parse_target(struct http_request_parser *parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch struct http_message_parser *_parser = &parser->parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *p = parser->parser.cur;
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool_t pool;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* We'll just parse anything up to the first SP or a control char.
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen We could also implement workarounds for buggy HTTP clients and
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parse anything up to the HTTP-version and return 301 with the
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch target properly encoded (FIXME). */
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch while (p < _parser->end && *p > ' ')
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen p++;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch /* target is too long when explicit limit is exceeded or when input buffer
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch runs out of space */
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch /* FIXME: put limit on full request line rather than target and method
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch separately */
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch /* FIXME: is it wise to keep target in stream buffer? It can become very
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch large for some applications, increasing the stream buffer size */
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if ((uoff_t)(p - _parser->cur) > parser->max_target_length ||
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch (p == _parser->end && ((uoff_t)(p - _parser->cur) >=
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch i_stream_get_max_buffer_size(_parser->input)))) {
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch parser->parser.error = "HTTP request target is too long";
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch return -1;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch }
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch if (p == _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool = http_message_parser_get_pool(_parser);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch parser->request_target = p_strdup_until(pool, _parser->cur, p);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->parser.cur = p;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic inline const char *_chr_sanitize(unsigned char c)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (c >= 0x20 && c < 0x7F)
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return t_strdup_printf("`%c'", c);
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch if (c == 0x0a)
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return "<LF>";
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch if (c == 0x0d)
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return "<CR>";
101e78ae4d5705f196fba22db3261db042bfb3c2Stephan Bosch return t_strdup_printf("<0x%02x>", c);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic int http_request_parse(struct http_request_parser *parser,
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch pool_t pool)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_message_parser *_parser = &parser->parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen int ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.1.1: Request Line
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch request-line = method SP request-target SP HTTP-version CRLF
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch method = token
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen for (;;) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen switch (parser->state) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_INIT:
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch http_request_parser_restart(parser, pool);
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch parser->state = HTTP_REQUEST_PARSE_STATE_SKIP_LINE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur == _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b383c911216963c707b3e9dec4e98fc6ebd15218Timo Sirainen /* fall through */
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch case HTTP_REQUEST_PARSE_STATE_SKIP_LINE:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (*_parser->cur == '\r' || *_parser->cur == '\n') {
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch if (parser->skipping_line) {
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch /* second extra CRLF; not allowed */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "Empty request line";
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch return -1;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch }
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch /* HTTP/1.0 client sent one extra CRLF after body.
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen ignore it. */
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch parser->skipping_line = TRUE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_CR;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch break;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch parser->state = HTTP_REQUEST_PARSE_STATE_METHOD;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch parser->skipping_line = FALSE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_METHOD:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret=http_request_parse_method(parser)) <= 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_SP1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur == _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_SP1:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (*_parser->cur != ' ') {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = t_strdup_printf
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ("Unexpected character %s in request method",
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _chr_sanitize(*_parser->cur));
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->cur++;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_TARGET;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur >= _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_TARGET:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret=http_request_parse_target(parser)) <= 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_SP2;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur == _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_SP2:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (*_parser->cur != ' ') {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = t_strdup_printf
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ("Unexpected character %s in request target",
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _chr_sanitize(*_parser->cur));
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->cur++;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_VERSION;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur >= _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_VERSION:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if ((ret=http_message_parse_version(&parser->parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "Invalid HTTP version in request";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_CR;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur == _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_CR:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (*_parser->cur == '\r')
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->cur++;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_LF;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->cur == _parser->end)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* fall through */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case HTTP_REQUEST_PARSE_STATE_LF:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (*_parser->cur != '\n') {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = t_strdup_printf
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ("Unexpected character %s at end of request line",
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _chr_sanitize(*_parser->cur));
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen _parser->cur++;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch if (!parser->skipping_line) {
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch parser->state = HTTP_REQUEST_PARSE_STATE_HEADER;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch return 1;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch }
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch parser->state = HTTP_REQUEST_PARSE_STATE_INIT;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch break;
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch case HTTP_REQUEST_PARSE_STATE_HEADER:
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch default:
188297bee5a2fb1bd5130019da4cd1955b753e15Stephan Bosch i_unreached();
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_unreached();
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic int http_request_parse_request_line(struct http_request_parser *parser,
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch pool_t pool)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_message_parser *_parser = &parser->parser;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *begin;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen size_t size, old_bytes = 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen int ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
651f981ca065d2365bf2ea07b04318a5402f047aTimo Sirainen while ((ret = i_stream_read_bytes(_parser->input, &begin, &size,
651f981ca065d2365bf2ea07b04318a5402f047aTimo Sirainen old_bytes + 1)) > 0) {
8f985b8241246b321db52b9f63d2e6a4a83d4707Stephan Bosch _parser->begin = _parser->cur = begin;
8f985b8241246b321db52b9f63d2e6a4a83d4707Stephan Bosch _parser->end = _parser->begin + size;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_request_parse(parser, pool)) < 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_stream_skip(_parser->input, _parser->cur - begin);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (ret > 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen old_bytes = i_stream_get_data_size(_parser->input);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret == -2) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "HTTP request line is too long";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (ret < 0) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (_parser->input->eof &&
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->state == HTTP_REQUEST_PARSE_STATE_INIT)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch _parser->error = "Broken stream";
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschstatic inline enum http_request_parse_error
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschhttp_request_parser_message_error(struct http_request_parser *parser)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch{
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch switch (parser->parser.error_code) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_MESSAGE_PARSE_ERROR_BAD_MESSAGE:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return HTTP_REQUEST_PARSE_ERROR_NOT_IMPLEMENTED;
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch case HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE:
fa4d00f73d120603a7886aed7433d6c3fceb9bf5Stephan Bosch return HTTP_REQUEST_PARSE_ERROR_PAYLOAD_TOO_LARGE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch case HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch default:
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch break;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch i_unreached();
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch}
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Boschbool http_request_parser_pending_payload(
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch struct http_request_parser *parser)
b8a1b8eb4f13971c0539ce95edcd99503cc6f475Stephan Bosch{
b8a1b8eb4f13971c0539ce95edcd99503cc6f475Stephan Bosch if (parser->parser.payload == NULL)
b8a1b8eb4f13971c0539ce95edcd99503cc6f475Stephan Bosch return FALSE;
b8a1b8eb4f13971c0539ce95edcd99503cc6f475Stephan Bosch return i_stream_have_bytes_left(parser->parser.payload);
b8a1b8eb4f13971c0539ce95edcd99503cc6f475Stephan Bosch}
b8a1b8eb4f13971c0539ce95edcd99503cc6f475Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Boschstatic int
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Boschhttp_request_parse_expect_header(struct http_request_parser *parser,
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch struct http_request *request, const struct http_header_field *hdr)
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch{
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch struct http_message_parser *_parser = &parser->parser;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch struct http_parser hparser;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch bool parse_error = FALSE;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch unsigned int num_expectations = 0;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7231, Section 5.1.1:
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Expect = "100-continue"
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch // FIXME: simplify; RFC 7231 discarded Expect extension mechanism
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parser_init(&hparser, (const unsigned char *)hdr->value, hdr->size);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch while (!parse_error) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch const char *expect_name, *expect_value;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* expect-name */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (http_parse_token(&hparser, &expect_name) > 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch num_expectations++;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (strcasecmp(expect_name, "100-continue") == 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch request->expect_100_continue = TRUE;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch } else {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch _parser->error = t_strdup_printf
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch ("Unknown Expectation `%s'", expect_name);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* BWS "=" BWS */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (hparser.cur >= hparser.end)
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (*hparser.cur == '=') {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch hparser.cur++;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* value */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch if (http_parse_token_or_qstring(&hparser, &expect_value) <= 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parse_error = TRUE;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch _parser->error = t_strdup_printf
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch ("Expectation `%s' has unexpected value", expect_name);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* *( OWS ";" [ OWS expect-param ] ) */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch while (!parse_error) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch const char *attribute, *value;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* OWS ";" */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (hparser.cur >= hparser.end || *hparser.cur != ';')
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch hparser.cur++;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* expect-param */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (http_parse_token(&hparser, &attribute) <= 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parse_error = TRUE;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* BWS "=" BWS */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (hparser.cur >= hparser.end || *hparser.cur != '=') {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parse_error = TRUE;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch hparser.cur++;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* value */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch if (http_parse_token_or_qstring(&hparser, &value) <= 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parse_error = TRUE;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (parser->error_code == HTTP_REQUEST_PARSE_ERROR_NONE) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_EXPECTATION_FAILED;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch _parser->error = t_strdup_printf
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch ("Expectation `%s' has unknown parameter `'%s'",
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch expect_name, attribute);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (parse_error)
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (hparser.cur >= hparser.end || *hparser.cur != ',')
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch break;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch hparser.cur++;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch http_parse_ows(&hparser);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (parse_error || hparser.cur < hparser.end) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch _parser->error = "Invalid Expect header";
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return -1;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (parser->error_code != HTTP_REQUEST_PARSE_ERROR_NONE)
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return -1;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (num_expectations == 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch parser->error_code = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch _parser->error = "Empty Expect header";
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return -1;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return 0;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch}
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Boschstatic int
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Boschhttp_request_parse_headers(struct http_request_parser *parser,
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch struct http_request *request)
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch{
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch const ARRAY_TYPE(http_header_field) *hdrs;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch const struct http_header_field *hdr;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch hdrs = http_header_get_fields(parser->parser.msg.header);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch array_foreach(hdrs, hdr) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch int ret = 0;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* Expect: */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (http_header_field_is(hdr, "Expect"))
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch ret = http_request_parse_expect_header(parser, request, hdr);
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (ret < 0)
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return -1;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return 0;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch}
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Boschint http_request_parse_finish_payload(
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch struct http_request_parser *parser,
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch enum http_request_parse_error *error_code_r,
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch const char **error_r)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen int ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = parser->error_code = HTTP_REQUEST_PARSE_ERROR_NONE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error = NULL;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* make sure we finished streaming payload from previous request
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen before we continue. */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_message_parse_finish_payload(&parser->parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = http_request_parser_message_error(parser);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch return ret;
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch}
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Boschint http_request_parse_next(struct http_request_parser *parser,
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch pool_t pool, struct http_request *request,
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch enum http_request_parse_error *error_code_r, const char **error_r)
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch{
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch const struct http_header_field *hdr;
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch const char *error;
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch int ret;
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch /* initialize and get rid of any payload of previous request */
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch if ((ret=http_request_parse_finish_payload
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch (parser, error_code_r, error_r)) <= 0)
d7b94e1721d86926891c74ca1998141d55d1adeaStephan Bosch return ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3:
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch HTTP-message = start-line
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen *( header-field CRLF )
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen CRLF
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen [ message-body ]
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (parser->state != HTTP_REQUEST_PARSE_STATE_HEADER) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch ret = http_request_parse_request_line(parser, pool);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* assign early for error reporting */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch request->method = parser->request_method;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch request->target_raw = parser->request_target;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch request->version_major = parser->parser.msg.version_major;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch request->version_minor = parser->parser.msg.version_minor;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = parser->error_code;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((ret = http_message_parse_headers(&parser->parser)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = http_request_parser_message_error(parser);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (http_message_parse_body(&parser->parser, TRUE) < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = http_request_parser_message_error(parser);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_r = parser->parser.error;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->state = HTTP_REQUEST_PARSE_STATE_INIT;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 5.4: Host
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch A server MUST respond with a 400 (Bad Request) status code to any
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch HTTP/1.1 request message that lacks a Host header field and to any
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch request message that contains more than one Host header field or a
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch Host header field with an invalid field-value.
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch */
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch if ((ret=http_header_field_find_unique
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch (parser->parser.msg.header, "Host", &hdr)) <= 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch if (ret == 0)
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch *error_r = "Missing Host header";
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch else
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch *error_r = "Duplicate Host header";
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch return -1;
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch }
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(request);
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool = http_message_parser_get_pool(&parser->parser);
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch if (http_url_request_target_parse(parser->request_target, hdr->value,
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool, &request->target, &error) < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch *error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch *error_r = t_strdup_printf("Bad request target `%s': %s",
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch parser->request_target, error);
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch return -1;
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch }
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch /* parse request-specific headers */
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch if (http_request_parse_headers(parser, request) < 0) {
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch *error_code_r = parser->error_code;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch *error_r = parser->parser.error;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch return -1;
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch }
22b47ecd1e6fd11d69433e4111adc57c40dde270Stephan Bosch
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch request->method = parser->request_method;
abd1c1f3b7f82c4f06d8ff447932416c63cfbbaeStephan Bosch request->target_raw = parser->request_target;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch request->version_major = parser->parser.msg.version_major;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch request->version_minor = parser->parser.msg.version_minor;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch request->date = parser->parser.msg.date;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch request->payload = parser->parser.payload;
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch request->header = parser->parser.msg.header;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch request->connection_options = parser->parser.msg.connection_options;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch request->connection_close = parser->parser.msg.connection_close;
ba9528fee8773980239901d99667c54a6d2c8132Stephan Bosch
ba9528fee8773980239901d99667c54a6d2c8132Stephan Bosch /* reset this state early */
ba9528fee8773980239901d99667c54a6d2c8132Stephan Bosch parser->request_method = NULL;
ba9528fee8773980239901d99667c54a6d2c8132Stephan Bosch parser->request_target = NULL;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}