diff --git a/src/cmdmain.lua b/src/cmdmain.lua new file mode 100644 index 0000000..b394e66 --- /dev/null +++ b/src/cmdmain.lua @@ -0,0 +1,50 @@ +--- This file wraps handle_request(env) in main.lua for command-line or CGI usage. +-- It emulates the env table usually constructed by uhttpd-mod-lua. +local main = require('main') + +--- Create an environment table mimicking the table uhttpd-mod-lua passes into handle_request(). +-- The table is created using shell environment variables leaving out only 'DOCUMENT_ROOT', +-- 'SCRIPT_PATH' and the regular shell variables (e.g. IFS, HOME and PS1). +-- Fields present in the 'real' env table but not in this one are: 'HTTP_VERSION' +-- and another table 'headers' which is mostly mirrored by the 'HTTP_*' fields. +-- Note that the 'headers' table may contain extra fields (e.g. 'cache-control'). +-- @treturn table An environment table created from shell environment variables. +local function createEnvTableFromShellEnvironment() + local environ = {} + + environ['CONTENT_LENGTH'] = os.getenv('CONTENT_LENGTH') or '' + environ['CONTENT_TYPE'] = os.getenv('CONTENT_TYPE') or '' + environ['GATEWAY_INTERFACE'] = os.getenv('GATEWAY_INTERFACE') or '' + environ['HTTP_ACCEPT'] = os.getenv('HTTP_ACCEPT') or '' + environ['HTTP_ACCEPT_CHARSET'] = os.getenv('HTTP_ACCEPT_CHARSET') or '' + environ['HTTP_ACCEPT_ENCODING'] = os.getenv('HTTP_ACCEPT_ENCODING') or '' + environ['HTTP_ACCEPT_LANGUAGE'] = os.getenv('HTTP_ACCEPT_LANGUAGE') or '' + environ['HTTP_AUTHORIZATION'] = os.getenv('HTTP_AUTHORIZATION') or '' + environ['HTTP_CONNECTION'] = os.getenv('HTTP_CONNECTION') or '' + environ['HTTP_COOKIE'] = os.getenv('HTTP_COOKIE') or '' + environ['HTTP_HOST'] = os.getenv('HTTP_HOST') or '' + environ['HTTP_REFERER'] = os.getenv('HTTP_REFERER') or '' + environ['HTTP_USER_AGENT'] = os.getenv('HTTP_USER_AGENT') or '' + environ['PATH_INFO'] = os.getenv('PATH_INFO') or '' + environ['QUERY_STRING'] = os.getenv('QUERY_STRING') or '' + environ['REDIRECT_STATUS'] = os.getenv('REDIRECT_STATUS') or '' + environ['REMOTE_ADDR'] = os.getenv('REMOTE_ADDR') or '' + environ['REMOTE_HOST'] = os.getenv('REMOTE_HOST') or '' + environ['REMOTE_PORT'] = os.getenv('REMOTE_PORT') or '' + environ['REQUEST_METHOD'] = os.getenv('REQUEST_METHOD') or '' + environ['REQUEST_URI'] = os.getenv('REQUEST_URI') or '' + environ['SCRIPT_FILENAME'] = os.getenv('SCRIPT_FILENAME') or '' + environ['SCRIPT_NAME'] = os.getenv('SCRIPT_NAME') or '' + environ['SERVER_ADDR'] = os.getenv('SERVER_ADDR') or '' + environ['SERVER_NAME'] = os.getenv('SERVER_NAME') or '' + environ['SERVER_PORT'] = os.getenv('SERVER_PORT') or '' + environ['SERVER_PROTOCOL'] = os.getenv('SERVER_PROTOCOL') or '' + environ['SERVER_SOFTWARE'] = os.getenv('SERVER_SOFTWARE') or '' + + return environ +end + + +--- Entry point for cgi-bin wrapper script. --- +local rv = handle_request(createEnvTableFromShellEnvironment()) +os.exit(rv) diff --git a/src/main.lua b/src/main.lua index 8c4abce..985ad34 100644 --- a/src/main.lua +++ b/src/main.lua @@ -74,7 +74,7 @@ local function setupAutoWifiMode() return nil, "autowifi: uh oh - bad situation in autowifi function" end -local function init() +local function init(environment) log:init(log.LEVEL.debug) log:setStream(io.stderr) @@ -88,8 +88,8 @@ local function init() log:info("Wifibox CGI handler started" .. dbgText) - if (os.getenv('REQUEST_METHOD') == 'POST') then - local n = tonumber(os.getenv('CONTENT_LENGTH')) + if (environment['REQUEST_METHOD'] == 'POST') then + local n = tonumber(environment['CONTENT_LENGTH']) postData = io.read(n) end @@ -103,8 +103,8 @@ local function init() return true end - local function main() - local rq = RequestClass.new(postData, confDefaults.DEBUG_API) + local function main(environment) + local rq = RequestClass.new(environment, postData, confDefaults.DEBUG_API) -- log:info("received request of type " .. rq:getRequestMethod() .. " for " .. (rq:getRequestedApiModule() or "") -- .. "/" .. (rq:getRealApiFunctionName() or "") .. " with arguments: " .. util.dump(rq:getAll())) @@ -134,19 +134,27 @@ end end end ----'entry point'--- -local s, msg = init() -if s == false then - local resp = ResponseClass.new() - local errSuffix = msg and " (" .. msg .. ")" or "" + +--- Main firmware entry point. +-- This is either used by uhttp-mod-lua directly, or by the d3dapi cgi-bin wrapper +-- script which builds the env table from the shell environment. The wrapper script +-- also handles command-line invocation. +-- @tparam table The CGI environment table. +-- @treturn number A Z+ return value suitable to return from wrapper script. Note that this value is ignored by uhttpd-mod-lua. +function handle_request(env) + local s, msg = init(env) - resp:setError("initialization failed" .. errSuffix) - io.write ("Content-type: text/plain\r\n\r\n") - resp:send() - log:error("initialization failed" .. errSuffix) --NOTE: this assumes the logger has been inited properly, despite init() having failed - - os.exit(1) -else - main() - os.exit(0) + if s == false then + local resp = ResponseClass.new() + local errSuffix = msg and " (" .. msg .. ")" or "" + + resp:setError("initialization failed" .. errSuffix) + resp:send() + log:error("initialization failed" .. errSuffix) --NOTE: this assumes the logger has been initialized properly, despite init() having failed + + return 1 + else + main(env) + return 0 + end end diff --git a/src/rest/request.lua b/src/rest/request.lua index 8f477b7..d569284 100644 --- a/src/rest/request.lua +++ b/src/rest/request.lua @@ -156,23 +156,23 @@ setmetatable(M, { --This function initializes itself using various environment variables, the arg array and the given postData --NOTE: if debugging is enabled, commandline arguments 'm' and 'f' override requested module and function -function M.new(postData, debugEnabled) +function M.new(environment, postData, debugEnabled) local self = setmetatable({}, M) --NOTE: is it correct to assume that absence of REQUEST_METHOD indicates command line invocation? - self.requestMethod = os.getenv('REQUEST_METHOD') - if self.requestMethod ~= nil then - self.remoteHost = os.getenv('REMOTE_HOST') - self.remotePort = os.getenv('REMOTE_PORT') - self.userAgent = os.getenv('HTTP_USER_AGENT') + self.requestMethod = environment['REQUEST_METHOD'] + if type(self.requestMethod) == 'string' and self.requestMethod:len() > 0 then + self.remoteHost = environment['REMOTE_HOST'] + self.remotePort = environment['REMOTE_PORT'] + self.userAgent = environment['HTTP_USER_AGENT'] else self.requestMethod = 'CMDLINE' end self.cmdLineArgs = kvTableFromArray(arg) - self.getArgs = kvTableFromUrlEncodedString(os.getenv('QUERY_STRING')) + self.getArgs = kvTableFromUrlEncodedString(environment['QUERY_STRING']) self.postArgs = kvTableFromUrlEncodedString(postData) - self.pathArgs = arrayFromPath(os.getenv('PATH_INFO')) + self.pathArgs = arrayFromPath(environment['PATH_INFO']) -- override path arguments with command line parameter and allow to emulate GET/POST if debugging is enabled *and* if the autowifi special command wasn't mentioned if debugEnabled and self.requestMethod == 'CMDLINE' and self:get('autowifi') == nil then diff --git a/src/script/d3dapi b/src/script/d3dapi index 870e627..d9b6856 100755 --- a/src/script/d3dapi +++ b/src/script/d3dapi @@ -6,9 +6,9 @@ SCRIPT_PATH=/usr/share/lua/wifibox LOG_FILE=/tmp/wifibox.log cd $SCRIPT_PATH -$LUA ./main.lua $@ 2>> $LOG_FILE +$LUA ./cmdmain.lua $@ 2>> $LOG_FILE -exit +exit $? # Code below is for debugging incoming CGI data read -n $CONTENT_LENGTH POSTDATA