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