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.
131 lines
3.8 KiB
131 lines
3.8 KiB
local M = { _NAME = "uri._util" }
|
|
|
|
local string_char, string_format = string.char, string.format
|
|
|
|
-- Build a char->hex map
|
|
local escapes = {}
|
|
for i = 0, 255 do
|
|
escapes[string_char(i)] = string_format("%%%02X", i)
|
|
end
|
|
local function _encode_char (chr) return escapes[chr] end
|
|
|
|
function M.uri_encode (text, patn)
|
|
if not text then return end
|
|
if not patn then
|
|
-- Default unsafe characters. RFC 2732 ^(uric - reserved)
|
|
-- TODO - this should be updated to the latest RFC.
|
|
patn = "^A-Za-z0-9%-_.!~*'()"
|
|
end
|
|
return (text:gsub("([" .. patn .. "])", _encode_char))
|
|
end
|
|
|
|
function M.uri_decode (str, patn)
|
|
-- Note from RFC1630: "Sequences which start with a percent sign
|
|
-- but are not followed by two hexadecimal characters are reserved
|
|
-- for future extension"
|
|
if not str then return end
|
|
if patn then patn = "[" .. patn .. "]" end
|
|
return (str:gsub("%%(%x%x)", function (hex)
|
|
local char = string_char(tonumber(hex, 16))
|
|
return (patn and not char:find(patn)) and "%" .. hex or char
|
|
end))
|
|
end
|
|
|
|
-- This is the remove_dot_segments algorithm from RFC 3986 section 5.2.4.
|
|
-- The input buffer is 's', the output buffer 'path'.
|
|
function M.remove_dot_segments (s)
|
|
local path = ""
|
|
|
|
while s ~= "" do
|
|
if s:find("^%.%.?/") then -- A
|
|
s = s:gsub("^%.%.?/", "", 1)
|
|
elseif s:find("^/%./") or s == "/." then -- B
|
|
s = s:gsub("^/%./?", "/", 1)
|
|
elseif s:find("^/%.%./") or s == "/.." then -- C
|
|
s = s:gsub("^/%.%./?", "/", 1)
|
|
if path:find("/") then
|
|
path = path:gsub("/[^/]*$", "", 1)
|
|
else
|
|
path = ""
|
|
end
|
|
elseif s == "." or s == ".." then -- D
|
|
s = ""
|
|
else -- E
|
|
local _, p, seg = s:find("^(/?[^/]*)")
|
|
s = s:sub(p + 1)
|
|
path = path .. seg
|
|
end
|
|
end
|
|
|
|
return path
|
|
end
|
|
|
|
-- TODO - wouldn't this be better as a method on string? s:split(patn)
|
|
function M.split (patn, s, max)
|
|
if s == "" then return {} end
|
|
|
|
local i, j = 1, string.find(s, patn)
|
|
if not j then return { s } end
|
|
|
|
local list = {}
|
|
while true do
|
|
if #list + 1 == max then list[max] = s:sub(i); return list end
|
|
list[#list + 1] = s:sub(i, j - 1)
|
|
i = j + 1
|
|
j = string.find(s, patn, i)
|
|
if not j then
|
|
list[#list + 1] = s:sub(i)
|
|
break
|
|
end
|
|
end
|
|
return list
|
|
end
|
|
|
|
function M.attempt_require (modname)
|
|
local ok, result = pcall(require, modname)
|
|
if ok then
|
|
return result
|
|
elseif type(result) == "string" and
|
|
result:find("module '.*' not found") then
|
|
return nil
|
|
else
|
|
error(result)
|
|
end
|
|
end
|
|
|
|
function M.subclass_of (class, baseclass)
|
|
class.__index = class
|
|
class.__tostring = baseclass.__tostring
|
|
class._SUPER = baseclass
|
|
setmetatable(class, baseclass)
|
|
end
|
|
|
|
function M.do_class_changing_change (uri, baseclass, changedesc, newvalue,
|
|
changefunc)
|
|
local tmpuri = {}
|
|
setmetatable(tmpuri, baseclass)
|
|
for k, v in pairs(uri) do tmpuri[k] = v end
|
|
changefunc(tmpuri, newvalue)
|
|
tmpuri._uri = nil
|
|
|
|
local foo, err = tmpuri:init()
|
|
if not foo then
|
|
error("URI not valid after " .. changedesc .. " changed to '" ..
|
|
newvalue .. "': " .. err, 3)
|
|
end
|
|
|
|
setmetatable(uri, getmetatable(tmpuri))
|
|
for k in pairs(uri) do uri[k] = nil end
|
|
for k, v in pairs(tmpuri) do uri[k] = v end
|
|
end
|
|
|
|
function M.uri_part_not_allowed (class, method)
|
|
class[method] = function (self, new)
|
|
if new then error(method .. " not allowed on this kind of URI") end
|
|
return self["_" .. method]
|
|
end
|
|
end
|
|
|
|
return M
|
|
-- vi:ts=4 sw=4 expandtab
|