changeset 16745:572b9a9031e7

lib-http: Implemented limits on overall HTTP header size, size of individual header fields and the number of fields in the header.
author Stephan Bosch <stephan@rename-it.nl>
date Sun, 15 Sep 2013 03:46:12 +0300
parents dca140149d80
children bbe4a469e276
files src/lib-http/http-client-connection.c src/lib-http/http-client.c src/lib-http/http-client.h src/lib-http/http-header-parser.c src/lib-http/http-header-parser.h src/lib-http/http-header.h src/lib-http/http-message-parser.c src/lib-http/http-message-parser.h src/lib-http/http-request-parser.c src/lib-http/http-request-parser.h src/lib-http/http-response-parser.c src/lib-http/http-response-parser.h src/lib-http/http-transfer-chunked.c src/lib-http/test-http-header-parser.c src/lib-http/test-http-response-parser.c src/lib-http/test-http-server.c
diffstat 16 files changed, 207 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- 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);
 }
--- 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;
--- 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;
--- 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);
 			
--- 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);
--- 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;
--- 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);
--- 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);
--- 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;
 }
 
--- 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"
 
 struct http_request_parser *
-http_request_parser_init(struct istream *input);
+http_request_parser_init(struct istream *input,
+	const struct http_header_limits *hdr_limits) ATTR_NULL(2);
 void http_request_parser_deinit(struct http_request_parser **_parser);
 
 int http_request_parse_next(struct http_request_parser *parser,
--- a/src/lib-http/http-response-parser.c	Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-response-parser.c	Sun Sep 15 03:46:12 2013 +0300
@@ -28,12 +28,15 @@
 	const char *response_reason;
 };
 
-struct http_response_parser *http_response_parser_init(struct istream *input)
+struct http_response_parser *
+http_response_parser_init(struct istream *input,
+	const struct http_header_limits *hdr_limits)
 {
 	struct http_response_parser *parser;
 
+	/* FIXME: implement status line limit */
 	parser = i_new(struct http_response_parser, 1);
-	http_message_parser_init(&parser->parser, input);
+	http_message_parser_init(&parser->parser, input, hdr_limits);
 	return parser;
 }
 
--- a/src/lib-http/http-response-parser.h	Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-response-parser.h	Sun Sep 15 03:46:12 2013 +0300
@@ -3,10 +3,12 @@
 
 #include "http-response.h"
 
+struct http_header_limits;
 struct http_response_parser;
 
 struct http_response_parser *
