bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "lib.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "array.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "istream.h"
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen#include "iostream.h"
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen#include "istream-sized.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-parser.h"
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch#include "http-header.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-header-parser.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-date.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-transfer.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include "http-message-parser.h"
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen#include <ctype.h>
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenvoid http_message_parser_init(struct http_message_parser *parser,
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch struct istream *input, const struct http_header_limits *hdr_limits,
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch uoff_t max_payload_size, enum http_message_parse_flags flags)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(parser);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->input = input;
269627263964a42f4fb9f9f540aa7a1fe673f2faPhil Carmody i_stream_ref(parser->input);
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch if (hdr_limits != NULL)
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch parser->header_limits = *hdr_limits;
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->max_payload_size = max_payload_size;
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch parser->flags = flags;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenvoid http_message_parser_deinit(struct http_message_parser *parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (parser->header_parser != NULL)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen http_header_parser_deinit(&parser->header_parser);
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&parser->msg.pool);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&parser->payload);
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&parser->input);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Boschvoid http_message_parser_restart(struct http_message_parser *parser,
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch pool_t pool)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_assert(parser->payload == NULL);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch if (parser->header_parser == NULL) {
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch enum http_header_parse_flags hdr_flags = 0;
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch if ((parser->flags & HTTP_MESSAGE_PARSE_FLAG_STRICT) != 0)
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch hdr_flags |= HTTP_HEADER_PARSE_FLAG_STRICT;
e0cf44fb802a5e7aa4cbeee5e80ef8f3f6aecdbeStephan Bosch parser->header_parser = http_header_parser_init
7ebcb054e0d3cc4be54038cbf763ec4189d9725bStephan Bosch (parser->input, &parser->header_limits, hdr_flags);
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch } else {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen http_header_parser_reset(parser->header_parser);
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&parser->msg.pool);
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&parser->msg);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch if (pool != NULL) {
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch parser->msg.pool = pool;
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch pool_ref(pool);
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->msg.date = (time_t)-1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Boschpool_t http_message_parser_get_pool(struct http_message_parser *parser)
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch{
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch if (parser->msg.pool == NULL)
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch parser->msg.pool = pool_alloconly_create("http_message", 4096);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch return parser->msg.pool;
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch}
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenint http_message_parse_version(struct http_message_parser *parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *p = parser->cur;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const size_t size = parser->end - parser->cur;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_NONE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = NULL;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 2.6: Protocol Versioning
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch HTTP-version = HTTP-name "/" DIGIT "." DIGIT
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (size < 8)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (memcmp(p, "HTTP/", 5) != 0 ||
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch !i_isdigit(p[5]) || p[6] != '.' || !i_isdigit(p[7])) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Bad HTTP version";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->msg.version_major = p[5] - '0';
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->msg.version_minor = p[7] - '0';
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->cur += 8;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschint http_message_parse_finish_payload(struct http_message_parser *parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *data;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen size_t size;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen int ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_NONE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = NULL;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (parser->payload == NULL)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody while ((ret = i_stream_read_more(parser->payload, &data, &size)) > 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_stream_skip(parser->payload, size);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (ret == 0 || parser->payload->stream_errno != 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (ret < 0) {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch if (parser->payload->stream_errno == EMSGSIZE) {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE;
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error = "Payload is too large";
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch } else if (parser->payload->stream_errno == EIO) {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error = "Invalid payload";
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch } else {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM;
2a8454fe986d4a881d3612eebb39101be1d6db94Timo Sirainen parser->error = t_strdup_printf("Stream error while skipping payload: %s",
2a8454fe986d4a881d3612eebb39101be1d6db94Timo Sirainen i_stream_get_error(parser->payload));
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
9a07da094849cc665628c60db3024446fb71bae3Stephan Bosch
9a07da094849cc665628c60db3024446fb71bae3Stephan Bosch i_stream_destroy(&parser->payload);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainenstatic int
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Boschhttp_message_parse_header(struct http_message_parser *parser,
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch const char *name, const unsigned char *data, size_t size)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch const struct http_header_field *hdr;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen struct http_parser hparser;
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool_t pool;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool = http_message_parser_get_pool(parser);
b04dfad6b03e3809ccbca7f504ba44c6ab7dfad5Stephan Bosch if (parser->msg.header == NULL)
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch parser->msg.header = http_header_create(pool, 32);
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch hdr = http_header_field_add(parser->msg.header, name, data, size);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.2.2: Field Order
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch A sender MUST NOT generate multiple header fields with the same field
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch name in a message unless either the entire field value for that
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch header field is defined as a comma-separated list [i.e., #(values)]
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch or the header field is a well-known exception.
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen switch (name[0]) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case 'C': case 'c':
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* Connection: */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (strcasecmp(name, "Connection") == 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch const char **opt_idx;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const char *option;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch unsigned int num_tokens = 0;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 6.1: Connection
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Connection = 1#connection-option
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch connection-option = token
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* Multiple Connection headers are allowed and combined into one */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen http_parser_init(&hparser, data, size);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen for (;;) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (http_parse_token_list_next(&hparser, &option) <= 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch num_tokens++;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (strcasecmp(option, "close") == 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->msg.connection_close = TRUE;
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch if (!array_is_created(&parser->msg.connection_options))
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch p_array_init(&parser->msg.connection_options, pool, 4);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch opt_idx = array_append_space(&parser->msg.connection_options);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch *opt_idx = p_strdup(pool, option);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (hparser.cur < hparser.end || num_tokens == 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Invalid Connection header";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* Content-Length: */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (strcasecmp(name, "Content-Length") == 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (parser->msg.have_content_length) {
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch /* There is no acceptable way to allow duplicates for this
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch header. */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Duplicate Content-Length header";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch return -1;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3.2: Content-Length
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Content-Length = 1*DIGIT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (str_to_uoff(hdr->value, &parser->msg.content_length) < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error= "Invalid Content-Length header";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch parser->msg.have_content_length = TRUE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen break;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case 'D': case 'd':
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* Date: */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (strcasecmp(name, "Date") == 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (parser->msg.date != (time_t)-1) {
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch if ((parser->flags & HTTP_MESSAGE_PARSE_FLAG_STRICT) != 0) {
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch parser->error = "Duplicate Date header";
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch return -1;
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch }
6e62aa36a3190ef7193bd86158a4245da49132f0Stephan Bosch /* Allow the duplicate; last instance is used */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7231, Section 7.1.1.2: Date
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Date = HTTP-date
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch */
d577bb9027e4ceb19ada88d6884265efa5e16b15Stephan Bosch if (!http_date_parse(data, size, &parser->msg.date) &&
d577bb9027e4ceb19ada88d6884265efa5e16b15Stephan Bosch (parser->flags & HTTP_MESSAGE_PARSE_FLAG_STRICT) != 0) {
d577bb9027e4ceb19ada88d6884265efa5e16b15Stephan Bosch parser->error = "Invalid Date header";
d577bb9027e4ceb19ada88d6884265efa5e16b15Stephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
d577bb9027e4ceb19ada88d6884265efa5e16b15Stephan Bosch return -1;
d577bb9027e4ceb19ada88d6884265efa5e16b15Stephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen break;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case 'L': case 'l':
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* Location: */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (strcasecmp(name, "Location") == 0) {
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7231, Section 7.1.2: Location
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Location = URI-reference
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch -> not parsed here
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* FIXME: move this to response parser */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->msg.location = hdr->value;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen break;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen case 'T': case 't':
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* Transfer-Encoding: */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (strcasecmp(name, "Transfer-Encoding") == 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch const char *trenc = NULL;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* Multiple Transfer-Encoding headers are allowed and combined into one */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (!array_is_created(&parser->msg.transfer_encoding))
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch p_array_init(&parser->msg.transfer_encoding, pool, 4);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3.1: Transfer-Encoding
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Transfer-Encoding = 1#transfer-coding
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch RFC 7230, Section 4: Transfer Codings
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch transfer-coding = "chunked" ; RFC 7230, Section 4.1
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / "compress" ; RFC 7230, Section 4.2.1
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / "deflate" ; RFC 7230, Section 4.2.2
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / "gzip" ; RFC 7230, Section 4.2.3
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / transfer-extension
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch transfer-extension = token *( OWS ";" OWS transfer-parameter )
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch transfer-parameter = token BWS "=" BWS ( token / quoted-string )
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parser_init(&hparser, data, size);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch for (;;) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* transfer-coding */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (http_parse_token(&hparser, &trenc) > 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch struct http_transfer_coding *coding;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch bool parse_error;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch coding = array_append_space(&parser->msg.transfer_encoding);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch coding->name = p_strdup(pool, trenc);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* *( OWS ";" OWS transfer-parameter ) */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch parse_error = FALSE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch for (;;) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch struct http_transfer_param *param;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch const char *attribute, *value;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* OWS ";" OWS */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parse_ows(&hparser);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (hparser.cur >= hparser.end || *hparser.cur != ';')
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch hparser.cur++;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parse_ows(&hparser);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* attribute */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (http_parse_token(&hparser, &attribute) <= 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch parse_error = TRUE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch /* BWS "=" BWS */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parse_ows(&hparser);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (hparser.cur >= hparser.end || *hparser.cur != '=') {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch parse_error = TRUE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch hparser.cur++;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parse_ows(&hparser);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* token / quoted-string */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch if (http_parse_token_or_qstring(&hparser, &value) <= 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch parse_error = TRUE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (!array_is_created(&coding->parameters))
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch p_array_init(&coding->parameters, pool, 2);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch param = array_append_space(&coding->parameters);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch param->attribute = p_strdup(pool, attribute);
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch param->value = p_strdup(pool, value);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (parse_error)
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch } else {
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 7: ABNF List Extension: #rule
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch For compatibility with legacy list rules, a recipient MUST parse
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch and ignore a reasonable number of empty list elements: enough to
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch handle common mistakes by senders that merge values, but not so
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch much that they could be used as a denial-of-service mechanism.
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch // FIXME: limit allowed number of empty list elements
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch // FIXME: handle invalid transfer encoding
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parse_ows(&hparser);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (hparser.cur >= hparser.end || *hparser.cur != ',')
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch break;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch hparser.cur++;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch http_parse_ows(&hparser);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (hparser.cur < hparser.end ||
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch array_count(&parser->msg.transfer_encoding) == 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Invalid Transfer-Encoding header";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch return -1;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen break;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen default:
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen break;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschint http_message_parse_headers(struct http_message_parser *parser)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen const unsigned char *field_data;
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch struct http_message *msg = &parser->msg;
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch const char *field_name, *error;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen size_t field_size;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen int ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_NONE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = NULL;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* *( header-field CRLF ) CRLF */
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch while ((ret=http_header_parse_next_field(parser->header_parser,
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch &field_name, &field_data, &field_size, &error)) > 0) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (field_name == NULL) {
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool_t pool;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* EOH */
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch
b04dfad6b03e3809ccbca7f504ba44c6ab7dfad5Stephan Bosch /* Create empty header if there is none */
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch pool = http_message_parser_get_pool(parser);
b04dfad6b03e3809ccbca7f504ba44c6ab7dfad5Stephan Bosch if (parser->msg.header == NULL)
1ec26e0b70ac7f8a4e3dfbc59aa77f572651d5aeStephan Bosch parser->msg.header = http_header_create(pool, 1);
b04dfad6b03e3809ccbca7f504ba44c6ab7dfad5Stephan Bosch
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch /* handle HTTP/1.0 persistence */
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch if (msg->version_major == 1 && msg->version_minor == 0 &&
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch !msg->connection_close) {
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch const char *const *option;
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch msg->connection_close = TRUE;
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch if (array_is_created(&parser->msg.connection_options)) {
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch array_foreach(&msg->connection_options, option) {
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch if (strcasecmp(*option, "Keep-Alive") == 0) {
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch msg->connection_close = FALSE;
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch break;
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch }
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch }
8b223f08b8ab40fd4e6a65542aac9ab6afc6839dStephan Bosch }
81498cffac5fb96fcbab6a30418017b04ffb59d1Stephan Bosch }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch if (http_message_parse_header(parser,
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch field_name, field_data, field_size) < 0)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (ret < 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (parser->input->eof || parser->input->stream_errno != 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Broken stream";
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch } else {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = t_strdup_printf("Failed to parse header: %s", error);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainenstatic const char *
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainenhttp_istream_error_callback(const struct istream_sized_error_data *data,
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen struct istream *input)
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen{
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen i_assert(data->eof);
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen i_assert(data->v_offset + data->new_bytes < data->wanted_size);
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen
fc61333d29f122122e27c11f20d7efd5fe8a97ccTimo Sirainen return t_strdup_printf("Disconnected while reading response payload at offset %"PRIuUOFF_T
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen " (wanted %"PRIuUOFF_T"): %s", data->v_offset + data->new_bytes,
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen data->wanted_size, io_stream_get_disconnect_reason(input, NULL));
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen}
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschint http_message_parse_body(struct http_message_parser *parser, bool request)
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen{
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen struct istream *input;
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen
9a07da094849cc665628c60db3024446fb71bae3Stephan Bosch i_assert(parser->payload == NULL);
9a07da094849cc665628c60db3024446fb71bae3Stephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_NONE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = NULL;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (array_is_created(&parser->msg.transfer_encoding)) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch const struct http_transfer_coding *coding;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch bool chunked_last = FALSE;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch array_foreach(&parser->msg.transfer_encoding, coding) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (strcasecmp(coding->name, "chunked") == 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch chunked_last = TRUE;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if ((parser->error_code == HTTP_MESSAGE_PARSE_ERROR_NONE)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch && array_is_created(&coding->parameters)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch && array_count(&coding->parameters) > 0) {
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch const struct http_transfer_param *param =
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch array_idx(&coding->parameters, 0);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BAD_MESSAGE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = t_strdup_printf(
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch "Unexpected parameter `%s' specified"
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch "for the `%s' transfer coding", param->attribute, coding->name);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* recoverable */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch } else if (chunked_last) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Chunked Transfer-Encoding must be last";
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch return -1;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch } else if (parser->error_code == HTTP_MESSAGE_PARSE_ERROR_NONE) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = t_strdup_printf(
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch "Unknown transfer coding `%s'", coding->name);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* recoverable */
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch if (chunked_last) {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->payload = http_transfer_chunked_istream_create
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch (parser->input, parser->max_payload_size);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch } else if (!request) {
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3.3: Message Body Length
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch If a Transfer-Encoding header field is present in a response and
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch the chunked transfer coding is not the final encoding, the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch message body length is determined by reading the connection until
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch it is closed by the server.
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch */
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch /* FIXME: enforce max payload size (relevant to http-client only) */
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->payload =
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch i_stream_create_limit(parser->input, (size_t)-1);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch } else {
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3.3: Message Body Length
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch If a Transfer-Encoding header field is present in a request and
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch the chunked transfer coding is not the final encoding, the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch message body length cannot be determined reliably; the server
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch MUST respond with the 400 (Bad Request) status code and then
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch close the connection.
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch parser->error = "Final Transfer-Encoding in request is not chunked";
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch return -1;
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch }
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3.3: Message Body Length
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch If a message is received with both a Transfer-Encoding and a
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Content-Length header field, the Transfer-Encoding overrides the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch Content-Length. Such a message might indicate an attempt to
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch perform request smuggling (Section 9.5 of [RFC7230]) or response
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch splitting (Section 9.4 of [RFC7230]) and ought to be handled as
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch an error. A sender MUST remove the received Content-Length field
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch prior to forwarding such a message downstream.
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch // FIXME: make this an error?
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch if (parser->msg.have_content_length)
e8f1e510df3ab051a816715c2056f0d10aee929eStephan Bosch http_header_field_delete(parser->msg.header, "Content-Length");
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch } else if (parser->msg.content_length > 0) {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch if (parser->max_payload_size > 0
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch && parser->msg.content_length > parser->max_payload_size) {
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error_code = HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE;
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch parser->error = "Payload is too large";
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch return -1;
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch }
1175415b88ff168e367c77df23901eada13225b9Stephan Bosch
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* Got explicit message size from Content-Length: header */
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen input = i_stream_create_limit(parser->input,
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen parser->msg.content_length);
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen /* Make sure we return failure if HTTP connection closes before
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen we've finished reading the full input. */
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen parser->payload = i_stream_create_sized_with_callback(input,
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen parser->msg.content_length,
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen http_istream_error_callback, input);
1492e7c2c39a6d99db654b8476a2a8e25e107ed8Timo Sirainen i_stream_unref(&input);
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch } else if (!parser->msg.have_content_length && !request) {
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* RFC 7230, Section 3.3.3: Message Body Length
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch 6. If this is a request message and none of the above are true, then
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch the message body length is zero (no message body is present).
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch 7. Otherwise, this is a response message without a declared message
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch body length, so the message body length is determined by the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch number of octets received prior to the server closing the
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch connection
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch // FIXME: enforce max payload size (relevant to http-client only)
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch // FIXME: handle request case correctly.
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch parser->payload =
9e7bf91667639a2390207ab4d90bf88e2afcec2aStephan Bosch i_stream_create_limit(parser->input, (size_t)-1);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen }
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (parser->error_code != HTTP_MESSAGE_PARSE_ERROR_NONE)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch return -1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return 0;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen}