[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Xavante/Cgilua: custom handler - please critique
- From: William Trenker <wtrenker@...>
- Date: Tue, 9 Aug 2005 14:01:05 -0400
I've been trying to use cgilua as a template processor from within a
custom, application-specific Xavante handler. I see a couple of key
cgilua features as beneficial, reuasable components. One is the
cgilua code that parses and provides the "unified" access to GET and
POST cgi data. The other feature is the handling of .lua and .lp
scripts.
I've attached the complete code for a simple, working Xavante handler
at the end of this message and would appreciate a critical review.
There are a couple of "tricks" (aka kludges) that I've employed to get
this to work. One of them is to make the cgilua.getparams global and
thus expose it as a very useful component of the Cgilua API. The
second trick is to force cgilua to be reloaded each pass through the
Xavante handler. I found I had to do this in order to get
cgilua.servervariable (and possibly other module-level variables) to
be redefined in terms of the current instantiation of the SAPI table.
The final trick is that I had to define the SAPI and cgi tables as
_G.SAPI and _G.cgi. Without doing this the SAPI and cgi tables would
not "make it" into the environment of the relevant cgilua code and the
templates.
With the above "tricks", the Xavante handler shown below works like a
charm. But I'm concerned that these tricks may also trigger
undesirable side effects. I am particularly concerned that by using
_G.SAPI and _G.cgi I may be breaking the thread-safety (or
coroutine-safety) of copas. Are the _G.SAPI and _G.cgi tables going
to be undesireably shared among copas connection instances and hence
corrupt the purity of the per-connection data?
Thanks for any insight you can share.
Bill
---------------- simpleCgiHandler.lua ------------------------
module"simpleCgiHandler"
-- borrowed from xavante/cgiluahandler.lua
local function set_api (req, res)
local SAPI = {
Response = {},
Request = {},
}
-- Headers
SAPI.Response.contenttype = function (s)
res.headers ["Content-Type"] = s
end
SAPI.Response.redirect = function (s)
res.headers ["Location"] = s
res.statusline = "HTTP/1.1 301 Moved Permanently\r\n"
res.content = " " --one blank to force output
end
SAPI.Response.header = function (h, v)
res.headers [h] = v
end
-- Contents
SAPI.Response.write = function (s)
httpd.send_res_data (res, s)
end
SAPI.Response.errorlog = function (s) io.stderr:write (s) end
-- Input POST data
SAPI.Request.getpostdata = function (n)
return req.socket:receive (n)
end
-- Input general information
SAPI.Request.servervariable = function (n)
return req.cgivars[n]
end
return SAPI
end
-- borrowed
local function set_cgivars (req, diskpath)
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,
PATH_INFO = "",
PATH_TRANSLATED = diskpath .. req.parsed_url.path,
SCRIPT_NAME = req.parsed_url.path,
QUERY_STRING = req.parsed_url.query,
REMOTE_HOST = req.headers["host"],
REMOTE_ADDR = string.gsub (req.rawskt:getpeername (), ":%d*$", ""),
AUTH_TYPE = nil,
REMOTE_USER = nil,
CONTENT_TYPE = req.headers ["content-type"],
CONTENT_LENGTH = req.headers ["content-length"],
}
for n,v in pairs (req.headers) do
req.cgivars ["HTTP_"..string.gsub (string.upper (n), "-", "_")] = v
end
end
local function setupCgilua(req, res)
-- must define SAPI before require"cgilua"
-- CAUTION: Thread-safety ??????
_G.SAPI = set_api(req, res)
-- force a reload of cgilua to catch changes
-- to such module-level variables as cgilua.servervariable
package.loaded.cgilua = nil
require"cgilua"
cgilua.addscripthandler ("lua", cgilua.doscript)
cgilua.addscripthandler ("lp", cgilua.handlelp)
set_cgivars(req, "")
-- CAUTION: Thread-safety ??????
_G.cgi = {}
-- changed cgilua.getparams to global function
cgilua.getparams(_G.cgi)
end
local function doCgiScript(scriptname, params)
--add programmatically defined cgi params
if params then
table.foreach(params, function(n,v) _G.cgi[n] = v end)
end
cgilua.handle(scriptname)
end
-- a container to hold values between invocations
-- (should I be using the Stable package for this?)
-- (Need to look into Sessions)
globals = {mytext=""}
local function simpleCgiHandler(req, res)
script = cgilua.servervariable("SCRIPT_NAME")
if script == "/form.lp" then
cgiparams = { x = os.date(), mytext = tostring(globals.mytext) }
doCgiScript("form.lp", cgiparams)
elseif script == "/dummy" then
globals.mytext = _G.cgi.mytext
doCgiScript("form.lua")
else
res.content = "servervariable(\"SCRIPT_NAME\") = "..script.."<br />"
return res
end
end
function makeHandler()
return function(req, res)
setupCgilua(req, res)
return simpleCgiHandler(req, res)
end
end
--------------------- end -----------------------------------
---------------- xavante/config.lua -----------------
<snip>
require "simpleCgiHandler"
local simplerules = {
{match= { "/", "/*" }, with = simpleCgiHandler.makeHandler() },
}
<snip>
--------------------- end -----------------------------------
------------------------- form.lp ---------------------
<html><body>
<form method="post" action="dummy">
httpd server variable: REMOTE_ADDR = <%= cgilua.servervariable
("REMOTE_ADDR") %><br />
programmatic cgi parameter: x = <%= cgi.x %><br />
Enter your name: <input type="text" name="mytext" value="<%=
cgi.mytext %>"><br />
<input type="submit" value="Go">
</form>
</body></html>
--------------------- end -----------------------------------
----------------------- form.lua ------------------------
cgilua.put("You entered: "..tostring(cgi.mytext).."<br />")
cgilua.put("<a href=\"form.lp?\">Try Again</a><br />")
--------------------- end -----------------------------------