Last active
December 25, 2015 06:59
-
-
Save rafis/6936230 to your computer and use it in GitHub Desktop.
This is unrolled version of wsapi.fcgi, so the only dependency is `lfcgi`. Beware! Unlike WSAPI in this implementation call to app.run assumes that it returns a string as third parameter, not an iterator. I have renamed it to `body` from `res_iter`. Also there is MobDebug (something like analog of Zend XDebug) being included and logging to `wsap…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env luajit | |
local jit = rawget(_G or _ENV, "jit") | |
--#if ENV ~= "PRODUCTION" then | |
jit.off(true, true) | |
--#end | |
if jit.arch == "x64" then | |
package.cpath = package.cpath .. ";/usr/lib/x86_64-linux-gnu/lua/5.1/?.so" | |
elseif jit.arch == "x86" then | |
package.cpath = package.cpath .. ";/usr/lib/i386-linux-gnu/lua/5.1/?.so" | |
end | |
-- Here is unrolled version of wsapi.fcgi launcher | |
local lfcgi = require("lfcgi") | |
local os = require("os") | |
local io = require("io") | |
local ipairs, pairs, type, assert = ipairs, pairs, type, assert | |
--#if ENV ~= "PRODUCTION" then | |
local collect_all_garbage = require("lua-nucleo/misc").collect_all_garbage | |
--#end | |
io.stdout = lfcgi.stdout | |
io.stderr = lfcgi.stderr | |
io.stdin = lfcgi.stdin | |
local app = require("index") | |
local mobdebug | |
if app.MOB_DEBUG then | |
mobdebug = require("mobdebug") | |
end | |
local fcgi_loop = function(app, wsapi_log) | |
-- HTTP status codes | |
local status_codes = { | |
[100] = "Continue", | |
[101] = "Switching Protocols", | |
[200] = "OK", | |
[201] = "Created", | |
[202] = "Accepted", | |
[203] = "Non-Authoritative Information", | |
[204] = "No Content", | |
[205] = "Reset Content", | |
[206] = "Partial Content", | |
[300] = "Multiple Choices", | |
[301] = "Moved Permanently", | |
[302] = "Found", | |
[303] = "See Other", | |
[304] = "Not Modified", | |
[305] = "Use Proxy", | |
[307] = "Temporary Redirect", | |
[400] = "Bad Request", | |
[401] = "Unauthorized", | |
[402] = "Payment Required", | |
[403] = "Forbidden", | |
[404] = "Not Found", | |
[405] = "Method Not Allowed", | |
[406] = "Not Acceptable", | |
[407] = "Proxy Authentication Required", | |
[408] = "Request Time-out", | |
[409] = "Conflict", | |
[410] = "Gone", | |
[411] = "Length Required", | |
[412] = "Precondition Failed", | |
[413] = "Request Entity Too Large", | |
[414] = "Request-URI Too Large", | |
[415] = "Unsupported Media Type", | |
[416] = "Requested range not satisfiable", | |
[417] = "Expectation Failed", | |
[500] = "Internal Server Error", | |
[501] = "Not Implemented", | |
[502] = "Bad Gateway", | |
[503] = "Service Unavailable", | |
[504] = "Gateway Time-out", | |
[505] = "HTTP Version not supported", | |
} | |
-- Makes an index metamethod for the environment, from | |
-- a function that returns the value of a server variable | |
-- a metamethod lets us do "on-demand" loading of the WSAPI | |
-- environment, and provides the invariant the the WSAPI | |
-- environment returns the empty string instead of nil for | |
-- variables that do not exist | |
local mt_wsapi_env = { | |
__index = function(self, n) | |
local v = lfcgi.getenv(n) or os.getenv(n) | |
self[n] = v or "" | |
return v or "" | |
end; | |
} | |
-- Runs an WSAPI application for each FastCGI request that comes | |
-- from the FastCGI pipeline, until USR1 signal or other error happened | |
while lfcgi.accept() >= 0 do | |
--#if ENV ~= "PRODUCTION" then | |
collect_all_garbage() | |
--#end | |
local time_request_start = os.clock() | |
local memory_request_start = collectgarbage("count") | |
-- Builds an WSAPI environment from the configuration table "t" | |
local wsapi_env = { } | |
setmetatable(wsapi_env, mt_wsapi_env) | |
wsapi_env.input = { } | |
wsapi_env.input.read = function(self, n) | |
n = n or self.length or 0 | |
if n > 0 then | |
return lfcgi.stdin:read(n) | |
end | |
end | |
wsapi_env.input.length = tonumber(wsapi_env.CONTENT_LENGTH) or 0 | |
wsapi_env.error = lfcgi.stderr | |
if wsapi_env.PATH_INFO == "" then wsapi_env.PATH_INFO = "/" end | |
local os_exit | |
if app.MOB_DEBUG and (app.MOB_DEBUG_ONLY_REMOTE_ADDR == nil or wsapi_env.REMOTE_ADDR == app.MOB_DEBUG_ONLY_REMOTE_ADDR) then | |
os_exit = os.exit | |
os.exit = mobdebug.done | |
mobdebug.coro() | |
mobdebug.start(wsapi_env.REMOTE_ADDR) | |
end | |
-- Runs an application with data from the configuration table "t", | |
-- sending the WSAPI error/not found responses in case of errors | |
local ok, status, headers, body = pcall(app.run, wsapi_env, wsapi_log) | |
if not ok then | |
-- In case of error the variable "status" contains error message | |
body = status | |
status = 500 | |
headers = { | |
["Content-Type"] = "text/html; charset=utf-8", | |
["Content-Length"] = #body, | |
} | |
end | |
assert(type(body) == "string") | |
-- Sends the complete response through the "out" pipe, | |
-- using the provided write method | |
assert(type(status) == "number" and status_codes[status] ~= nil) | |
lfcgi.stdout:write("Status: " .. status .. " " .. status_codes[status] .. "\r\n") | |
for h, v in pairs(headers or { }) do | |
if type(v) ~= "table" then | |
lfcgi.stdout:write(h .. ": " .. tostring(v) .. "\r\n") | |
else | |
for _, v in ipairs(v) do | |
lfcgi.stdout:write(h .. ": " .. tostring(v) .. "\r\n") | |
end | |
end | |
end | |
lfcgi.stdout:write("\r\n") | |
lfcgi.stdout:write(body) | |
if lfcgi.stdout.flush then | |
lfcgi.stdout:flush() | |
end | |
if app.MOB_DEBUG and (app.MOB_DEBUG_ONLY_REMOTE_ADDR == nil or wsapi_env.REMOTE_ADDR == app.MOB_DEBUG_ONLY_REMOTE_ADDR) then | |
mobdebug.done() | |
os.exit = os_exit | |
end | |
--#if ENV ~= "PRODUCTION" then | |
collect_all_garbage() | |
--#end | |
wsapi_log:write( | |
wsapi_env["REMOTE_ADDR"], " - ", | |
wsapi_env["REMOTE_USER"] == "" and "-" or wsapi_env["REMOTE_USER"], " ", | |
os.date("[%d/%b/%Y:%H:%M:%S +0000]"), " ", | |
string.format('"%s %s %s"', wsapi_env["REQUEST_METHOD"], wsapi_env["REQUEST_URI"], wsapi_env["SERVER_PROTOCOL"]), " ", | |
tostring(status), " ", | |
string.format('"%s"', headers["Content-Type"]), " ", | |
tostring(headers["Content-Length"]), " ", | |
string.format('"%s"', wsapi_env["HTTP_REFERER"] == "" and "-" or wsapi_env["HTTP_REFERER"]), " ", | |
string.format('"%s"', wsapi_env["HTTP_USER_AGENT"]), " ", | |
--#if ENV ~= "PRODUCTION" then | |
string.format("%.2fs", os.clock() - time_request_start), " ", | |
string.format("%.2fKb", collectgarbage("count") - memory_request_start), | |
--#end | |
"\n" | |
) | |
wsapi_log:flush() | |
end | |
end | |
local wsapi_log = io.open("../log/wsapi.log", "a") | |
local ok, err = xpcall( | |
function() | |
fcgi_loop(app, wsapi_log) | |
end, | |
function(err) | |
return debug.traceback(err, 2) | |
end | |
) | |
if not ok then | |
wsapi_log:write("ERROR:\n", err, "\n") | |
else | |
wsapi_log:write("NOTE: Exited FastCGI loop nicely\n") | |
end | |
wsapi_log:close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment