mirror of https://github.com/sipwise/lua-uri.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.5 KiB
82 lines
2.5 KiB
local M = { _NAME = "uri._relative" }
|
|
local Util = require "uri._util"
|
|
local URI = require "uri"
|
|
Util.subclass_of(M, URI)
|
|
|
|
-- There needs to be an 'init' method in this class, to because the base-class
|
|
-- one expects there to be a 'scheme' value.
|
|
function M.init (self)
|
|
return self
|
|
end
|
|
|
|
function M.scheme (self, ...)
|
|
if select("#", ...) > 0 then
|
|
error("relative URI references can't have a scheme, perhaps you" ..
|
|
" need to resolve this against an absolute URI instead", 2)
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function M.is_relative () return true end
|
|
|
|
-- This implements the algorithm from RFC 3986 section 5.2.3
|
|
-- Note that this takes an additional argument which appears to be required
|
|
-- by the algorithm, but isn't shown when it is used in the RFC.
|
|
local function _merge_paths (base, r, base_has_auth)
|
|
if base_has_auth and base == "" then
|
|
return "/" .. r
|
|
end
|
|
|
|
return base:gsub("[^/]+$", "", 1) .. r
|
|
end
|
|
|
|
local function _do_resolve (self, base)
|
|
if type(base) == "string" then base = assert(URI:new(base)) end
|
|
setmetatable(self, URI)
|
|
|
|
if self:host() or self:userinfo() or self:port() then
|
|
-- network path reference, just needs a scheme
|
|
self:path(Util.remove_dot_segments(self:path()))
|
|
self:scheme(base:scheme())
|
|
return
|
|
end
|
|
|
|
local path = self:path()
|
|
if path == "" then
|
|
self:path(base:path())
|
|
if not self:query() then self:query(base:query()) end
|
|
else
|
|
if path:find("^/") then
|
|
self:path(Util.remove_dot_segments(path))
|
|
else
|
|
local base_has_auth = base:host() or base:userinfo() or base:port()
|
|
local merged = _merge_paths(base:path(), path, base_has_auth)
|
|
self:path(Util.remove_dot_segments(merged))
|
|
end
|
|
end
|
|
self:host(base:host())
|
|
self:userinfo(base:userinfo())
|
|
self:port(base:port())
|
|
self:scheme(base:scheme())
|
|
end
|
|
|
|
function M.resolve (self, base)
|
|
local orig = tostring(self)
|
|
local ok, result = pcall(_do_resolve, self, base)
|
|
if ok then return end
|
|
|
|
-- If the resolving causes an exception, it means that the resulting URI
|
|
-- would be invalid, so we restore self to its original state and rethrow
|
|
-- the exception.
|
|
local restored = assert(URI:new(orig))
|
|
for k in pairs(self) do self[k] = nil end
|
|
for k, v in pairs(restored) do self[k] = v end
|
|
setmetatable(self, getmetatable(restored))
|
|
error("resolved URI reference would be invalid: " .. result, 2)
|
|
end
|
|
|
|
function M.relativize (self, base) end -- already relative
|
|
|
|
return M
|
|
-- vi:ts=4 sw=4 expandtab
|