dovecot-2.2: http: Improved HTTP header parser state machine and...

dovecot at dovecot.org dovecot at dovecot.org
Fri Jan 10 22:00:54 EET 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/012d6d22aa67
changeset: 17095:012d6d22aa67
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Fri Jan 10 15:00:39 2014 -0500
description:
http: Improved HTTP header parser state machine and error messages.

diffstat:

 src/lib-http/http-header-parser.c |  62 +++++++++++++++++++-------------------
 1 files changed, 31 insertions(+), 31 deletions(-)

diffs (114 lines):

diff -r 4650bfc057fb -r 012d6d22aa67 src/lib-http/http-header-parser.c
--- a/src/lib-http/http-header-parser.c	Fri Jan 10 15:00:28 2014 -0500
+++ b/src/lib-http/http-header-parser.c	Fri Jan 10 15:00:39 2014 -0500
@@ -19,7 +19,6 @@
 	HTTP_HEADER_PARSE_STATE_CR,
 	HTTP_HEADER_PARSE_STATE_LF,
 	HTTP_HEADER_PARSE_STATE_NEW_LINE,
-	HTTP_HEADER_PARSE_STATE_LAST_LINE,
 	HTTP_HEADER_PARSE_STATE_EOH
 };
 
@@ -172,16 +171,24 @@
 		case HTTP_HEADER_PARSE_STATE_INIT:
 			buffer_set_used_size(parser->value_buf, 0);
 			str_truncate(parser->name, 0);
+			if (*parser->cur == '\r') {
+				/* last CRLF */
+				parser->cur++;
+				parser->state = HTTP_HEADER_PARSE_STATE_EOH;
+				if (parser->cur == parser->end)
+					return 0;
+				break;
+			} else if (*parser->cur == '\n') {
+				/* last LF */
+				parser->state = HTTP_HEADER_PARSE_STATE_EOH;
+				break;
+			}
+			/* next line */
 			parser->state = HTTP_HEADER_PARSE_STATE_NAME;
 			/* fall through */
 		case HTTP_HEADER_PARSE_STATE_NAME:
-			if (http_char_is_token(*parser->cur)) {
-				if ((ret=http_header_parse_name(parser)) <= 0)
-					return ret;
-			} else if (*parser->cur != ':' && str_len(parser->name) == 0) {
-				parser->state = HTTP_HEADER_PARSE_STATE_LAST_LINE;
-				break;
-			}
+			if ((ret=http_header_parse_name(parser)) <= 0)
+				return ret;
 			parser->state = HTTP_HEADER_PARSE_STATE_COLON;
 			/* fall through */
 		case HTTP_HEADER_PARSE_STATE_COLON:
@@ -216,6 +223,12 @@
 		case HTTP_HEADER_PARSE_STATE_CR:
 			if (*parser->cur == '\r') {
 				parser->cur++;
+			} else if (*parser->cur != '\n') {
+				parser->error = t_strdup_printf
+					("Invalid character %s in content of header field '%s'",
+						_chr_sanitize(*parser->cur),
+						str_sanitize(str_c(parser->name),64));
+				return -1;
 			}
 			parser->state = HTTP_HEADER_PARSE_STATE_LF;
 			if (parser->cur == parser->end)
@@ -224,7 +237,7 @@
 		case HTTP_HEADER_PARSE_STATE_LF:
 			if (*parser->cur != '\n') {
 				parser->error = t_strdup_printf
-					("Expected line end after header field '%s', but found %s",
+					("Expected LF after CR at end of header field '%s', but found %s",
 						str_sanitize(str_c(parser->name),64),
 						_chr_sanitize(*parser->cur));
 				return -1;
@@ -240,31 +253,14 @@
 				buffer_append_c(parser->value_buf, ' ');
 				parser->state = HTTP_HEADER_PARSE_STATE_OWS;
 				break;
-			}
+			} 
+			/* next header line */
 			parser->state = HTTP_HEADER_PARSE_STATE_INIT;
 			return 1;
-		case HTTP_HEADER_PARSE_STATE_LAST_LINE:
-			if (*parser->cur == '\r') {
-				/* last CRLF */
-				parser->cur++;
-				parser->state = HTTP_HEADER_PARSE_STATE_EOH;
-				if (parser->cur == parser->end)
-					return 0;
-				break;
-			} else if (*parser->cur == '\n') {
-				/* header fully parsed */
-				parser->cur++;
-				parser->state = HTTP_HEADER_PARSE_STATE_EOH;
-				return 1;
-			}
-			parser->error = t_strdup_printf
-				("Expected CRLF or header field name, but found %s",
-					_chr_sanitize(*parser->cur));
-			return -1;
 		case HTTP_HEADER_PARSE_STATE_EOH:
 			if (*parser->cur != '\n') {
 				parser->error = t_strdup_printf
-					("Expected LF after CR at end of header, but found %s",
+					("Encountered stray CR at beginning of header line, followed by %s",
 						_chr_sanitize(*parser->cur));
 				return -1;
 			}
@@ -350,7 +346,11 @@
 	}
 
 	i_assert(ret != -2);
-	if (ret < 0)
-		*error_r = "Stream error";
+	if (ret < 0) {
+		if (i_stream_is_eof(parser->input))
+			*error_r = "Premature end of input";
+		else
+			*error_r = "Stream error";
+	}
 	return ret;
 }


More information about the dovecot-cvs mailing list