summaryrefslogtreecommitdiff
path: root/script/3rd/lua-uri/uri/_relative.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script/3rd/lua-uri/uri/_relative.lua')
-rw-r--r--script/3rd/lua-uri/uri/_relative.lua81
1 files changed, 81 insertions, 0 deletions
diff --git a/script/3rd/lua-uri/uri/_relative.lua b/script/3rd/lua-uri/uri/_relative.lua
new file mode 100644
index 00000000..8cd53ca7
--- /dev/null
+++ b/script/3rd/lua-uri/uri/_relative.lua
@@ -0,0 +1,81 @@
+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")
+ 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)
+end
+
+function M.relativize (self, base) end -- already relative
+
+return M
+-- vi:ts=4 sw=4 expandtab