From 3d6cdfc49a617ff39e16d9978fe697d02adb874f Mon Sep 17 00:00:00 2001 From: Miguel de Moura Date: Mon, 8 Nov 2021 02:42:11 +0000 Subject: [PATCH] Fix url parse_path() discarding consecutive slashes The `parse_path` function from `nselib/url.lua` splits a path into segments using the `/` delimiter. However, it ends up discarding consecutive `/`s as it doesn't add empty segments to the parsed table. This patch ensures that we preserve these empty segments and thus are able to rebuild the correct path with the `build_path` function. --- nselib/url.lua | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/nselib/url.lua b/nselib/url.lua index e066a5f10..dac652d4f 100644 --- a/nselib/url.lua +++ b/nselib/url.lua @@ -308,9 +308,19 @@ end ----------------------------------------------------------------------------- function parse_path(path) local parsed = {} - path = path or "" - --path = string.gsub(path, "%s", "") - string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) + if path == nil or path == "" then + return parsed + end + for slashes, segment in string.gmatch(path, "(/*)([^/]*)") do + -- Append empty segments to ensure presence of consecutive `/` isn't lost. + for _ = 1, string.len(slashes) - 1 do + table.insert(parsed, "") + end + -- Append path segment + if segment ~= "" then + table.insert(parsed, segment) + end + end for i, v in ipairs(parsed) do parsed[i] = unescape(v) end @@ -503,6 +513,36 @@ for k, v in pairs(expected) do test_suite:add_test(unittest.equal(result[k], v), k) end +local parse_path_tests = { + -- path, expected_tbl, expected_tbl_size + {"/", {}, 0}, + {"//", {""}, 1}, + {"///", {"", ""}, 2}, + {"/test", {"test"}, 1}, + {"/test/", {"test"}, 1}, + {"/test//", {"test", ""}, 2}, + {"/test//test", {"test", "", "test"}, 3}, + {"/test//test/", {"test", "", "test"}, 3}, +} + +for test_k, test_v in ipairs(parse_path_tests) do + local path, expected_tbl, expected_tbl_size = table.unpack(test_v) + local parsed_path = parse_path(path) + + local parsed_path_size = 0 + for expected_k, expected_v in pairs(expected_tbl) do + test_suite:add_test( + unittest.equal(parsed_path[expected_k], expected_v), + ("parse_path #%d `%q` - tbl key `%q`"):format(test_k, path, expected_k) + ) + parsed_path_size = parsed_path_size + 1 + end + test_suite:add_test( + unittest.equal(parsed_path_size, expected_tbl_size), + ("parse_path #%d `%q` - tbl size"):format(test_k, path) + ) +end + -- path merging tests for compliance with RFC 3986, section 5.2 -- https://tools.ietf.org/html/rfc3986#section-5.2 local absolute_path_tests = { -- {bpath, rpath, expected}