Skip to content

Commit

Permalink
Changes absolute_path() behavior with respect to dot and dot-dot path…
Browse files Browse the repository at this point in the history
… segments

to comply with RFC 3986, section 5.2. Fixes #1129
  • Loading branch information
nnposter committed Feb 25, 2018
1 parent cec59fa commit 4303c2f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 17 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG
@@ -1,5 +1,8 @@
#Nmap Changelog ($Id$); -*-text-*-

o [NSE][GH#1129] Changed url.absolute() behavior with respect to dot and
dot-dot path segments to comply with RFC 3986, section 5.2. [nnposter]

o Removed deprecated and undocumented aliases for several long options that
used underscores instead of hyphens, such as --max_retries. [Daniel Miller]

Expand Down
60 changes: 43 additions & 17 deletions nselib/url.lua
Expand Up @@ -82,24 +82,27 @@ end
-- @return The corresponding absolute path.
-----------------------------------------------------------------------------
local function absolute_path(base_path, relative_path)
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
local path = string.gsub(base_path, "[^/]*$", "")
.. relative_path
path = string.gsub(path, "([^/]*%./)", function (s)
if s ~= "./" then return s else return "" end
end)
path = string.gsub(path, "/%.$", "/")
local reduced
while reduced ~= path do
reduced = path
path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
if s ~= "../../" then return "" else return s end
end)
-- Function for normalizing trailing dot and dot-dot by adding the final /
local fixdots = function (s)
return s:gsub("%f[^/\0]%.$", "./"):gsub("%f[^/\0]%.%.$", "../")
end
local path = relative_path
if path:sub(1, 1) ~= "/" then
path = fixdots(base_path):gsub("[^/]*$", path)
end
path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
if s ~= "../.." then return "" else return s end
end)
return path
-- Break the path into segments, processing dot and dot-dot
local segs = {}
for s in fixdots(path):gmatch("[^/]*") do
if s == "." then -- ignore
elseif s == ".." then -- remove the previous segment
if #segs > 1 or #segs == 1 and segs[#segs] ~= "" then
table.remove(segs)
end
else -- add a regular segment, possibly empty
table.insert(segs, s)
end
end
return table.concat(segs, "/")
end
Expand Down Expand Up @@ -475,4 +478,27 @@ for k, v in pairs(expected) do
test_suite:add_test(unittest.equal(result[k], v), k)
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}
{'a', '.', '' },
{'a', './', '' },
{'..', 'b', 'b' },
{'../', 'b', 'b' },
{'/', '..', '/' },
{'/', '../', '/' },
{'/../', '..', '/' },
{'/../', '../', '/' },
{'a/..', 'b', 'b' },
{'a/../', 'b', 'b' },
{'/a/..', '', '/' },
{'', '/a/..', '/' },
{'', '/a//..', '/a/' },
}
for k, v in ipairs(absolute_path_tests) do
local bpath, rpath, expected = table.unpack(v)
test_suite:add_test(unittest.equal(absolute_path(bpath, rpath), expected),
("absolute_path #%d (%q,%q)"):format(k, bpath, rpath))
end
return _ENV;

0 comments on commit 4303c2f

Please sign in to comment.