dovecot-2.2: lib-http: Added support for enforcing a payload lim...
dovecot at dovecot.org
dovecot at dovecot.org
Sun Sep 15 03:57:22 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/a335db9dca6a
changeset: 16750:a335db9dca6a
user: Stephan Bosch <stephan at rename-it.nl>
date: Sun Sep 15 03:52:01 2013 +0300
description:
lib-http: Added support for enforcing a payload limit for incoming HTTP messages.
diffstat:
src/lib-http/http-message-parser.c | 31 +++++++++++++++++++++++++------
src/lib-http/http-message-parser.h | 20 ++++++++++++--------
src/lib-http/http-request-parser.c | 2 +-
src/lib-http/http-response-parser.c | 2 +-
src/lib-http/http-transfer-chunked.c | 14 ++++++++++++--
src/lib-http/http-transfer.h | 2 +-
src/lib-http/test-http-transfer.c | 6 +++---
7 files changed, 55 insertions(+), 22 deletions(-)
diffs (235 lines):
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/http-message-parser.c
--- a/src/lib-http/http-message-parser.c Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/http-message-parser.c Sun Sep 15 03:52:01 2013 +0300
@@ -13,12 +13,14 @@
#include <ctype.h>
void http_message_parser_init(struct http_message_parser *parser,
- struct istream *input, const struct http_header_limits *hdr_limits)
+ struct istream *input, const struct http_header_limits *hdr_limits,
+ uoff_t max_payload_size)
{
memset(parser, 0, sizeof(*parser));
parser->input = input;
if (hdr_limits != NULL)
parser->header_limits = *hdr_limits;
+ parser->max_payload_size = max_payload_size;
}
void http_message_parser_deinit(struct http_message_parser *parser)
@@ -98,8 +100,16 @@
i_stream_skip(parser->payload, size);
if (ret == 0 || parser->payload->stream_errno != 0) {
if (ret < 0) {
- parser->error = "Stream error while skipping payload";
- parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM;
+ if (parser->payload->stream_errno == EMSGSIZE) {
+ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE;
+ parser->error = "Payload is too large";
+ } else if (parser->payload->stream_errno == EIO) {
+ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE;
+ parser->error = "Invalid payload";
+ } else {
+ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM;
+ parser->error = "Stream error while skipping payload";
+ }
}
return ret;
}
@@ -370,8 +380,8 @@
}
if (chunked_last) {
- parser->payload =
- http_transfer_chunked_istream_create(parser->input);
+ parser->payload = http_transfer_chunked_istream_create
+ (parser->input, parser->max_payload_size);
} else if (!request) {
/* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23
Section 3.3.3.:
@@ -381,7 +391,8 @@
message body length is determined by reading the connection until
it is closed by the server.
*/
- parser->payload =
+ /* FIXME: enforce max payload size (relevant to http-client only) */
+ parser->payload =
i_stream_create_limit(parser->input, (size_t)-1);
} else {
/* https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23
@@ -412,6 +423,13 @@
http_header_field_delete(parser->msg.header, "Content-Length");
} else if (parser->msg.content_length > 0) {
+ if (parser->max_payload_size > 0
+ && parser->msg.content_length > parser->max_payload_size) {
+ parser->error_code = HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE;
+ parser->error = "Payload is too large";
+ return -1;
+ }
+
/* Got explicit message size from Content-Length: header */
parser->payload =
i_stream_create_limit(parser->input,
@@ -427,6 +445,7 @@
body length, so the message body length is determined by the
number of octets received prior to the server closing the connection.
*/
+ /* FIXME: enforce max payload size (relevant to http-client only) */
parser->payload =
i_stream_create_limit(parser->input, (size_t)-1);
}
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/http-message-parser.h
--- a/src/lib-http/http-message-parser.h Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/http-message-parser.h Sun Sep 15 03:52:01 2013 +0300
@@ -7,12 +7,14 @@
#include "http-header.h"
enum http_message_parse_error {
- HTTP_MESSAGE_PARSE_ERROR_NONE = 0, /* no error */
- HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM, /* stream error */
- HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE, /* unrecoverable generic error */
- HTTP_MESSAGE_PARSE_ERROR_BAD_MESSAGE, /* recoverable generic error */
- HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED, /* used unimplemented feature
- (recoverable) */
+ HTTP_MESSAGE_PARSE_ERROR_NONE = 0, /* no error */
+ HTTP_MESSAGE_PARSE_ERROR_BROKEN_STREAM, /* stream error */
+ HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE, /* unrecoverable generic error */
+ HTTP_MESSAGE_PARSE_ERROR_BAD_MESSAGE, /* recoverable generic error */
+ HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED, /* used unimplemented feature
+ (recoverable) */
+ HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE /* message payload is too large
+ (fatal) */
};
struct http_message {
@@ -35,7 +37,9 @@
struct http_message_parser {
struct istream *input;
+
struct http_header_limits header_limits;
+ uoff_t max_payload_size;
const unsigned char *cur, *end;
@@ -50,8 +54,8 @@
};
void http_message_parser_init(struct http_message_parser *parser,
- struct istream *input, const struct http_header_limits *hdr_limits)
- ATTR_NULL(3);
+ struct istream *input, const struct http_header_limits *hdr_limits,
+ uoff_t max_payload_size) ATTR_NULL(3);
void http_message_parser_deinit(struct http_message_parser *parser);
void http_message_parser_restart(struct http_message_parser *parser,
pool_t pool);
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/http-request-parser.c
--- a/src/lib-http/http-request-parser.c Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/http-request-parser.c Sun Sep 15 03:52:01 2013 +0300
@@ -39,7 +39,7 @@
struct http_request_parser *parser;
parser = i_new(struct http_request_parser, 1);
- http_message_parser_init(&parser->parser, input, hdr_limits);
+ http_message_parser_init(&parser->parser, input, hdr_limits, 0);
return parser;
}
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/http-response-parser.c
--- a/src/lib-http/http-response-parser.c Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/http-response-parser.c Sun Sep 15 03:52:01 2013 +0300
@@ -36,7 +36,7 @@
/* FIXME: implement status line limit */
parser = i_new(struct http_response_parser, 1);
- http_message_parser_init(&parser->parser, input, hdr_limits);
+ http_message_parser_init(&parser->parser, input, hdr_limits, 0);
return parser;
}
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/http-transfer-chunked.c
--- a/src/lib-http/http-transfer-chunked.c Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/http-transfer-chunked.c Sun Sep 15 03:52:01 2013 +0300
@@ -43,6 +43,7 @@
unsigned int parsed_chars;
uoff_t chunk_size, chunk_v_offset, chunk_pos;
+ uoff_t size, max_size;
const char *error;
struct http_header_parser *header_parser;
@@ -327,8 +328,16 @@
i_stream_skip(input, tcstream->cur - tcstream->begin);
if (ret > 0) {
- if (tcstream->state == HTTP_CHUNKED_PARSE_STATE_DATA)
+ if (tcstream->state == HTTP_CHUNKED_PARSE_STATE_DATA) {
tcstream->chunk_v_offset = input->v_offset;
+
+ tcstream->size += tcstream->chunk_size;
+ if (tcstream->max_size > 0 && tcstream->size > tcstream->max_size) {
+ tcstream->error = "Total chunked payload size exceeds maximum";
+ stream->istream.stream_errno = EMSGSIZE;
+ return -1;
+ }
+ }
return ret;
}
}
@@ -495,11 +504,12 @@
}
struct istream *
-http_transfer_chunked_istream_create(struct istream *input)
+http_transfer_chunked_istream_create(struct istream *input, uoff_t max_size)
{
struct http_transfer_chunked_istream *tcstream;
tcstream = i_new(struct http_transfer_chunked_istream, 1);
+ tcstream->max_size = max_size;
tcstream->istream.max_buffer_size =
input->real_stream->max_buffer_size;
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/http-transfer.h
--- a/src/lib-http/http-transfer.h Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/http-transfer.h Sun Sep 15 03:52:01 2013 +0300
@@ -18,7 +18,7 @@
// FIXME: we currently lack a means to get error strings from the input stream
struct istream *
- http_transfer_chunked_istream_create(struct istream *input);
+http_transfer_chunked_istream_create(struct istream *input, uoff_t max_size);
struct ostream *
http_transfer_chunked_ostream_create(struct ostream *output);
diff -r 28e5d58e49dc -r a335db9dca6a src/lib-http/test-http-transfer.c
--- a/src/lib-http/test-http-transfer.c Sun Sep 15 03:50:08 2013 +0300
+++ b/src/lib-http/test-http-transfer.c Sun Sep 15 03:52:01 2013 +0300
@@ -99,7 +99,7 @@
test_begin(t_strdup_printf("http transfer_chunked input valid [%d]", i));
input = i_stream_create_from_data(in, strlen(in));
- chunked = http_transfer_chunked_istream_create(input);
+ chunked = http_transfer_chunked_istream_create(input, 0);
buffer_set_used_size(payload_buffer, 0);
output = o_stream_create_buffer(payload_buffer);
@@ -193,7 +193,7 @@
test_begin(t_strdup_printf("http transfer_chunked input invalid [%d]", i));
input = i_stream_create_from_data(in, strlen(in));
- chunked = http_transfer_chunked_istream_create(input);
+ chunked = http_transfer_chunked_istream_create(input, 0);
buffer_set_used_size(payload_buffer, 0);
output = o_stream_create_buffer(payload_buffer);
@@ -306,7 +306,7 @@
/* create chunked input stream */
input = i_stream_create_from_data
(chunked_buffer->data, chunked_buffer->used);
- ichunked = http_transfer_chunked_istream_create(input);
+ ichunked = http_transfer_chunked_istream_create(input, 0);
/* read back chunk */
buffer_set_used_size(plain_buffer, 0);
More information about the dovecot-cvs
mailing list