local _M = {} ---------------------------------------------------------------------------- -- Decode an URL-encoded string (see RFC 2396) ---------------------------------------------------------------------------- function _M.url_decode(str) if not str then return nil end str = string.gsub (str, "+", " ") str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end) str = string.gsub (str, "\r\n", "\n") return str end ---------------------------------------------------------------------------- -- URL-encode a string (see RFC 2396) ---------------------------------------------------------------------------- function _M.url_encode(str) if not str then return nil end str = string.gsub (str, "\n", "\r\n") str = string.gsub (str, "([^%w ])", function (c) return string.format ("%%%02X", string.byte(c)) end) str = string.gsub (str, " ", "+") return str end ---------------------------------------------------------------------------- -- Sanitizes all HTML tags ---------------------------------------------------------------------------- function _M.sanitize(text) return text:gsub(">", ">"):gsub("<", "<") end ---------------------------------------------------------------------------- -- Checks whether s is not nil or the empty string ---------------------------------------------------------------------------- function _M.not_empty(s) if s and s ~= "" then return s else return nil end end ---------------------------------------------------------------------------- -- Wraps the WSAPI environment to make the input rewindable, so you -- can parse postdata more than once, call wsapi_env.input:rewind() ---------------------------------------------------------------------------- function _M.make_rewindable(wsapi_env) local new_env = { input = { position = 1, contents = "" } } function new_env.input:read(size) local left = #self.contents - self.position + 1 local s if left < size then self.contents = self.contents .. wsapi_env.input:read(size - left) s = self.contents:sub(self.position) self.position = #self.contents + 1 else s = self.contents:sub(self.position, self.position + size) self.position = self.position + size end if s == "" then return nil else return s end end function new_env.input:rewind() self.position = 1 end return setmetatable(new_env, { __index = wsapi_env, __newindex = wsapi_env }) end ---------------------------------------------------------------------------- -- getopt, POSIX style command line argument parser -- param arg contains the command line arguments in a standard table. -- param options is a string with the letters that expect string values. -- returns a table where associated keys are true, nil, or a string value. -- The following example styles are supported -- -a one ==> opts["a"]=="one" -- -bone ==> opts["b"]=="one" -- -c ==> opts["c"]==true -- --c=one ==> opts["c"]=="one" -- -cdaone ==> opts["c"]==true opts["d"]==true opts["a"]=="one" -- note POSIX demands the parser ends at the first non option -- this behavior isn't implemented. ---------------------------------------------------------------------------- function _M.getopt( arg, options ) local tab, args = {}, {} local k = 1 while k <= #arg do local v = arg[k] if string.sub( v, 1, 2) == "--" then local x = string.find( v, "=", 1, true ) if x then tab[ string.sub( v, 3, x-1 ) ] = string.sub( v, x+1 ) else tab[ string.sub( v, 3 ) ] = true end k = k + 1 elseif string.sub( v, 1, 1 ) == "-" then local y = 2 local l = #v local jopt local next = 1 while ( y <= l ) do jopt = string.sub( v, y, y ) if string.find( options, jopt, 1, true ) then if y < l then tab[ jopt ] = string.sub( v, y+1 ) y = l else tab[ jopt ] = arg[ k + 1 ] next = 2 end else tab[ jopt ] = true end y = y + 1 end k = k + next else args[#args + 1] = v k = k + 1 end end return tab, args end ---------------------------------------------------------------------------- -- Makes a mock WSAPI environment with GET method and the provided -- query string ---------------------------------------------------------------------------- function _M.make_env_get(qs) return { REQUEST_METHOD = "GET", QUERY_STRING = qs or "", CONTENT_LENGTH = 0, PATH_INFO = "/", SCRIPT_NAME = "", CONTENT_TYPE = "x-www-form-urlencoded", input = { read = function () return nil end }, error = { messages = {}, write = function (self, msg) self.messages[#self.messages+1] = msg end } } end ---------------------------------------------------------------------------- -- Makes a mock WSAPI environment with POST method and the provided -- postdata, type (x-www-form-urlenconded default) and query string ---------------------------------------------------------------------------- function _M.make_env_post(pd, type, qs) pd = pd or "" return { REQUEST_METHOD = "POST", QUERY_STRING = qs or "", CONTENT_LENGTH = #pd, PATH_INFO = "/", CONTENT_TYPE = type or "x-www-form-urlencoded", SCRIPT_NAME = "", input = { post_data = pd, current = 1, read = function (self, len) if self.current > #self.post_data then return nil end local s = self.post_data:sub(self.current, len) self.current = self.current + len return s end }, error = { messages = {}, write = function (self, msg) self.messages[#self.messages+1] = msg end } } end function _M.loadfile(filename, env) if _VERSION == "Lua 5.2" then return loadfile(filename, "bt", env) else local f, err = loadfile(filename) if not f then return nil, err end setfenv(f, env) return f end end return _M