From 65870edf9f1e579b4301e1677d70c9387a9a72dc Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Fri, 20 Jun 2008 19:57:57 +0000 Subject: [PATCH] * libs/core: Added garbage collector to luci.util.threadlocal to avoid memory leaks * libs/http: Use env-Variables instead of headers for parse_message_body and subsequent functions * libs/http: Added missing urldecode call for parsing urlencoded params * libs/web: Ported luci.http to use ltn12 sources and sinks instead of sockets or file pointers * libs/sgi-cgi, libs/sgi-webuci, libs/sgi-wsapi: Updated to work with new luci.http.Request ABI --- libs/core/luasrc/util.lua | 7 +++++++ libs/http/luasrc/http/protocol.lua | 19 ++++++++++++------- libs/sgi-cgi/luasrc/sgi/cgi.lua | 7 ++++++- libs/sgi-webuci/luasrc/sgi/webuci.lua | 8 +++++++- libs/sgi-wsapi/luasrc/sgi/wsapi.lua | 9 ++++++--- libs/web/luasrc/http.lua | 18 +++++++----------- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/libs/core/luasrc/util.lua b/libs/core/luasrc/util.lua index 3a0b2fbfc1..5168560572 100644 --- a/libs/core/luasrc/util.lua +++ b/libs/core/luasrc/util.lua @@ -281,6 +281,13 @@ function threadlocal() rawset(self, thread, {}) end rawget(self, thread)[key] = value + + -- Avoid memory leaks by removing abandoned stores + for k, v in pairs(self) do + if type(k) == "thread" and coroutine.status(k) == "dead" then + rawset(self, k, nil) + end + end end setmetatable(tbl, {__index = get, __newindex = set}) diff --git a/libs/http/luasrc/http/protocol.lua b/libs/http/luasrc/http/protocol.lua index 01d3128b25..6e53d7ca18 100644 --- a/libs/http/luasrc/http/protocol.lua +++ b/libs/http/luasrc/http/protocol.lua @@ -378,8 +378,8 @@ process_states['urldecode-init'] = function( msg, chunk, filecb ) if chunk ~= nil then -- Check for Content-Length - if msg.headers['Content-Length'] then - msg.content_length = tonumber(msg.headers['Content-Length']) + if msg.env.CONTENT_LENGTH then + msg.content_length = tonumber(msg.env.CONTENT_LENGTH) if msg.content_length <= HTTP_MAX_CONTENT then -- Initialize buffer @@ -404,7 +404,6 @@ end -- Process urldecoding stream, read and validate parameter key process_states['urldecode-key'] = function( msg, chunk, filecb ) - if chunk ~= nil then -- Prevent oversized requests @@ -436,6 +435,11 @@ process_states['urldecode-key'] = function( msg, chunk, filecb ) else msg._urldeccallback = function( chunk, eof ) msg.params[key] = msg.params[key] .. chunk + + -- FIXME: Use a filter + if eof then + msg.params[key] = urldecode( msg.params[key] ) + end end end @@ -520,9 +524,9 @@ end function mimedecode_message_body( source, msg, filecb ) -- Find mime boundary - if msg and msg.headers['Content-Type'] then + if msg and msg.env.CONTENT_TYPE then - local bound = msg.headers['Content-Type']:match("^multipart/form%-data; boundary=(.+)") + local bound = msg.env.CONTENT_TYPE:match("^multipart/form%-data; boundary=(.+)") if bound then msg.mime_boundary = bound @@ -666,7 +670,8 @@ function parse_message_header( source ) REQUEST_METHOD = msg.request_method:upper(); REQUEST_URI = msg.request_uri; SCRIPT_NAME = msg.request_uri:gsub("?.+$",""); - SCRIPT_FILENAME = "" -- XXX implement me + SCRIPT_FILENAME = ""; -- XXX implement me + SERVER_PROTOCOL = "HTTP/" .. msg.http_version } -- Populate HTTP_* environment variables @@ -707,8 +712,8 @@ function parse_message_body( source, msg, filecb ) elseif msg.env.REQUEST_METHOD == "POST" and msg.env.CONTENT_TYPE and msg.env.CONTENT_TYPE == "application/x-www-form-urlencoded" then - return urldecode_message_body( source, msg, filecb ) + -- Unhandled encoding -- If a file callback is given then feed it line by line, else diff --git a/libs/sgi-cgi/luasrc/sgi/cgi.lua b/libs/sgi-cgi/luasrc/sgi/cgi.lua index 7abb1ef781..8ba4c54a3a 100644 --- a/libs/sgi-cgi/luasrc/sgi/cgi.lua +++ b/libs/sgi-cgi/luasrc/sgi/cgi.lua @@ -24,12 +24,17 @@ limitations under the License. ]]-- module("luci.sgi.cgi", package.seeall) +require("ltn12") require("luci.http") require("luci.sys") require("luci.dispatcher") function run() - local r = luci.http.Request(luci.sys.getenv(), io.stdin, io.stderr) + local r = luci.http.Request( + luci.sys.getenv(), + ltn12.source.file(io.stdin), + ltn12.sink.file(io.stderr) + ) local x = coroutine.create(luci.dispatcher.httpdispatch) diff --git a/libs/sgi-webuci/luasrc/sgi/webuci.lua b/libs/sgi-webuci/luasrc/sgi/webuci.lua index 7bfa2fe13c..cf8cbcce20 100644 --- a/libs/sgi-webuci/luasrc/sgi/webuci.lua +++ b/libs/sgi-webuci/luasrc/sgi/webuci.lua @@ -24,12 +24,18 @@ limitations under the License. ]]-- module("luci.sgi.webuci", package.seeall) +require("ltn12") require("luci.http") require("luci.util") require("luci.dispatcher") function run(env, vars) - local r = luci.http.Request(env, {}, io.stderr) + local r = luci.http.Request( + env, + ltn12.source.empty(), + ltn12.sink.file(io.stderr) + ) + r.message.params = vars local x = coroutine.create(luci.dispatcher.httpdispatch) diff --git a/libs/sgi-wsapi/luasrc/sgi/wsapi.lua b/libs/sgi-wsapi/luasrc/sgi/wsapi.lua index f77ac5c5bc..5b237cd7a5 100644 --- a/libs/sgi-wsapi/luasrc/sgi/wsapi.lua +++ b/libs/sgi-wsapi/luasrc/sgi/wsapi.lua @@ -24,14 +24,17 @@ limitations under the License. ]]-- module("luci.sgi.wsapi", package.seeall) +require("ltn12") require("luci.http") require("luci.dispatcher") require("luci.http.protocol") function run(wsapi_env) - local r = luci.http.Request(wsapi_env, wsapi_env.input, wsapi_env.error) - r.postds = function() return wsapi.request.parse_post_data(wsapi_env) end - r.getds = function() return wsapi.request.parse_qs(wsapi_env.QUERY_STRING) end + local r = luci.http.Request( + wsapi_env, + ltn12.source.file(wsapi_env.input), + ltn12.sink.file(wsapi_env.error) + ) local res, id, data1, data2 = true, 0, nil, nil local headers = {} diff --git a/libs/web/luasrc/http.lua b/libs/web/luasrc/http.lua index f2c3660739..2bd914429e 100644 --- a/libs/web/luasrc/http.lua +++ b/libs/web/luasrc/http.lua @@ -28,6 +28,7 @@ limitations under the License. ]]-- module("luci.http", package.seeall) +require("ltn12") require("luci.http.protocol") require("luci.util") @@ -35,15 +36,10 @@ context = luci.util.threadlocal() Request = luci.util.class() -function Request.__init__(self, env, instream, errstream) - self.input = instream - self.error = errstream - - -- Provide readline function - self.inputreader = self.input.readline - or self.input.read and function() return self.input:read() end - or self.input.receive and function() return self.input:receive() end - or function() return nil end +function Request.__init__(self, env, sourcein, sinkerr) + self.input = sourcein + self.error = sinkerr + -- File handler self.filehandler = function() end @@ -52,13 +48,13 @@ function Request.__init__(self, env, instream, errstream) self.message = { env = env, headers = {}, - params = luci.http.protocol.urldecode_params("?"..(env.QUERY_STRING or "")), + params = luci.http.protocol.urldecode_params(env.QUERY_STRING or ""), } setmetatable(self.message.params, {__index = function(tbl, key) luci.http.protocol.parse_message_body( - self.inputreader, + self.input, self.message, self.filehandler ) -- 2.30.2