* Introducing LuCI HTTPD as testing environment
[project/luci.git] / libs / httpd / luasrc / httpd.lua
1 --[[
2
3 HTTP server implementation for LuCI - core
4 (c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 module("luci.httpd", package.seeall)
17 require("socket")
18 require("luci.util")
19
20 function Socket(ip, port)
21 local sock, err = socket.bind( ip, port )
22
23 if sock then
24 sock:settimeout( 0, "t" )
25 end
26
27 return sock, err
28 end
29
30
31 Daemon = luci.util.class()
32
33 function Daemon.__init__(self, threadlimit, timeout)
34 self.reading = {}
35 self.running = {}
36 self.handler = {}
37 self.debug = false
38 self.threadlimit = threadlimit
39 self.timeout = timeout or 0.1
40 end
41
42 function Daemon.dprint(self, msg)
43 if self.debug then
44 io.stderr:write("[daemon] " .. msg .. "\n")
45 end
46 end
47
48 function Daemon.register(self, sock, clhandler, errhandler)
49 table.insert( self.reading, sock )
50 self.handler[sock] = { clhandler = clhandler, errhandler = errhandler }
51 end
52
53 function Daemon.run(self)
54 while true do
55 self:step()
56 end
57 end
58
59 function Daemon.step(self)
60 local input, output, err = socket.select( self.reading, nil, 0 )
61
62 if err == "timeout" and #self.running == 0 then
63 socket.sleep(self.timeout)
64 end
65
66 -- accept new connections
67 for i, connection in ipairs(input) do
68
69 local sock = connection:accept()
70
71 -- check capacity
72 if not self.threadlimit or #self.running < self.threadlimit then
73
74 self:dprint("Accepted incoming connection from " .. sock:getpeername())
75
76 table.insert( self.running, {
77 coroutine.create( self.handler[connection].clhandler ),
78 sock
79 } )
80
81 self:dprint("Created " .. tostring(self.running[#self.running][1]))
82
83 -- reject client
84 else
85 self:dprint("Rejected incoming connection from " .. sock:getpeername())
86
87 if self.handler[connection].errhandler then
88 self.handler[connection].errhandler( sock )
89 end
90
91 sock:close()
92 end
93 end
94
95 -- create client handler
96 for i, client in ipairs( self.running ) do
97
98 -- reap dead clients
99 if coroutine.status( client[1] ) == "dead" then
100 self:dprint("Completed " .. tostring(client[1]))
101 table.remove( self.running, i )
102 else
103 self:dprint("Resuming " .. tostring(client[1]))
104
105 local stat, err = coroutine.resume( client[1], client[2] )
106
107 self:dprint(tostring(client[1]) .. " returned")
108
109 if not stat then
110 self:dprint("Error in " .. tostring(client[1]) .. " " .. err)
111 end
112 end
113 end
114 end