Tarantool development patches archive
 help / color / mirror / Atom feed
From: Ilya Markov <imarkov@tarantool.org>
To: georgy@tarantool.org
Cc: tarantool-patches@freelists.org
Subject: [tarantool-patches] [http.client 1/2] http: Remove parsed status line from headers
Date: Fri, 15 Jun 2018 17:24:10 +0300	[thread overview]
Message-ID: <02e9c328f4c895dec7655e91ab62004988ff0575.1529072604.git.imarkov@tarantool.org> (raw)
In-Reply-To: <cover.1529072604.git.imarkov@tarantool.org>
In-Reply-To: <cover.1529072604.git.imarkov@tarantool.org>

Bug: Header parser validates http status line and besides saving http
status, saves valid characters to header name, which is wrong.

Fix this with skipping status line after validation without saving it as
a header.

In scope of #3451
---
 src/http_parser.c                 | 30 +++++++++++++++++++++++++++++-
 src/http_parser.h                 |  1 +
 src/lua/httpc.c                   |  3 +--
 test/app-tap/http_client.test.lua |  3 ++-
 4 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/src/http_parser.c b/src/http_parser.c
index 7166903..64f20e5 100644
--- a/src/http_parser.c
+++ b/src/http_parser.c
@@ -220,6 +220,8 @@ http_parse_header_line(struct http_parser *parser, char **bufp,
 
 	enum {
 		sw_start = 0,
+		skip_status_line,
+		skipped_status_line_almost_done,
 		sw_name,
 		sw_space_before_value,
 		sw_value,
@@ -271,6 +273,25 @@ http_parse_header_line(struct http_parser *parser, char **bufp,
 				break;
 			}
 			break;
+		case skip_status_line:
+			switch (ch) {
+			case LF:
+				goto skipped_status;
+			case CR:
+				state = skipped_status_line_almost_done;
+			default:
+				break;
+			}
+			break;
+		case skipped_status_line_almost_done:
+			switch (ch) {
+			case LF:
+				goto skipped_status;
+			case CR:
+				break;
+			default:
+				return HTTP_PARSE_INVALID;
+			}
 		/* http_header name */
 		case sw_name:
 			c = lowcase[ch];
@@ -304,8 +325,11 @@ http_parse_header_line(struct http_parser *parser, char **bufp,
 				if (rc == HTTP_PARSE_INVALID) {
 					parser->http_minor = -1;
 					parser->http_major = -1;
+					state = sw_start;
+				} else {
+					/* Skip it till end of line. */
+					state = skip_status_line;
 				}
-				state = sw_start;
 				break;
 			}
 			if (ch == '\0')
@@ -389,6 +413,10 @@ http_parse_header_line(struct http_parser *parser, char **bufp,
 		}
 	}
 
+skipped_status:
+	*bufp = p + 1;
+	return HTTP_PARSE_CONTINUE;
+
 done:
 	*bufp = p + 1;
 	return HTTP_PARSE_OK;
diff --git a/src/http_parser.h b/src/http_parser.h
index 5e20f53..c4d59a9 100644
--- a/src/http_parser.h
+++ b/src/http_parser.h
@@ -36,6 +36,7 @@
 
 enum {
 	HTTP_PARSE_OK,
+	HTTP_PARSE_CONTINUE,
 	HTTP_PARSE_DONE,
 	HTTP_PARSE_INVALID
 };
diff --git a/src/lua/httpc.c b/src/lua/httpc.c
index 45abb98..0fe27d4 100644
--- a/src/lua/httpc.c
+++ b/src/lua/httpc.c
@@ -69,13 +69,12 @@ parse_headers(lua_State *L, char *buffer, size_t len)
 	lua_newtable(L);
 	while (true) {
 		int rc = http_parse_header_line(&parser, &buffer, end_buf);
-		if (rc == HTTP_PARSE_INVALID) {
+		if (rc == HTTP_PARSE_INVALID || rc == HTTP_PARSE_CONTINUE) {
 			continue;
 		}
 		if (rc == HTTP_PARSE_DONE) {
 			break;
 		}
-
 		if (rc == HTTP_PARSE_OK) {
 			lua_pushlstring(L, parser.header_name,
 					parser.header_name_idx);
diff --git a/test/app-tap/http_client.test.lua b/test/app-tap/http_client.test.lua
index 887395d..d9380c0 100755
--- a/test/app-tap/http_client.test.lua
+++ b/test/app-tap/http_client.test.lua
@@ -197,7 +197,7 @@ local function test_errors(test)
 end
 
 local function test_headers(test, url, opts)
-    test:plan(15)
+    test:plan(16)
     local http = client:new()
     local r = http:get(url .. 'headers', opts)
     test:is(type(r.headers["set-cookie"]), 'string', "set-cookie check")
@@ -205,6 +205,7 @@ local function test_headers(test, url, opts)
     test:ok(r.headers["set-cookie"]:match("age = 17"), "set-cookie check")
     test:is(r.headers["content-type"], "application/json", "content-type check")
     test:is(r.headers["my_header"], "value1,value2", "other header check")
+    test:isnil(r.headers["11200ok"], "http status line not included in headers")
     test:is(r.cookies["likes"][1], "cheese", "cookie value check")
     test:ok(r.cookies["likes"][2][1]:match("Expires"), "cookie option check")
     test:ok(r.cookies["likes"][2][3]:match("HttpOnly"), "cookie option check")
-- 
2.7.4

  reply	other threads:[~2018-06-15 14:24 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-15 14:24 [tarantool-patches] [http.client 0/2] Fix parsing headers Ilya Markov
2018-06-15 14:24 ` Ilya Markov [this message]
2018-06-15 14:24 ` [tarantool-patches] [http.client 2/2] http: Fix parse long headers names Ilya Markov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=02e9c328f4c895dec7655e91ab62004988ff0575.1529072604.git.imarkov@tarantool.org \
    --to=imarkov@tarantool.org \
    --cc=georgy@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [tarantool-patches] [http.client 1/2] http: Remove parsed status line from headers' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox