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.
134 lines
3.9 KiB
134 lines
3.9 KiB
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 .. ")", 2)
|
|
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 .. ")", 2)
|
|
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 .. ")", 2)
|
|
end
|
|
local _, _, newnid, newnss = path:find("^([^:]+):(.*)")
|
|
if not newnid then error("bad path for URN, no NID part found", 2) end
|
|
local ok, msg = _valid_nid(newnid)
|
|
if not ok then
|
|
error("invalid namespace identifier (" .. msg .. ")", 2)
|
|
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
|