-- General information about OpenResty installation -- Copyright (C) 2013 Bertrand Mansion (golgote), Mamasam -- License MIT local M = { _VERSION = '0.1' } local function htmlspecialchars(str) local html = { ["<"] = "<", [">"] = ">", ["&"] = "&", } return string.gsub(tostring(str), "[<>&]", function(char) return html[char] or char end) end local function dump2html(value, field) local html local function isemptytable(t) return next(t) == nil end local function basicSerialize(o) local so = tostring(o) if not o then return "nil" elseif type(o) == "function" then local info = debug.getinfo(o, "S") -- info.name is nil because o is not a calling level if info.what == "C" then return "C function" else -- the information is defined through lines return string.format("%s", so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source) end elseif type(o) == "number" then return so elseif type(o) == "boolean" then return so else return htmlspecialchars(so) end end local function addtohtml(value, field, saved) local value = value saved = saved or {} html[#html+1] = '' .. field .. '' if type(value) ~= "table" then html[#html+1] = '' .. basicSerialize(value) .. '' else if saved[value] then html[#html+1] = '' .. saved[value] .. ' (self reference)' .. '' else saved[value] = field if isemptytable(value) then html[#html+1] = '{ }' else html[#html+1] = '' html[#html+1] = '' for k, v in pairs(value) do k = basicSerialize(k) addtohtml(v, k, saved) end html[#html+1] = '
' html[#html+1] = '' end html[#html+1] = '' end end end if type(value) ~= "table" then return '' .. field .. '' .. basicSerialize(value) .. '' end html = {} addtohtml(value, field) return table.concat(html, "\n") end local function package_info() local ngx = ngx local modules = {} local packages = {} for id, content in pairs(package.loaded) do packages[id] = content end packages["ngx"] = ngx for id, content in pairs(packages) do if id ~= 'package' and id ~= 'preload' and id ~= '_G' and type(content) == 'table' then modules[id] = {} local functions = {} local meta = {} for its_id, its_c in pairs(content) do if type(its_c) == 'string' or type(its_c) == 'number' then meta[its_id] = tostring(its_c) elseif type(its_c) == 'function' then functions[#functions+1] = its_id end end modules[id]["meta"] = meta table.sort(functions) modules[id]["functions"] = functions end end local html = {} -- sorted list of modules local sorted = {} for n in pairs(modules) do table.insert(sorted, n) end table.sort(sorted) for _,id in ipairs(sorted) do local values = modules[id] html[#html+1] = '' if values["meta"] then -- sort properties local meta = values['meta'] sorted = {} for n in pairs(meta) do table.insert(sorted, n) end table.sort(sorted) for i,n in ipairs(sorted) do html[#html+1] = '' end end -- functions if values["functions"] and #values["functions"] > 0 then html[#html+1] = '' end html[#html+1] = '
'.. id ..'
' .. n .. '' .. meta[n] .. '
' .. table.concat(values["functions"], ' ') .. '
' end return table.concat(html, "\n") end local function server_configuration() local ngx = ngx local html = {''} html[#html+1] = '' html[#html+1] = '' html[#html+1] = '' local paths -- package.path paths = {} for token in string.gmatch(package.path, "[^;]+") do paths[#paths+1] = htmlspecialchars(token) end html[#html+1] = '' -- package.cpath paths = {} for token in string.gmatch(package.cpath, "[^;]+") do paths[#paths+1] = htmlspecialchars(token) end html[#html+1] = '' html[#html+1] = '
DirectiveValue
Nginx version' .. htmlspecialchars(tostring(ngx.config.nginx_version)) .. '
Nginx Lua version' .. htmlspecialchars(tostring(ngx.config.ngx_lua_version)) .. '
Lua version' .. htmlspecialchars(tostring(_VERSION)) .. '
package.path' .. table.concat(paths, "
") .. '
package.cpath' .. table.concat(paths, "
") .. '
' return table.concat(html, "\n") end local function server_info() local ngx = ngx -- from http://wiki.nginx.org/NginxHttpCoreModule#.24arg_PARAMETER local vars = { "args", "body_bytes_sent", "content_length", "content_type", "cookie_test", -- cookie_COOKIE "document_root", "document_uri", "headers_in", "headers_out", "host", "hostname", "http_user_agent", -- http_HEADER "http_referer", -- http_HEADER "is_args", "limit_rate", "nginx_version", "query_string", "remote_addr", "remote_port", "remote_user", "request_filename", "request_body", "request_body_file", "request_completion", "request_method", "request_uri", "scheme", "server_addr", "server_name", "server_port", "server_protocol", "uri", } local html = {''} for i,v in ipairs(vars) do if ngx.var[v] then html[#html+1] = '' end end html[#html+1] = '' html[#html+1] = '' html[#html+1] = '' html[#html+1] = dump2html(ngx.ctx, 'ngx.ctx') html[#html+1] = '
VariableValue
ngx.var.' .. v .. '' .. htmlspecialchars(tostring(ngx.var[v])) .. '
ngx.header_sent' .. htmlspecialchars(tostring(ngx.header_sent)) .. '
ngx.status' .. htmlspecialchars(tostring(ngx.status)) .. '
ngx.is_subrequest' .. htmlspecialchars(tostring(ngx.is_subrequest)) .. '
' return table.concat(html, "\n") end local function server_functions() local html = {} local result = {} local ngx = ngx result['ngx.req.get_headers()'] = ngx.req.get_headers() result['ngx.req.get_uri_args()'] = ngx.req.get_uri_args() result['ngx.today()'] = ngx.today() result['ngx.time()'] = ngx.time() result['ngx.now()'] = ngx.now() result['ngx.localtime()'] = ngx.localtime() result['ngx.utctime()'] = ngx.utctime() result['ngx.get_phase()'] = ngx.get_phase() local html = {''} for id, content in pairs(result) do html[#html+1] = dump2html(content, id) end html[#html+1] = '
FunctionResult
' return table.concat(html, "\n") end M.info = function() local template = [[Lua resty info

Nginx OpenResty version %s

Server configuration

%s

Modules

%s

Server variables

%s

Resty functions

%s ]] local html = string.format(template, ngx.var.nginx_version, server_configuration(), package_info(), server_info(), server_functions()) ngx.header.content_type = 'text/html' ngx.print(html) end local mt = {} mt.__call = function(...) return M.info(...) end setmetatable(M, mt) return M