diff --git a/CHANGELOG b/CHANGELOG index d48211aa7..9f002953d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,9 @@ o [GH#1204] Nmap could be fooled into ignoring TCP response packets if they used an unknown TCP Option, which would misalign the validation, causing it to fail. [Clément Notin, Daniel Miller] +o [NSE]The HTTP response parser now tolerates status lines without a reason + phrase, which improves compatibility with some HTTP servers. [nnposter] + o [NSE][GH#1169][GH#1170][GH#1171]][GH#1198] Parser for HTTP Set-Cookie header is now more compliant with RFC 6265: - empty attributes are tolerated diff --git a/nselib/http.lua b/nselib/http.lua index 3a546de66..ce4aaa903 100644 --- a/nselib/http.lua +++ b/nselib/http.lua @@ -657,7 +657,7 @@ end local function parse_status_line(status_line, response) response["status-line"] = status_line local version, status, reason_phrase = string.match(status_line, - "^HTTP/(%d+%.%d+) +(%d+) +(.-)\r?\n$") + "^HTTP/(%d+%.%d+) +(%d+)%f[ \r\n] *(.-)\r?\n$") if not version then return nil, string.format("Error parsing status-line %q.", status_line) end @@ -2895,6 +2895,58 @@ do test_suite:add_test(unittest.keys_equal(parsed, test.parsed), test.name) end end + + local status_line_tests = { + { name = "valid status line", + line = "HTTP/1.0 200 OK\r\n", + result = true, + parsed = { + version = "1.0", + status = 200, + } + }, + { name = "malformed version in status line", + line = "HTTP/1. 200 OK\r\n", + result = false, + parsed = { + version = nil, + status = nil, + } + }, + { name = "non-integer status code in status line", + line = "HTTP/1.0 20A OK\r\n", + result = false, + parsed = { + version = "1.0", + status = nil, + } + }, + { name = "missing reason phrase in status line", + line = "HTTP/1.0 200\r\n", + result = true, + parsed = { + version = "1.0", + status = 200, + } + }, + } + + for _, test in ipairs(status_line_tests) do + local response = {} + local result, error = parse_status_line(test.line, response) + if test.result then + test_suite:add_test(unittest.not_nil(result), test.name) + else + test_suite:add_test(unittest.is_nil(result), test.name) + test_suite:add_test(unittest.not_nil(error), test.name) + end + test_suite:add_test(unittest.equal(response["status-line"], test.line), test.name) + if result then + test_suite:add_test(unittest.equal(response.status, test.parsed.status), test.name) + test_suite:add_test(unittest.equal(response.version, test.parsed.version), test.name) + end + end + end return _ENV;