summaryrefslogtreecommitdiff
path: root/script/3rd/lua-uri/uri/urn.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script/3rd/lua-uri/uri/urn.lua')
-rw-r--r--script/3rd/lua-uri/uri/urn.lua131
1 files changed, 131 insertions, 0 deletions
diff --git a/script/3rd/lua-uri/uri/urn.lua b/script/3rd/lua-uri/uri/urn.lua
new file mode 100644
index 00000000..aa4b1776
--- /dev/null
+++ b/script/3rd/lua-uri/uri/urn.lua
@@ -0,0 +1,131 @@
+local M = { _NAME = "uri.urn" }
+local Util = require "uri._util"
+local URI = require "uri"
+Util.subclass_of(M, URI)
+
+-- This implements RFC 2141, and attempts to change the class of the URI object
+-- to one of its subclasses for further validation and normalization of the
+-- namespace-specific string.
+
+-- Check NID syntax matches RFC 2141 section 2.1.
+local function _valid_nid (nid)
+ if nid == "" then return nil, "missing completely" end
+ if nid:len() > 32 then return nil, "too long" end
+ if not nid:find("^[A-Za-z0-9][-A-Za-z0-9]*$") then
+ return nil, "contains illegal character"
+ end
+ if nid:lower() == "urn" then return nil, "'urn' is reserved" end
+ return true
+end
+
+-- Check NSS syntax matches RFC 2141 section 2.2.
+local function _valid_nss (nss)
+ if nss == "" then return nil, "can't be empty" end
+ if nss:find("[^A-Za-z0-9()+,%-.:=@;$_!*'/%%]") then
+ return nil, "contains illegal character"
+ end
+ return true
+end
+
+local function _validate_and_normalize_path (path)
+ local _, _, nid, nss = path:find("^([^:]+):(.*)$")
+ if not nid then return nil, "illegal path syntax for URN" end
+
+ local ok, msg = _valid_nid(nid)
+ if not ok then
+ return nil, "invalid namespace identifier (" .. msg .. ")"
+ end
+ ok, msg = _valid_nss(nss)
+ if not ok then
+ return nil, "invalid namespace specific string (" .. msg .. ")"
+ end
+
+ return nid:lower() .. ":" .. nss
+end
+
+-- TODO - this should check that percent-encoded bytes are valid UTF-8
+function M.init (self)
+ if M._SUPER.query(self) then
+ return nil, "URNs may not have query parts"
+ end
+ if M._SUPER.host(self) then
+ return nil, "URNs may not have authority parts"
+ end
+
+ local path, msg = _validate_and_normalize_path(self:path())
+ if not path then return nil, msg end
+ M._SUPER.path(self, path)
+
+ local nid_class
+ = Util.attempt_require("uri.urn." .. self:nid():gsub("%-", "_"))
+ if nid_class then
+ setmetatable(self, nid_class)
+ if self.init ~= M.init then return self:init() end
+ end
+
+ return self
+end
+
+function M.nid (self, new)
+ local _, _, old = self:path():find("^([^:]+)")
+
+ if new then
+ new = new:lower()
+ if new ~= old then
+ local ok, msg = _valid_nid(new)
+ if not ok then
+ error("invalid namespace identifier (" .. msg .. ")")
+ end
+ end
+ Util.do_class_changing_change(self, M, "NID", new, function (uri, new)
+ M._SUPER.path(uri, new .. ":" .. uri:nss())
+ end)
+ end
+
+ return old
+end
+
+function M.nss (self, new)
+ local _, _, old = self:path():find(":(.*)")
+
+ if new and new ~= old then
+ local ok, msg = _valid_nss(new)
+ if not ok then
+ error("invalid namespace specific string (" .. msg .. ")")
+ end
+ M._SUPER.path(self, self:nid() .. ":" .. new)
+ end
+
+ return old
+end
+
+function M.path (self, new)
+ local old = M._SUPER.path(self)
+
+ if new and new ~= old then
+ local path, msg = _validate_and_normalize_path(new)
+ if not path then
+ error("invalid path for URN '" .. new .. "' (" ..msg .. ")")
+ end
+ local _, _, newnid, newnss = path:find("^([^:]+):(.*)")
+ if not newnid then error("bad path for URN, no NID part found") end
+ local ok, msg = _valid_nid(newnid)
+ if not ok then error("invalid namespace identifier (" .. msg .. ")") end
+ if newnid:lower() == self:nid() then
+ self:nss(newnss)
+ else
+ Util.do_class_changing_change(self, M, "path", path,
+ function (uri, new) M._SUPER.path(uri, new) end)
+ end
+ end
+
+ return old
+end
+
+Util.uri_part_not_allowed(M, "userinfo")
+Util.uri_part_not_allowed(M, "host")
+Util.uri_part_not_allowed(M, "port")
+Util.uri_part_not_allowed(M, "query")
+
+return M
+-- vi:ts=4 sw=4 expandtab