From a49e255b9044c7abba35ac0a28861e40a73e0a72 Mon Sep 17 00:00:00 2001 From: Wouter R Date: Wed, 23 Mar 2016 16:37:47 +0100 Subject: [PATCH] Include HTTP request headers in info/logfiles endpoint. --- src/rest/api/api_info.lua | 19 ++++++++++++++++++- src/rest/request.lua | 2 ++ src/util/utils.lua | 29 ++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/rest/api/api_info.lua b/src/rest/api/api_info.lua index 4e00994..fcdd33a 100644 --- a/src/rest/api/api_info.lua +++ b/src/rest/api/api_info.lua @@ -16,6 +16,7 @@ local printerAPI = require('rest.api.api_printer') local wifi = require('network.wlanconfig') local settings = require('util.settings') +local MOD_ABBR = "AINF" local TMP_DIR = '/tmp' local LOG_COLLECT_DIRNAME = 'wifibox-logs' local LOG_COLLECT_DIR = TMP_DIR .. '/' .. LOG_COLLECT_DIRNAME @@ -25,7 +26,7 @@ local WIFIBOX_STDOUT_LOG_FILENAME = 'wifibox.stdout.log' local WIFIBOX_STDOUT_LOG_FILE = TMP_DIR .. '/' .. WIFIBOX_STDOUT_LOG_FILENAME local ROTATED_LOGS_DIRNAME = 'wifibox-rotated' local ROTATED_LOGS_DIR = TMP_DIR .. '/' .. ROTATED_LOGS_DIRNAME -local MOD_ABBR = "AINF" +local REQUEST_INFO_FILENAME = 'request-info.txt' local SYSLOG_FILENAME = 'syslog' local PROCESS_LIST_FILENAME = 'processes' @@ -115,6 +116,21 @@ function M.logfiles(request, response) -- list directory structure for primary USB controller rv,sig,code = os.execute(USB_DIRTREE_COMMAND .. ' > ' .. LOG_COLLECT_DIR .. '/' .. USB_DIRTREE_FILENAME) + rqf,msg,code = io.open(LOG_COLLECT_DIR .. '/' .. REQUEST_INFO_FILENAME, 'w') + if rqf then + local env = request:getEnvironment() + for k,v in pairs(env) do + if type(v) ~= 'table' then -- nicely format one nested table level (for http headers) + rqf:write(utils.dump(k) .. ": " .. utils.dump(v) .. "\n") + else + rqf:write(utils.dump(k) .. ": " .. utils.dump(v) .. "\n") + end + end + rqf:close() + else + log:error(MOD_ABBR, "could not open file '" .. (LOG_COLLECT_DIR .. '/' .. REQUEST_INFO_FILENAME) .. "' for writing (" .. msg .. ", " .. code .. ")") + end + -- copy relevant openwrt configuration files -- Note: we cannot link them because that would require the link to span over filesystems rv,msg = lfs.mkdir(LOG_COLLECT_DIR .. '/config') @@ -159,6 +175,7 @@ function M.logfiles(request, response) rv,sig,code = redirectedExecute('rm ' .. LOG_COLLECT_DIR .. '/' .. ROTATED_LOGS_DIRNAME .. '/*') rv,msg = lfs.rmdir(LOG_COLLECT_DIR .. '/' .. ROTATED_LOGS_DIRNAME) + rv,sig,code = redirectedExecute('rm ' .. LOG_COLLECT_DIR .. '/' .. REQUEST_INFO_FILENAME) rv,sig,code = redirectedExecute('rm ' .. LOG_COLLECT_DIR .. '/' .. USB_DIRTREE_FILENAME) rv,sig,code = redirectedExecute('rm ' .. LOG_COLLECT_DIR .. '/' .. DISKFREE_FILENAME) rv,sig,code = redirectedExecute('rm ' .. LOG_COLLECT_DIR .. '/' .. MOUNTS_FILENAME) diff --git a/src/rest/request.lua b/src/rest/request.lua index 00ad3e4..188493c 100644 --- a/src/rest/request.lua +++ b/src/rest/request.lua @@ -172,6 +172,7 @@ setmetatable(M, { function M.new(environment, postData, debugEnabled) local self = setmetatable({}, M) + self.requestEnvironment = environment --NOTE: is it correct to assume that absence of REQUEST_METHOD indicates command line invocation? self.requestMethod = environment['REQUEST_METHOD'] if type(self.requestMethod) == 'string' and self.requestMethod:len() > 0 then @@ -241,6 +242,7 @@ function M.new(environment, postData, debugEnabled) return self end +function M:getEnvironment() return self.requestEnvironment end --returns the environment as passed to the ctor function M:getRequestMethod() return self.requestMethod end --returns either GET or POST or CMDLINE function M:getRequestedApiModule() return self.requestedApiModule end function M:getRequestedApiFunction() return self.requestedApiFunction end diff --git a/src/util/utils.lua b/src/util/utils.lua index f0c1020..a4c4eec 100644 --- a/src/util/utils.lua +++ b/src/util/utils.lua @@ -57,15 +57,34 @@ end --- Stringifies the given object. -- Note that self-referencing objects will cause an endless loop with the current implementation. -- @param o The object to convert. +-- @param withNewlines include newlines and indent subtables if true (false by default). +-- @param level For internal use, do not pass this along. -- @treturn string Stringified version of o. -function M.dump(o) +function M.dump(o, withNewlines, level) + withNewlines = withNewlines or false + level = level or 0 + if type(o) == 'table' then - local s = '{ ' + local s = withNewlines and '' or '{ ' + local firstPair = true + + if withNewlines and level > 0 then s = s .. "\n" end for k,v in pairs(o) do - if type(k) ~= 'number' then k = '"'..k..'"' end - s = s .. '['..k..'] = ' .. M.dump(v) .. ',' + if withNewlines then + local indentation = string.rep(' ', level * 2) + if type(v) == 'string' or type(v) == 'number' then v = '"'..v..'"' end + if not firstPair then s = s .. "\n" end + s = s .. indentation .. k .. ': ' .. M.dump(v, withNewlines, level + 1) + else + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. M.dump(v, withNewlines, level + 1) .. ', ' + end + firstPair = false + end + + if withNewlines then return s + else return s .. '} ' end - return s .. '} ' else return tostring(o) end