* 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
This commit is contained in:
Steven Barth 2008-06-20 19:57:57 +00:00
parent e2e9e119d6
commit 65870edf9f
6 changed files with 45 additions and 23 deletions

View file

@ -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})

View file

@ -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,9 +712,9 @@ 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
-- store whole buffer in message.content

View file

@ -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)

View file

@ -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)

View file

@ -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 = {}

View file

@ -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
function Request.__init__(self, env, sourcein, sinkerr)
self.input = sourcein
self.error = sinkerr
-- 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
-- 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
)