* libs/core: Added garbage collector to luci.util.threadlocal to avoid memory leaks
authorSteven Barth <steven@midlink.org>
Fri, 20 Jun 2008 19:57:57 +0000 (19:57 +0000)
committerSteven Barth <steven@midlink.org>
Fri, 20 Jun 2008 19:57:57 +0000 (19:57 +0000)
* 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
libs/http/luasrc/http/protocol.lua
libs/sgi-cgi/luasrc/sgi/cgi.lua
libs/sgi-webuci/luasrc/sgi/webuci.lua
libs/sgi-wsapi/luasrc/sgi/wsapi.lua
libs/web/luasrc/http.lua

index 3a0b2fbfc11ed2ab6a8e7bcb782ca9266d12b7d1..51685605721767ffa1fd4f362a7067551c446642 100644 (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})
index 01d3128b2525f4e9ffd9604f655054037598f442..6e53d7ca187c15a3fe530a4aa211ee3b5f4897a2 100644 (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,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
index 7abb1ef781190ddcc49ee2429bbd4f70552b499b..8ba4c54a3a33abb43d4c7b1522a22c53cfd650df 100644 (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)
        
index 7bfa2fe13c96e8dbdcaffe036881e7c8f5e4ee1e..cf8cbcce20cff94bba2fda43dc6f6bb32cdce273 100644 (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)
index f77ac5c5bce7700fd8f5ffc684c214c26a6ab302..5b237cd7a53c78ed30056186f09029e726f08cb7 100644 (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 = {}
index f2c36607398821eb50636cdc0eb1759a2e69ad21..2bd914429e75b2c4a0ba877ada92738f1af87dcc 100644 (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
-       
-       -- 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
                        )