dovecot-2.2: lib-http: Implemented limits on overall HTTP header...
dovecot at dovecot.org
dovecot at dovecot.org
Sun Sep 15 03:50:34 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/572b9a9031e7
changeset: 16745:572b9a9031e7
user: Stephan Bosch <stephan at rename-it.nl>
date: Sun Sep 15 03:46:12 2013 +0300
description:
lib-http: Implemented limits on overall HTTP header size, size of individual header fields and the number of fields in the header.
diffstat:
src/lib-http/http-client-connection.c | 3 +-
src/lib-http/http-client.c | 1 +
src/lib-http/http-client.h | 3 +
src/lib-http/http-header-parser.c | 61 ++++++++++++-
src/lib-http/http-header-parser.h | 5 +-
src/lib-http/http-header.h | 6 +
src/lib-http/http-message-parser.c | 12 +-
src/lib-http/http-message-parser.h | 6 +-
src/lib-http/http-request-parser.c | 6 +-
src/lib-http/http-request-parser.h | 3 +-
src/lib-http/http-response-parser.c | 7 +-
src/lib-http/http-response-parser.h | 4 +-
src/lib-http/http-transfer-chunked.c | 4 +-
src/lib-http/test-http-header-parser.c | 134 +++++++++++++++++++++++-------
src/lib-http/test-http-response-parser.c | 6 +-
src/lib-http/test-http-server.c | 2 +-
16 files changed, 207 insertions(+), 56 deletions(-)
diffs (truncated from 605 to 300 lines):
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-client-connection.c Sun Sep 15 03:46:12 2013 +0300
@@ -721,7 +721,8 @@
}
/* start protocol I/O */
- conn->http_parser = http_response_parser_init(conn->conn.input);
+ conn->http_parser = http_response_parser_init
+ (conn->conn.input, &conn->client->set.response_hdr_limits);
o_stream_set_flush_callback(conn->conn.output,
http_client_connection_output, conn);
}
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-client.c
--- a/src/lib-http/http-client.c Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-client.c Sun Sep 15 03:46:12 2013 +0300
@@ -96,6 +96,7 @@
(set->max_pipelined_requests > 0 ? set->max_pipelined_requests : 1);
client->set.max_attempts = set->max_attempts;
client->set.max_redirects = set->max_redirects;
+ client->set.response_hdr_limits = set->response_hdr_limits;
client->set.request_timeout_msecs = set->request_timeout_msecs;
client->set.connect_timeout_msecs = set->connect_timeout_msecs;
client->set.soft_connect_timeout_msecs = set->soft_connect_timeout_msecs;
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-client.h
--- a/src/lib-http/http-client.h Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-client.h Sun Sep 15 03:46:12 2013 +0300
@@ -59,6 +59,9 @@
/* maximum number of attempts for a request */
unsigned int max_attempts;
+ /* response header limits */
+ struct http_header_limits response_hdr_limits;
+
/* max time to wait for HTTP request to finish before retrying
(default = unlimited) */
unsigned int request_timeout_msecs;
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-header-parser.c
--- a/src/lib-http/http-header-parser.c Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-header-parser.c Sun Sep 15 03:46:12 2013 +0300
@@ -6,6 +6,7 @@
#include "str.h"
#include "str-sanitize.h"
#include "http-parser.h"
+#include "http-header.h"
#include "http-header-parser.h"
@@ -25,6 +26,10 @@
struct http_header_parser {
struct istream *input;
+ struct http_header_limits limits;
+ uoff_t size, field_size;
+ unsigned int field_count;
+
const unsigned char *begin, *cur, *end;
const char *error;
@@ -34,9 +39,9 @@
enum http_header_parse_state state;
};
-// FIXME(Stephan): Add support for limiting maximum header size.
-
-struct http_header_parser *http_header_parser_init(struct istream *input)
+struct http_header_parser *
+http_header_parser_init(struct istream *input,
+ const struct http_header_limits *limits)
{
struct http_header_parser *parser;
@@ -45,6 +50,16 @@
parser->name = str_new(default_pool, 128);
parser->value_buf = buffer_create_dynamic(default_pool, 4096);
+ if (limits != NULL)
+ parser->limits = *limits;
+
+ if (parser->limits.max_size == 0)
+ parser->limits.max_size = (uoff_t)-1;
+ if (parser->limits.max_field_size == 0)
+ parser->limits.max_field_size = (uoff_t)-1;
+ if (parser->limits.max_fields == 0)
+ parser->limits.max_fields = (unsigned int)-1;
+
return parser;
}
@@ -62,6 +77,9 @@
void http_header_parser_reset(struct http_header_parser *parser)
{
parser->state = HTTP_HEADER_PARSE_STATE_INIT;
+ parser->size = 0;
+ parser->field_size = 0;
+ parser->field_count = 0;
}
static int http_header_parse_name(struct http_header_parser *parser)
@@ -144,7 +162,7 @@
if (http_char_is_token(*parser->cur)) {
if ((ret=http_header_parse_name(parser)) <= 0)
return ret;
- } else if (str_len(parser->name) == 0) {
+ } else if (*parser->cur != ':' && str_len(parser->name) == 0) {
parser->state = HTTP_HEADER_PARSE_STATE_LAST_LINE;
break;
}
@@ -163,6 +181,10 @@
parser->error = "Empty header field name";
return -1;
}
+ if (++parser->field_count > parser->limits.max_fields) {
+ parser->error = "Excessive number of header fields";
+ return -1;
+ }
parser->state = HTTP_HEADER_PARSE_STATE_OWS;
/* fall through */
case HTTP_HEADER_PARSE_STATE_OWS:
@@ -203,7 +225,7 @@
parser->state = HTTP_HEADER_PARSE_STATE_OWS;
break;
}
- parser->state = HTTP_HEADER_PARSE_STATE_NAME;
+ parser->state = HTTP_HEADER_PARSE_STATE_INIT;
return 1;
case HTTP_HEADER_PARSE_STATE_LAST_LINE:
if (*parser->cur == '\r') {
@@ -247,12 +269,35 @@
const char **name_r, const unsigned char **data_r, size_t *size_r,
const char **error_r)
{
+ const uoff_t max_size = parser->limits.max_size;
+ const uoff_t max_field_size = parser->limits.max_field_size;
const unsigned char *data;
- size_t size;
+ uoff_t size;
int ret;
+ *error_r = NULL;
+
while ((ret=i_stream_read_data
(parser->input, &parser->begin, &size, 0)) > 0) {
+
+ /* check header size limits */
+ if (parser->size >= max_size) {
+ *error_r = "Excessive header size";
+ return -1;
+ }
+ if (parser->field_size > max_field_size) {
+ *error_r = "Excessive header field size";
+ return -1;
+ }
+
+ /* don't parse beyond header size limits */
+ if (size > (max_size - parser->size))
+ size = max_size - parser->size;
+ if (size > (max_field_size - parser->field_size)) {
+ size = max_field_size - parser->field_size;
+ size = (size == 0 ? 1 : size); /* need to parse one more byte */
+ }
+
parser->cur = parser->begin;
parser->end = parser->cur + size;
@@ -262,8 +307,12 @@
}
i_stream_skip(parser->input, parser->cur - parser->begin);
+ parser->size += parser->cur - parser->begin;
+ parser->field_size += parser->cur - parser->begin;
if (ret == 1) {
+ parser->field_size = 0;
+
if (parser->state != HTTP_HEADER_PARSE_STATE_EOH) {
data = buffer_get_data(parser->value_buf, &size);
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-header-parser.h
--- a/src/lib-http/http-header-parser.h Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-header-parser.h Sun Sep 15 03:46:12 2013 +0300
@@ -1,9 +1,12 @@
#ifndef HTTP_HEADER_PARSER_H
#define HTTP_HEADER_PARSER_H
+struct http_header_limits;
struct http_header_parser;
-struct http_header_parser *http_header_parser_init(struct istream *input);
+struct http_header_parser *
+http_header_parser_init(struct istream *input,
+ const struct http_header_limits *limits);
void http_header_parser_deinit(struct http_header_parser **_parser);
void http_header_parser_reset(struct http_header_parser *parser);
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-header.h
--- a/src/lib-http/http-header.h Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-header.h Sun Sep 15 03:46:12 2013 +0300
@@ -3,6 +3,12 @@
struct http_header;
+struct http_header_limits {
+ uoff_t max_size;
+ uoff_t max_field_size;
+ unsigned int max_fields;
+};
+
struct http_header_field {
const char *key; /* FIXME: rename to 'name' for v2.3 */
const char *value;
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-message-parser.c
--- a/src/lib-http/http-message-parser.c Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-message-parser.c Sun Sep 15 03:46:12 2013 +0300
@@ -13,10 +13,12 @@
#include <ctype.h>
void http_message_parser_init(struct http_message_parser *parser,
- struct istream *input)
+ struct istream *input, const struct http_header_limits *hdr_limits)
{
memset(parser, 0, sizeof(*parser));
parser->input = input;
+ if (hdr_limits != NULL)
+ parser->header_limits = *hdr_limits;
}
void http_message_parser_deinit(struct http_message_parser *parser)
@@ -34,10 +36,12 @@
{
i_assert(parser->payload == NULL);
- if (parser->header_parser == NULL)
- parser->header_parser = http_header_parser_init(parser->input);
- else
+ if (parser->header_parser == NULL) {
+ parser->header_parser =
+ http_header_parser_init(parser->input, &parser->header_limits);
+ } else {
http_header_parser_reset(parser->header_parser);
+ }
if (parser->msg.pool != NULL)
pool_unref(&parser->msg.pool);
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-message-parser.h
--- a/src/lib-http/http-message-parser.h Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-message-parser.h Sun Sep 15 03:46:12 2013 +0300
@@ -4,7 +4,7 @@
#include "http-response.h"
#include "http-transfer.h"
-struct http_header;
+#include "http-header.h"
struct http_message {
pool_t pool;
@@ -26,6 +26,7 @@
struct http_message_parser {
struct istream *input;
+ struct http_header_limits header_limits;
const unsigned char *cur, *end;
@@ -37,7 +38,8 @@
};
void http_message_parser_init(struct http_message_parser *parser,
- struct istream *input);
+ struct istream *input, const struct http_header_limits *hdr_limits)
+ 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 dca140149d80 -r 572b9a9031e7 src/lib-http/http-request-parser.c
--- a/src/lib-http/http-request-parser.c Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-request-parser.c Sun Sep 15 03:46:12 2013 +0300
@@ -29,12 +29,14 @@
unsigned int skipping_line:1;
};
-struct http_request_parser *http_request_parser_init(struct istream *input)
+struct http_request_parser *
+http_request_parser_init(struct istream *input,
+ const struct http_header_limits *hdr_limits)
{
struct http_request_parser *parser;
parser = i_new(struct http_request_parser, 1);
- http_message_parser_init(&parser->parser, input);
+ http_message_parser_init(&parser->parser, input, hdr_limits);
return parser;
}
diff -r dca140149d80 -r 572b9a9031e7 src/lib-http/http-request-parser.h
--- a/src/lib-http/http-request-parser.h Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-request-parser.h Sun Sep 15 03:46:12 2013 +0300
@@ -4,7 +4,8 @@
#include "http-request.h"
More information about the dovecot-cvs
mailing list