----------------------------------------------------------------------------- -- Xavante WSAPI handler -- -- Author: Fabio Mascarenhas -- Copyright (c) 2007 Kepler Project -- ----------------------------------------------------------------------------- local coxpcall = require "coxpcall" pcall = coxpcall.pcall xpcall = coxpcall.xpcall local common = require"wsapi.common" local _M = {} ------------------------------------------------------------------------------- -- Implements WSAPI ------------------------------------------------------------------------------- local function set_cgivars (req, diskpath, path_info_pat, script_name_pat, extra_vars) diskpath = diskpath or req.diskpath or "" req.cgivars = { SERVER_SOFTWARE = req.serversoftware, SERVER_NAME = req.parsed_url.host, GATEWAY_INTERFACE = "CGI/1.1", SERVER_PROTOCOL = "HTTP/1.1", SERVER_PORT = req.parsed_url.port, REQUEST_METHOD = req.cmd_mth, DOCUMENT_ROOT = diskpath, PATH_INFO = string.match(req.parsed_url.path, path_info_pat) or "", PATH_TRANSLATED = script_name_pat and (diskpath .. script_name_pat), SCRIPT_NAME = script_name_pat, QUERY_STRING = req.parsed_url.query or "", REMOTE_ADDR = string.gsub (req.rawskt:getpeername (), ":%d*$", ""), CONTENT_TYPE = req.headers ["content-type"], CONTENT_LENGTH = req.headers ["content-length"], } if req.cgivars.PATH_INFO == "" then req.cgivars.PATH_INFO = "/" end for n,v in pairs(extra_vars or {}) do req.cgivars[n] = v end for n,v in pairs (req.headers) do req.cgivars ["HTTP_"..string.gsub (string.upper (n), "-", "_")] = v end end local function wsapihandler (req, res, wsapi_run, app_prefix, docroot, app_path, extra_vars) local path_info_pat = "^" .. (app_prefix or "") .. "(.*)" set_cgivars(req, docroot, path_info_pat, app_prefix, extra_vars) local get_cgi_var = function (var) return req.cgivars[var] or "" end local wsapi_env = common.wsapi_env { input = req.socket, read_method = "receive", error = io.stderr, env = get_cgi_var } wsapi_env.APP_PATH = app_path local function set_status(status) if type(status) == "string" and status:match("^%d+$") then status = tonumber(status) end if type(status) == "number" then status = ("%d %s"):format(status, common.status_codes[status]) end res.statusline = "HTTP/1.1 " .. (status or "500 Internal Server Error") end local function send_headers(headers) for h, v in pairs(headers) do if h == "Status" or h == "Content-Type" then res.headers[h] = v elseif type(v) == "string" then res:add_header(h, v) elseif type(v) == "table" then for _, v in ipairs(v) do res:add_header(h, tostring(v)) end else res:add_header(h, tostring(v)) end end res:send_headers() end local ok, status, headers, res_iter = common.run_app(wsapi_run, wsapi_env) if ok then set_status(status or 500) send_headers(headers or {}) common.send_content(res, res_iter, "send_data") else if wsapi_env.STATUS == 404 then res.statusline = "HTTP/1.1 404" send_headers({ ["Content-Type"] = "text/html", ["Content-Length"] = (status and #status) or 0 }) res:send_data(status) else local content = common.error_html(status) res.statusline = "HTTP/1.1 500" send_headers({ ["Content-Type"] = "text/html", ["Content-Length"] = #content}) res:send_data(content) end end end -- Makes a WSAPI handler for a single WSAPI application function _M.makeHandler (app_func, app_prefix, docroot, app_path, extra_vars) return function (req, res) return wsapihandler(req, res, app_func, app_prefix, docroot, app_path, extra_vars) end end -- Makes a generic WSAPI handler, that launches WSAPI application scripts -- See the wsapi script for the possible values of the "params" table function _M.makeGenericHandler(docroot, params, extra_vars) params = params or { isolated = true } return function (req, res) return wsapihandler(req, res, common.make_loader(params), nil, docroot, nil, extra_vars) end end return _M