-http_response_parser_init(struct istream *input);
+http_response_parser_init(struct istream *input,
+	const struct http_header_limits *hdr_limits) ATTR_NULL(2);
 void http_response_parser_deinit(struct http_response_parser **_parser);
 
 int http_response_parse_next(struct http_response_parser *parser,
--- a/src/lib-http/http-transfer-chunked.c	Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/http-transfer-chunked.c	Sun Sep 15 03:46:12 2013 +0300
@@ -425,7 +425,9 @@
 	int ret;
 
 	if (tcstream->header_parser == NULL) {
-		tcstream->header_parser = http_header_parser_init(tcstream->istream.parent);
+		/* FIXME: limit trailer size */
+		tcstream->header_parser =
+			http_header_parser_init(tcstream->istream.parent, 0);
 	}
 
 	while ((ret=http_header_parse_next_field(tcstream->header_parser,
--- a/src/lib-http/test-http-header-parser.c	Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/test-http-header-parser.c	Sun Sep 15 03:46:12 2013 +0300
@@ -3,6 +3,7 @@
 #include "test-lib.h"
 #include "istream.h"
 #include "test-common.h"
+#include "http-response.h"
 #include "http-header-parser.h"
 
 #include <time.h>
@@ -14,6 +15,7 @@
 
 struct http_header_parse_test {
 	const char *header;
+	struct http_header_limits limits;
 	const struct http_header_parse_result *fields;
 };
 
@@ -138,7 +140,12 @@
 			"Content-Type: text/html; charset=utf-8\r\n"
 			"Content-Encoding: gzip\r\n"
 			"\r\n",
-		.fields = valid_header_parse_result4
+		.fields = valid_header_parse_result4,
+		.limits = {
+			.max_size = 340,
+			.max_field_size = 46,
+			.max_fields = 12
+		}
 	},{
 		.header =
 			"\r\n",
@@ -155,7 +162,8 @@
 	for (i = 0; i < valid_header_parse_test_count; i++) T_BEGIN {
 		struct istream *input;
 		struct http_header_parser *parser;
-		const char *header, *field_name, *error;
+		const struct http_header_limits *limits;
+		const char *header, *field_name, *error = NULL;
 		const unsigned char *field_data;
 		size_t field_size;
 		int ret;
@@ -163,8 +171,9 @@
 
 		header = valid_header_parse_tests[i].header;
 		header_len = strlen(header);
+		limits = &valid_header_parse_tests[i].limits;
 		input = test_istream_create_data(header, header_len);
-		parser = http_header_parser_init(input);
+		parser = http_header_parser_init(input, limits);
 
 		test_begin(t_strdup_printf("http header valid [%d]", i));
 
@@ -199,35 +208,96 @@
 			j++;
 		}
 
-		test_out("parse success", ret > 0);
+		test_out_reason("parse success", ret > 0, error);
 		test_end();
 		http_header_parser_deinit(&parser);
 	} T_END;
 }
 
-static const char *invalid_header_parse_tests[] = {
-	"Date: Sat, 06 Oct 2012 16:01:44 GMT\r\n"
-	"Server : Apache/2.2.16 (Debian)\r\n"
-	"Last-Modified: Mon, 30 Jul 2012 11:09:28 GMT\r\n"
-	"\r\n",
-	"Date: Sat, 06 Oct 2012 17:18:22 GMT\r\n"
-	"Server: Apache/2.2.3 (CentOS)\r\n"
-	"X Powered By: PHP/5.3.6\r\n"
-	"\r\n",
-	"Host: www.example.com\n\r"
-	"Accept: image/png,image/*;q=0.8,*/*;q=0.5\n\r"
-	"Accept-Language: en-us,en;q=0.5\n\r"
-	"Accept-Encoding: gzip, deflate\n\r"
-	"\n\r",
-	"Host: p5-lrqzb4yavu4l7nagydw-428649-i2-v6exp3-ds.metric.example.com\n"
-	"User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0)\n"
-	"Accept:\t\timage/png,image/*;q=0.8,*/\177;q=0.5\n"
-	"\n",
-	"Date: Sat, 06 Oct 2012 17:12:37 GMT\r\n"
-	"Server: Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze14 with\r\n"
-	"Suhosin-Patch proxy_html/3.0.1 mod_python/3.3.1 Python/2.6.6\r\n"
-	"mod_ssl/2.2.16 OpenSSL/0.9.8o mod_perl/2.0.4 Perl/v5.10.1\r\n"
-	"\r\n",
+static const struct http_header_parse_test invalid_header_parse_tests[] = {
+	{
+		.header = 
+			"Date: Sat, 06 Oct 2012 16:01:44 GMT\r\n"
+			"Server : Apache/2.2.16 (Debian)\r\n"
+			"Last-Modified: Mon, 30 Jul 2012 11:09:28 GMT\r\n"
+			"\r\n"
+	},{
+		.header = 
+			"Date: Sat, 06 Oct 2012 17:18:22 GMT\r\n"
+			"Server: Apache/2.2.3 (CentOS)\r\n"
+			"X Powered By: PHP/5.3.6\r\n"
+			"\r\n"
+	},{
+		.header = 
+			"Host: www.example.com\n\r"
+			"Accept: image/png,image/*;q=0.8,*/*;q=0.5\n\r"
+			"Accept-Language: en-us,en;q=0.5\n\r"
+			"Accept-Encoding: gzip, deflate\n\r"
+			"\n\r"
+	},{
+		.header = 
+			"Host: p5-lrqzb4yavu4l7nagydw-428649-i2-v6exp3-ds.metric.example.com\n"
+			"User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0)\n"
+			"Accept:\t\timage/png,image/*;q=0.8,*/\177;q=0.5\n"
+			"\n"
+	},{
+		.header = 
+			"Date: Sat, 06 Oct 2012 17:12:37 GMT\r\n"
+			"Server: Apache/2.2.16 (Debian) PHP/5.3.3-7+squeeze14 with\r\n"
+			"Suhosin-Patch proxy_html/3.0.1 mod_python/3.3.1 Python/2.6.6\r\n"
+			"mod_ssl/2.2.16 OpenSSL/0.9.8o mod_perl/2.0.4 Perl/v5.10.1\r\n"
+			"\r\n"
+	},{
+		.header = 
+			"Age: 58        \r\n"
+			"Date: Sun, 04 Aug 2013 09:33:09 GMT\r\n"
+			"Expires: Sun, 04 Aug 2013 09:34:08 GMT\r\n"
+			"Cache-Control: max-age=60        \r\n"
+			"Content-Length: 17336     \r\n"
+			"Connection: Keep-Alive\r\n"
+			"Via: NS-CACHE-9.3\r\n"
+			"Server: Apache\r\n"
+			"Vary: Host\r\n"
+			"Last-Modified: Sun, 04 Aug 2013 09:33:07 GMT\r\n"
+			"Content-Type: text/html; charset=utf-8\r\n"
+			"Content-Encoding: gzip\r\n"
+			"\r\n",
+		.limits = { .max_size = 339 }
+	},{
+		.header = 
+			"Age: 58        \r\n"
+			"Date: Sun, 04 Aug 2013 09:33:09 GMT\r\n"
+			"Expires: Sun, 04 Aug 2013 09:34:08 GMT\r\n"
+			"Cache-Control: max-age=60        \r\n"
+			"Content-Length: 17336     \r\n"
+			"Connection: Keep-Alive\r\n"
+			"Via: NS-CACHE-9.3\r\n"
+			"Server: Apache\r\n"
+			"Vary: Host\r\n"
+			"Last-Modified: Sun, 04 Aug 2013 09:33:07 GMT\r\n"
+			"Content-Type: text/html; charset=utf-8\r\n"
+			"Content-Encoding: gzip\r\n"
+			"\r\n",
+		.fields = valid_header_parse_result4,
+		.limits = { .max_field_size = 45 }
+	},{
+		.header = 
+			"Age: 58        \r\n"
+			"Date: Sun, 04 Aug 2013 09:33:09 GMT\r\n"
+			"Expires: Sun, 04 Aug 2013 09:34:08 GMT\r\n"
+			"Cache-Control: max-age=60        \r\n"
+			"Content-Length: 17336     \r\n"
+			"Connection: Keep-Alive\r\n"
+			"Via: NS-CACHE-9.3\r\n"
+			"Server: Apache\r\n"
+			"Vary: Host\r\n"
+			"Last-Modified: Sun, 04 Aug 2013 09:33:07 GMT\r\n"
+			"Content-Type: text/html; charset=utf-8\r\n"
+			"Content-Encoding: gzip\r\n"
+			"\r\n",
+		.fields = valid_header_parse_result4,
+		.limits = { .max_fields = 11 }
+	}
 };
 
 unsigned int invalid_header_parse_test_count = N_ELEMENTS(invalid_header_parse_tests);
@@ -239,14 +309,16 @@
 	for (i = 0; i < invalid_header_parse_test_count; i++) T_BEGIN {
 		struct istream *input;
 		struct http_header_parser *parser;
-		const char *header, *field_name, *error;
+		const struct http_header_limits *limits;
+		const char *header, *field_name, *error = NULL;
 		const unsigned char *field_data;
 		size_t field_size;
 		int ret;
 
-		header = invalid_header_parse_tests[i];
+		header = invalid_header_parse_tests[i].header;
+		limits = &invalid_header_parse_tests[i].limits;
 		input = i_stream_create_from_data(header, strlen(header));
-		parser = http_header_parser_init(input);
+		parser = http_header_parser_init(input, limits);
 
 		test_begin(t_strdup_printf("http header invalid [%d]", i));
 
@@ -255,7 +327,7 @@
 			if (field_name == NULL) break;
 		}
 
-		test_out("parse failure", ret < 0);
+		test_out_reason("parse failure", ret < 0, error);
 		test_end();
 		http_header_parser_deinit(&parser);
 	} T_END;
--- a/src/lib-http/test-http-response-parser.c	Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/test-http-response-parser.c	Sun Sep 15 03:46:12 2013 +0300
@@ -108,7 +108,7 @@
 		response_text = test->response;
 		response_text_len = strlen(response_text);
 		input = test_istream_create_data(response_text, response_text_len);
-		parser = http_response_parser_init(input);
+		parser = http_response_parser_init(input, NULL);
 
 		test_begin(t_strdup_printf("http response valid [%d]", i));
 
@@ -196,7 +196,7 @@
 		test = invalid_response_parse_tests[i];
 		response_text = test;
 		input = i_stream_create_from_data(response_text, strlen(response_text));
-		parser = http_response_parser_init(input);
+		parser = http_response_parser_init(input, NULL);
 
 		test_begin(t_strdup_printf("http response invalid [%d]", i));
 
@@ -212,7 +212,7 @@
 	test_begin("http response with NULs");
 	input = i_stream_create_from_data(invalid_response_with_nuls,
 					  sizeof(invalid_response_with_nuls)-1);
-	parser = http_response_parser_init(input);
+	parser = http_response_parser_init(input, 0);
 	while ((ret=http_response_parse_next(parser, FALSE, &response, &error)) > 0);
 	test_assert(ret < 0);
 	test_end();
--- a/src/lib-http/test-http-server.c	Sun Sep 15 03:44:42 2013 +0300
+++ b/src/lib-http/test-http-server.c	Sun Sep 15 03:46:12 2013 +0300
@@ -84,7 +84,7 @@
 	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);
+	client->parser = http_request_parser_init(client->conn.input, 0);
 }
 
 static void client_accept(void *context ATTR_UNUSED)