--[[
-LuCI - HTTPD
+
+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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
]]--
-module("luci.httpd", package.seeall)
-require("luci.copas")
-require("luci.http.protocol")
-require("luci.sys")
+module("luci.httpd", package.seeall)
+require("socket")
+require("luci.util")
+function Socket(ip, port)
+ local sock, err = socket.bind( ip, port )
-function run(config)
- -- TODO: process config
- local server = socket.bind("0.0.0.0", 8080)
- copas.addserver(server, spawnworker)
-
- while true do
- copas.step()
+ if sock then
+ sock:settimeout( 0, "t" )
end
-end
-
-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)
+ return sock, err
end
-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
+Daemon = luci.util.class()
+
+function Daemon.__init__(self, threadlimit, timeout)
+ self.reading = {}
+ self.running = {}
+ self.handler = {}
+ self.debug = false
+ self.threadlimit = threadlimit
+ self.timeout = timeout or 0.1
end
-function Response.addheader(self, key, value)
- self.headers[key] = value
+function Daemon.dprint(self, msg)
+ if self.debug then
+ io.stderr:write("[daemon] " .. msg .. "\n")
+ end
end
-function Response.setstatus(self, status)
- self.status = status
+function Daemon.register(self, sock, clhandler, errhandler)
+ table.insert( self.reading, sock )
+ self.handler[sock] = { 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, output, err = socket.select( self.reading, nil, 0 )
-Handler = luci.util.class()
-function Handler.__init__(self)
- self.filter = {}
-end
+ if err == "timeout" and #self.running == 0 then
+ socket.sleep(self.timeout)
+ end
-function Handler.addfilter(self, filter)
- table.insert(self.filter, filter)
-end
+ -- accept new connections
+ for i, connection in ipairs(input) do
+
+ local sock = connection:accept()
+
+ -- check capacity
+ if not self.threadlimit or #self.running < self.threadlimit then
+
+ self:dprint("Accepted incoming connection from " .. sock:getpeername())
+
+ table.insert( self.running, {
+ coroutine.create( self.handler[connection].clhandler ),
+ sock
+ } )
-function Handler.process(self, request, output)
- -- TODO: Process input filters
+ self:dprint("Created " .. tostring(self.running[#self.running][1]))
- 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")
+ -- reject client
+ else
+ self:dprint("Rejected incoming connection from " .. sock:getpeername())
+
+ 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
+ self:dprint("Completed " .. tostring(client[1]))
+ table.remove( self.running, i )
+ else
+ self:dprint("Resuming " .. tostring(client[1]))
+
+ local stat, err = coroutine.resume( client[1], client[2] )
+
+ self:dprint(tostring(client[1]) .. " returned")
+
+ if not stat then
+ self:dprint("Error in " .. tostring(client[1]) .. " " .. err)
+ end
+ end
end
end
-