1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
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
|