* libs/httpd: Prepared HTTPD dispatching model
[project/luci.git] / libs / httpd / luasrc / httpd.lua
index 773d3c8..8cd946f 100644 (file)
@@ -1,84 +1,77 @@
 --[[
-LuCI - HTTPD
-]]--
-module("luci.httpd", package.seeall)
-require("luci.copas")
-require("luci.http.protocol")
-require("luci.sys")
 
+HTTP server implementation for LuCI - core
+(c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
 
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
 
-function run(config)
-       -- TODO: process config
-       local server = socket.bind("0.0.0.0", 8080)
-       copas.addserver(server, spawnworker)
-       
-       while true do
-               copas.step()
-       end
-end
+        http://www.apache.org/licenses/LICENSE-2.0
 
+$Id$
 
-function spawnworker(socket)
-       socket = copas.wrap(socket)
-       local request = luci.http.protocol.parse_message_header(socket)
-       request.input = socket -- TODO: replace with streamreader
-       request.error = io.stderr
-       
-       
-       local output = socket -- TODO: replace with streamwriter
-       
-       -- TODO: detect matching handler
-       local h = luci.httpd.FileHandler.SimpleHandler(luci.sys.libpath() .. "/httpd/httest")
-       h:process(request, output)
-end
+]]--
 
+require("ltn12")
+require("socket")
+require("luci.util")
 
-Response = luci.util.class()
-function Response.__init__(self, sourceout, headers, status)
-       self.sourceout = sourceout or function() end
-       self.headers   = headers or {}
-       self.status    = status or 200
-end
 
-function Response.addheader(self, key, value)
-       self.headers[key] = value
+Daemon = luci.util.class()
+
+function Daemon.__init__(self, threadlimit)
+       self.reading = {}
+       self.running = {}
+       self.handler = {}
+       self.threadlimit = threadlimit
 end
 
-function Response.setstatus(self, status)
-       self.status = status
+function Daemon.register(self, socket, clhandler, errhandler)
+       table.insert( self.reading, socket )
+       self.handler[socket] = { clhandler = clhandler, errhandler = errhandler }
 end
 
-function Response.setsource(self, source)
-       self.sourceout = source
+function Daemon.run(self)
+       while true do
+               self:step()
+       end
 end
 
+function Daemon.step(self)     
+       local input = socket.select( self.reading, nil, 0 )
 
-Handler = luci.util.class()
-function Handler.__init__(self)
-       self.filter = {}
-end
+       -- accept new connections
+       for i, connection in ipairs(input) do
 
-function Handler.addfilter(self, filter)
-       table.insert(self.filter, filter)
-end
+               local sock = connection:accept()
 
-function Handler.process(self, request, output)
-       -- TODO: Process input filters
+               -- check capacity
+               if self.threadlimit and #running < self.threadlimit then
 
-       local response = self:handle(request)
-       
-       -- TODO: Process output filters
-       
-       output:send("HTTP/1.0 " .. response.status .. " BLA\r\n")
-       for k, v in pairs(response.headers) do
-               output:send(k .. ": " .. v .. "\r\n")
+                       table.insert( self.running, {
+                               coroutine.create( self.handler[connection].clhandler ),
+                               sock
+                       } )
+
+               -- reject client
+               else
+                       if self.handler[connection].errhandler then
+                               self.handler[connection].errhandler( sock )
+                       end
+                       
+                       sock:close()
+               end
        end
-       
-       output:send("\r\n")
 
-       for chunk in response.sourceout do
-               output:send(chunk)
+       -- create client handler
+       for i, client in ipairs( self.running ) do
+
+               -- reap dead clients
+               if coroutine.status( client[1] ) == "dead" then
+                       table.remove( self.running, i )
+               end
+
+               coroutine.resume( client[1], client[2] )
        end
 end
-