Add web.uri.encode[_component]

This commit is contained in:
Lars Mueller 2022-01-19 17:24:29 +01:00
parent 4a9fa41827
commit e346128d4d
4 changed files with 80 additions and 30 deletions

@ -367,8 +367,10 @@ do
local text = "<tag> & '\""
local escaped = web.html.escape(text)
assert(web.html.unescape(escaped) == text)
assert(web.html.unescape("&#42;") == _G.string.char(42))
assert(web.html.unescape("&#x42;") == _G.string.char(0x42))
assert(web.html.unescape"&#42;" == _G.string.char(42))
assert(web.html.unescape"&#x42;" == _G.string.char(0x42))
assert(web.uri.encode"https://example.com/foo bar" == "https://example.com/foo%20bar")
assert(web.uri.encode_component"foo/bar baz" == "foo%2Fbar%20baz")
end
if not _G.minetest then return end

33
web.lua

@ -1,28 +1,7 @@
-- TODO incorporate https://github.com/minetest/minetest/pull/11578
return {
html = setmetatable({
escape = function(text)
return text:gsub(".", {
["<"] = "&lt;",
[">"] = "&gt;",
["&"] = "&amp;",
["'"] = "&apos;",
['"'] = "&quot;",
})
return setmetatable({}, {__index = function(self, module_name)
if module_name == "uri" or module_name == "html" then
local module = assert(loadfile(modlib.mod.get_resource(modlib.modname, "web", module_name .. ".lua")))()
self[module_name] = module
return module
end
}, {__index = function(self, key)
if key == "unescape" then
local func = assert(loadfile(modlib.mod.get_resource("modlib", "web", "html", "entities.lua")))
setfenv(func, {})
local named_entities = assert(func())
local function unescape(text)
return text
:gsub("&([A-Za-z]+);", named_entities) -- named
:gsub("&#(%d+);", function(digits) return modlib.text.utf8(tonumber(digits)) end) -- decimal
:gsub("&#x(%x+);", function(digits) return modlib.text.utf8(tonumber(digits, 16)) end) -- hex
end
self.unescape = unescape
return unescape
end
end})
}
end})

27
web/html.lua Normal file

@ -0,0 +1,27 @@
local html = setmetatable({}, {__index = function(self, key)
if key == "unescape" then
local func = assert(loadfile(modlib.mod.get_resource("modlib", "web", "html", "entities.lua")))
setfenv(func, {})
local named_entities = assert(func())
local function unescape(text)
return text
:gsub("&([A-Za-z]+);", named_entities) -- named
:gsub("&#(%d+);", function(digits) return modlib.text.utf8(tonumber(digits)) end) -- decimal
:gsub("&#x(%x+);", function(digits) return modlib.text.utf8(tonumber(digits, 16)) end) -- hex
end
self.unescape = unescape
return unescape
end
end})
function html.escape(text)
return text:gsub(".", {
["<"] = "&lt;",
[">"] = "&gt;",
["&"] = "&amp;",
["'"] = "&apos;",
['"'] = "&quot;",
})
end
return html

42
web/uri.lua Normal file

@ -0,0 +1,42 @@
-- URI escaping utilities
-- See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
local uri_unescaped_chars = {}
for char in ("-_.!~*'()"):gmatch(".") do
uri_unescaped_chars[char] = true
end
local function add_unescaped_range(from, to)
for byte = from:byte(), to:byte() do
uri_unescaped_chars[string.char(byte)] = true
end
end
add_unescaped_range("0", "9")
add_unescaped_range("a", "z")
add_unescaped_range("A", "Z")
local uri_allowed_chars = table.copy(uri_unescaped_chars)
for char in (";,/?:@&=+$#"):gmatch(".") do
-- Reserved characters are allowed
uri_allowed_chars[char] = true
end
local function encode(text, allowed_chars)
return text:gsub(".", function(char)
if allowed_chars[char] then
return char
end
return ("%%%02X"):format(char:byte())
end)
end
local uri = {}
function uri.encode_component(text)
return encode(text, uri_unescaped_chars)
end
function uri.encode(text)
return encode(text, uri_allowed_chars)
end
return uri