dovecot-2.2: lib-http: Simplify http response status-line parsin...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jul 11 09:27:04 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/d7244f7ceca4
changeset: 16596:d7244f7ceca4
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jul 11 09:23:14 2013 +0300
description:
lib-http: Simplify http response status-line parsing code.
Also by not using a temporary string buffer the istream can at least in
theory limit the maximum status-line length (=max memory usage).

diffstat:

 src/lib-http/http-response-parser.c |  83 ++++++++++--------------------------
 1 files changed, 24 insertions(+), 59 deletions(-)

diffs (165 lines):

diff -r a99b211f0409 -r d7244f7ceca4 src/lib-http/http-response-parser.c
--- a/src/lib-http/http-response-parser.c	Thu Jul 11 00:30:28 2013 +0300
+++ b/src/lib-http/http-response-parser.c	Thu Jul 11 09:23:14 2013 +0300
@@ -32,8 +32,6 @@
 	const unsigned char *begin, *cur, *end;
 	const char *error;
 
-	string_t *strbuf;
-
 	enum http_response_parser_state state;
 	struct http_header_parser *header_parser;
 
@@ -51,7 +49,6 @@
 
 	parser = i_new(struct http_response_parser, 1);
 	parser->input = input;
-	parser->strbuf = str_new(default_pool, 128);
 	return parser;
 }
 
@@ -59,7 +56,6 @@
 {
 	struct http_response_parser *parser = *_parser;
 
-	str_free(&parser->strbuf);
 	if (parser->header_parser != NULL)
 		http_header_parser_deinit(&parser->header_parser);
 	if (parser->response_pool != NULL)
@@ -75,7 +71,6 @@
 	i_assert(parser->payload == NULL);
 	parser->content_length = 0;
 	parser->transfer_encoding = NULL;
-	str_truncate(parser->strbuf, 0);
 	if (parser->response_pool != NULL)
 		pool_unref(&parser->response_pool);
 	parser->response_pool = pool_alloconly_create("http_response", 4096);
@@ -86,85 +81,54 @@
 
 static int http_response_parse_version(struct http_response_parser *parser)
 {
-	const unsigned char *first = parser->cur;
-	const char *p;
+	const unsigned char *p = parser->cur;
+	const size_t size = parser->end - parser->cur;
 
 	/* HTTP-version  = HTTP-name "/" DIGIT "." DIGIT
 	   HTTP-name     = %x48.54.54.50 ; "HTTP", case-sensitive
 	 */
-	while (parser->cur < parser->end && http_char_is_value(*parser->cur))
-		parser->cur++;
-
-	if (str_len(parser->strbuf) + (parser->cur-first) > 8)
+	if (size < 8)
+		return 0;
+	if (memcmp(p, "HTTP/", 5) != 0 ||
+	    !i_isdigit(p[5]) || p[6] != '.' || !i_isdigit(p[7]))
 		return -1;
-
-	if ((parser->cur - first) > 0)
-		str_append_n(parser->strbuf, first, parser->cur-first);
-	if (parser->cur == parser->end)
-		return 0;
-
-	if (str_len(parser->strbuf) != 8)
-		return -1;
-	if (strncmp(str_c(parser->strbuf), "HTTP/",5) != 0)
-		return -1;
-	p = str_c(parser->strbuf) + 5;
-	if (!i_isdigit(*p))
-		return -1;
-	parser->response->version_major = *p - '0';
-	p++;
-	if (*(p++) != '.')
-		return -1;
-	if (!i_isdigit(*p))
-		return -1;
-	parser->response->version_minor = *p - '0';
-	str_truncate(parser->strbuf, 0);
+	parser->response->version_major = p[5] - '0';
+	parser->response->version_minor = p[7] - '0';
+	parser->cur += 8;
 	return 1;
 }
 
 static int http_response_parse_status(struct http_response_parser *parser)
 {
-	const unsigned char *first = parser->cur;
-	const unsigned char *p;
+	const unsigned char *p = parser->cur;
+	const size_t size = parser->end - parser->cur;
 
 	/* status-code   = 3DIGIT
 	 */
-	while (parser->cur < parser->end && i_isdigit(*parser->cur)) {
-		parser->cur++;
-		if ((parser->cur - first) > 3)
-			return -1;
-	}
-
-	if (str_len(parser->strbuf) + (parser->cur - first) > 3)
+	if (size < 3)
+		return 0;
+	if (!i_isdigit(p[0]) || !i_isdigit(p[1]) || !i_isdigit(p[2]))
 		return -1;
-	if ((parser->cur - first) > 0)
-		str_append_n(parser->strbuf, first, parser->cur-first);
-	if (parser->cur == parser->end)
-		return 0;
-	if (str_len(parser->strbuf) != 3)
-		return -1;
-	p = str_data(parser->strbuf);
 	parser->response->status =
 		(p[0] - '0')*100 + (p[1] - '0')*10 + (p[2] - '0');
-	str_truncate(parser->strbuf, 0);
+	parser->cur += 3;
 	return 1;
 }
 
 static int http_response_parse_reason(struct http_response_parser *parser)
 {
-	const unsigned char *first = parser->cur;
+	const unsigned char *p = parser->cur;
 
 	/* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
 	 */
-	while (parser->cur < parser->end && http_char_is_text(*parser->cur))
-		parser->cur++;
+	while (p < parser->end && http_char_is_text(*p))
+		p++;
 
-	if ((parser->cur - first) > 0)
-		str_append_n(parser->strbuf, first, parser->cur-first);
-	if (parser->cur == parser->end)
+	if (p == parser->end)
 		return 0;
 	parser->response->reason =
-		p_strdup(parser->response_pool, str_c(parser->strbuf));
-	str_truncate(parser->strbuf, 0);
+		p_strdup_until(parser->response_pool, parser->cur, p);
+	parser->cur = p;
 	return 1;
 }
 
@@ -270,11 +234,11 @@
 
 static int http_response_parse_status_line(struct http_response_parser *parser)
 {
-	size_t size;
+	size_t size, old_bytes = 0;
 	int ret;
 
 	while ((ret = i_stream_read_data(parser->input,
-					 &parser->begin, &size, 0)) > 0) {
+					 &parser->begin, &size, old_bytes)) > 0) {
 		parser->cur = parser->begin;
 		parser->end = parser->cur + size;
 
@@ -284,6 +248,7 @@
 		i_stream_skip(parser->input, parser->cur - parser->begin);
 		if (ret > 0)
 			return 1;
+		old_bytes = i_stream_get_data_size(parser->input);
 	}
 
 	i_assert(ret != -2);


More information about the dovecot-cvs mailing list