diff options
author | Valentin Bartenev <vbart@nginx.com> | 2019-09-17 18:40:21 +0300 |
---|---|---|
committer | Valentin Bartenev <vbart@nginx.com> | 2019-09-17 18:40:21 +0300 |
commit | 6352c21a58d66db99f8f981c37e6d57e62fc24a2 (patch) | |
tree | 6c9c4a5bf510d5847b7f5667b8195bac79410b52 | |
parent | 3b77e402a903d9f7a6eeb32f7930d8979f8e0c9e (diff) | |
download | unit-6352c21a58d66db99f8f981c37e6d57e62fc24a2.tar.gz unit-6352c21a58d66db99f8f981c37e6d57e62fc24a2.tar.bz2 |
HTTP parser: fixed parsing of target after literal space character.
In theory, all space characters in request target must be encoded; however,
some clients may violate the specification. For the sake of interoperability,
Unit supports unencoded space characters.
Previously, if there was a space character before the extension or arguments
parts, those parts weren't recognized. Also, quoted symbols and complex
target weren't detected after a space character.
Diffstat (limited to '')
-rw-r--r-- | src/nxt_http_parse.c | 20 | ||||
-rw-r--r-- | src/test/nxt_http_parse_test.c | 15 | ||||
-rw-r--r-- | test/test_python_application.py | 31 |
3 files changed, 63 insertions, 3 deletions
diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index 4d806c61..5b009d96 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -164,6 +164,7 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, { u_char *p, ch, *after_slash, *exten, *args; nxt_int_t rc; + nxt_bool_t rest; nxt_http_ver_t ver; nxt_http_target_traps_e trap; @@ -256,6 +257,9 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, after_slash = p + 1; exten = NULL; args = NULL; + rest = 0; + +continue_target: for ( ;; ) { p++; @@ -312,6 +316,8 @@ nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, rest_of_target: + rest = 1; + for ( ;; ) { p++; @@ -378,7 +384,12 @@ space_after_target: } rp->space_in_target = 1; - goto rest_of_target; + + if (rest) { + goto rest_of_target; + } + + goto continue_target; } /* " HTTP/1.1\r\n" or " HTTP/1.1\n" */ @@ -392,7 +403,12 @@ space_after_target: } rp->space_in_target = 1; - goto rest_of_target; + + if (rest) { + goto rest_of_target; + } + + goto continue_target; } nxt_memcpy(ver.str, &p[1], 8); diff --git a/src/test/nxt_http_parse_test.c b/src/test/nxt_http_parse_test.c index 6fbda25a..5498cb1f 100644 --- a/src/test/nxt_http_parse_test.c +++ b/src/test/nxt_http_parse_test.c @@ -206,13 +206,26 @@ static nxt_http_parse_test_case_t nxt_http_test_cases[] = { }} }, { + nxt_string("GET /na %20me.ext?args HTTP/1.0\r\n\r\n"), + NXT_DONE, + &nxt_http_parse_test_request_line, + { .request_line = { + nxt_string("GET"), + nxt_string("/na %20me.ext?args"), + nxt_string("ext"), + nxt_string("args"), + "HTTP/1.0", + 0, 1, 1 + }} + }, + { nxt_string("GET / HTTP/1.0 HTTP/1.1\r\n\r\n"), NXT_DONE, &nxt_http_parse_test_request_line, { .request_line = { nxt_string("GET"), nxt_string("/ HTTP/1.0"), - nxt_null_string, + nxt_string("0"), nxt_null_string, "HTTP/1.1", 0, 0, 1 diff --git a/test/test_python_application.py b/test/test_python_application.py index 1f366570..5b6e2089 100644 --- a/test/test_python_application.py +++ b/test/test_python_application.py @@ -71,6 +71,37 @@ class TestPythonApplication(TestApplicationPython): 'Query-String header', ) + def test_python_application_query_string_space(self): + self.load('query_string') + + resp = self.get(url='/ ?var1=val1&var2=val2') + self.assertEqual( + resp['headers']['Query-String'], + 'var1=val1&var2=val2', + 'Query-String space', + ) + + resp = self.get(url='/ %20?var1=val1&var2=val2') + self.assertEqual( + resp['headers']['Query-String'], + 'var1=val1&var2=val2', + 'Query-String space 2', + ) + + resp = self.get(url='/ %20 ?var1=val1&var2=val2') + self.assertEqual( + resp['headers']['Query-String'], + 'var1=val1&var2=val2', + 'Query-String space 3', + ) + + resp = self.get(url='/blah %20 blah? var1= val1 & var2=val2') + self.assertEqual( + resp['headers']['Query-String'], + ' var1= val1 & var2=val2', + 'Query-String space 4', + ) + def test_python_application_query_string_empty(self): self.load('query_string') |