diff options
Diffstat (limited to 'script/3rd/lua-uri/uri/urn.lua')
-rw-r--r-- | script/3rd/lua-uri/uri/urn.lua | 131 |
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 |