dovecot-2.2: lib-http: Implemented limits on request method and ...
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/7c7e3aa13de7
changeset: 16751:7c7e3aa13de7
user: Stephan Bosch <stephan at rename-it.nl>
date: Sun Sep 15 03:54:04 2013 +0300
description:
lib-http: Implemented limits on request method and target length.
diffstat:
src/lib-http/http-request-parser.c | 60 +++++++++++++++++++++++++++++++++----
src/lib-http/http-request-parser.h | 19 ++++++-----
src/lib-http/http-request.h | 13 ++++++++
src/lib-http/test-http-server.c | 6 +++-
4 files changed, 81 insertions(+), 17 deletions(-)
diffs (193 lines):
diff -r a335db9dca6a -r 7c7e3aa13de7 src/lib-http/http-request-parser.c
--- a/src/lib-http/http-request-parser.c Sun Sep 15 03:52:01 2013 +0300
+++ b/src/lib-http/http-request-parser.c Sun Sep 15 03:54:04 2013 +0300
@@ -7,6 +7,8 @@
#include "http-message-parser.h"
#include "http-request-parser.h"
+#define HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH 32
+
enum http_request_parser_state {
HTTP_REQUEST_PARSE_STATE_INIT = 0,
HTTP_REQUEST_PARSE_STATE_SKIP_LINE,
@@ -24,6 +26,8 @@
struct http_message_parser parser;
enum http_request_parser_state state;
+ uoff_t max_target_length;
+
enum http_request_parse_error error_code;
const char *request_method;
@@ -34,12 +38,34 @@
struct http_request_parser *
http_request_parser_init(struct istream *input,
- const struct http_header_limits *hdr_limits)
+ const struct http_request_limits *limits)
{
struct http_request_parser *parser;
+ struct http_header_limits hdr_limits;
+ uoff_t max_payload_size = limits->max_payload_size;
parser = i_new(struct http_request_parser, 1);
- http_message_parser_init(&parser->parser, input, hdr_limits, 0);
+ parser->max_target_length = limits->max_target_length;
+
+ if (limits != NULL)
+ hdr_limits = limits->header;
+ else
+ memset(&hdr_limits, 0, sizeof(hdr_limits));
+
+ /* substitute default limits */
+ if (parser->max_target_length == 0)
+ parser->max_target_length = HTTP_REQUEST_DEFAULT_MAX_TARGET_LENGTH;
+ if (hdr_limits.max_size == 0)
+ hdr_limits.max_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_SIZE;
+ if (hdr_limits.max_field_size == 0)
+ hdr_limits.max_field_size = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELD_SIZE;
+ if (hdr_limits.max_fields == 0)
+ hdr_limits.max_fields = HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELDS;
+ if (max_payload_size == 0)
+ max_payload_size = HTTP_REQUEST_DEFAULT_MAX_PAYLOAD_SIZE;
+
+ http_message_parser_init
+ (&parser->parser, input, &hdr_limits, max_payload_size);
return parser;
}
@@ -69,6 +95,11 @@
while (p < parser->parser.end && http_char_is_token(*p))
p++;
+ if ((p - parser->parser.cur) > HTTP_REQUEST_PARSER_MAX_METHOD_LENGTH) {
+ parser->error_code = HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG;
+ parser->parser.error = "HTTP request method is too long";
+ return -1;
+ }
if (p == parser->parser.end)
return 0;
parser->request_method =
@@ -79,19 +110,32 @@
static int http_request_parse_target(struct http_request_parser *parser)
{
+ struct http_message_parser *_parser = &parser->parser;
const unsigned char *p = parser->parser.cur;
/* We'll just parse anything up to the first SP or a control char.
We could also implement workarounds for buggy HTTP clients and
parse anything up to the HTTP-version and return 301 with the
- target properly encoded. */
- while (p < parser->parser.end && *p > ' ')
+ target properly encoded (FIXME). */
+ while (p < _parser->end && *p > ' ')
p++;
- if (p == parser->parser.end)
+ /* target is too long when explicit limit is exceeded or when input buffer
+ runs out of space */
+ /* FIXME: put limit on full request line rather than target and method
+ separately */
+ /* FIXME: is it wise to keep target in stream buffer? It can become very
+ large for some applications, increasing the stream buffer size */
+ if ((uoff_t)(p - _parser->cur) > parser->max_target_length ||
+ (p == _parser->end && ((uoff_t)(p - _parser->cur) >=
+ i_stream_get_max_buffer_size(_parser->input)))) {
+ parser->error_code = HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG;
+ parser->parser.error = "HTTP request target is too long";
+ return -1;
+ }
+ if (p == _parser->end)
return 0;
- parser->request_target =
- p_strdup_until(parser->parser.msg.pool, parser->parser.cur, p);
+ parser->request_target = p_strdup_until(_parser->msg.pool, _parser->cur, p);
parser->parser.cur = p;
return 1;
}
@@ -272,6 +316,8 @@
return HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
case HTTP_MESSAGE_PARSE_ERROR_NOT_IMPLEMENTED:
return HTTP_REQUEST_PARSE_ERROR_NOT_IMPLEMENTED;
+ case HTTP_MESSAGE_PARSE_ERROR_PAYLOAD_TOO_LARGE:
+ return HTTP_REQUEST_PARSE_ERROR_PAYLOAD_TOO_LARGE;
case HTTP_MESSAGE_PARSE_ERROR_BROKEN_MESSAGE:
return HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST;
default:
diff -r a335db9dca6a -r 7c7e3aa13de7 src/lib-http/http-request-parser.h
--- a/src/lib-http/http-request-parser.h Sun Sep 15 03:52:01 2013 +0300
+++ b/src/lib-http/http-request-parser.h Sun Sep 15 03:54:04 2013 +0300
@@ -4,19 +4,20 @@
#include "http-request.h"
enum http_request_parse_error {
- HTTP_REQUEST_PARSE_ERROR_NONE = 0, /* no error */
- HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM, /* stream error */
- HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST, /* unrecoverable generic error */
- HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST, /* recoverable generic error */
- HTTP_REQUEST_PARSE_ERROR_NOT_IMPLEMENTED, /* used unimplemented feature
- (recoverable) */
- HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG, /* method too long (fatal) */
- HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG /* target too long (fatal) */
+ HTTP_REQUEST_PARSE_ERROR_NONE = 0, /* no error */
+ HTTP_REQUEST_PARSE_ERROR_BROKEN_STREAM, /* stream error */
+ HTTP_REQUEST_PARSE_ERROR_BROKEN_REQUEST, /* unrecoverable generic error */
+ HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST, /* recoverable generic error */
+ HTTP_REQUEST_PARSE_ERROR_NOT_IMPLEMENTED, /* used unimplemented feature
+ (recoverable) */
+ HTTP_REQUEST_PARSE_ERROR_METHOD_TOO_LONG, /* method too long (fatal) */
+ HTTP_REQUEST_PARSE_ERROR_TARGET_TOO_LONG, /* target too long (fatal) */
+ HTTP_REQUEST_PARSE_ERROR_PAYLOAD_TOO_LARGE /* payload too large (fatal) */
};
struct http_request_parser *
http_request_parser_init(struct istream *input,
- const struct http_header_limits *hdr_limits) ATTR_NULL(2);
+ const struct http_request_limits *limits) ATTR_NULL(2);
void http_request_parser_deinit(struct http_request_parser **_parser);
int http_request_parse_next(struct http_request_parser *parser,
diff -r a335db9dca6a -r 7c7e3aa13de7 src/lib-http/http-request.h
--- a/src/lib-http/http-request.h Sun Sep 15 03:52:01 2013 +0300
+++ b/src/lib-http/http-request.h Sun Sep 15 03:54:04 2013 +0300
@@ -5,6 +5,19 @@
struct http_url;
+#define HTTP_REQUEST_DEFAULT_MAX_TARGET_LENGTH (8 * 1024)
+#define HTTP_REQUEST_DEFAULT_MAX_HEADER_SIZE (200 * 1024)
+#define HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELD_SIZE (8 * 1024)
+#define HTTP_REQUEST_DEFAULT_MAX_HEADER_FIELDS 50
+#define HTTP_REQUEST_DEFAULT_MAX_PAYLOAD_SIZE (1 * 1024 * 1024)
+
+struct http_request_limits {
+ uoff_t max_target_length;
+ uoff_t max_payload_size;
+
+ struct http_header_limits header;
+};
+
enum http_request_target_format {
HTTP_REQUEST_TARGET_FORMAT_ORIGIN = 0,
HTTP_REQUEST_TARGET_FORMAT_ABSOLUTE,
diff -r a335db9dca6a -r 7c7e3aa13de7 src/lib-http/test-http-server.c
--- a/src/lib-http/test-http-server.c Sun Sep 15 03:52:01 2013 +0300
+++ b/src/lib-http/test-http-server.c Sun Sep 15 03:54:04 2013 +0300
@@ -81,11 +81,15 @@
static void client_init(int fd)
{
struct client *client;
+ struct http_request_limits req_limits;
+
+ memset(&req_limits, 0, sizeof(req_limits));
+ req_limits.max_target_length = 4096;
client = i_new(struct client, 1);
connection_init_server(clients, &client->conn,
"(http client)", fd, fd);
- client->parser = http_request_parser_init(client->conn.input, 0);
+ client->parser = http_request_parser_init(client->conn.input, &req_limits);
}
static void client_accept(void *context ATTR_UNUSED)
More information about the dovecot-cvs
mailing list