201ece616bdebaa96ee901a34a5a6f2385ee5b84
[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 (c) 2008 Steven Barth <steven@midlink.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14
15 ]]--
16
17 module("luci.httpd", package.seeall)
18 require("socket")
19
20 THREAD_IDLEWAIT = 0.01
21 THREAD_TIMEOUT = 90
22 THREAD_LIMIT = nil
23
24 local reading = {}
25 local clhandler = {}
26 local erhandler = {}
27
28 local threadc = 0
29 local threads = {}
30 local threadm = {}
31 local threadi = {}
32
33 function Socket(ip, port)
34 local sock, err = socket.bind( ip, port )
35
36 if sock then
37 sock:settimeout( 0, "t" )
38 end
39
40 return sock, err
41 end
42
43 function corecv(socket, ...)
44 threadi[socket] = true
45
46 while true do
47 local chunk, err, part = socket:receive(...)
48
49 if err ~= "timeout" then
50 threadi[socket] = false
51 return chunk, err, part
52 end
53
54 coroutine.yield()
55 end
56 end
57
58 function register(socket, s_clhandler, s_errhandler)
59 table.insert(reading, socket)
60 clhandler[socket] = s_clhandler
61 erhandler[socket] = s_errhandler
62 end
63
64 function run()
65 while true do
66 step()
67 end
68 end
69
70 function step()
71 local idle = true
72
73 if not THREAD_LIMIT or threadc < THREAD_LIMIT then
74 local now = os.time()
75 for i, server in ipairs(reading) do
76 local client = server:accept()
77 if client then
78 threadm[client] = now
79 threadc = threadc + 1
80 threads[client] = coroutine.create(clhandler[server])
81 end
82 end
83 end
84
85 for client, thread in pairs(threads) do
86 coroutine.resume(thread, client)
87 local now = os.time()
88 if coroutine.status(thread) == "dead" then
89 threads[client] = nil
90 threadc = threadc - 1
91 elseif threadm[client] and threadm[client] + THREAD_TIMEOUT < now then
92 threads[client] = nil
93 threadc = threadc - 1
94 client:close()
95 elseif not threadi[client] then
96 threadm[client] = now
97 idle = false
98 end
99 end
100
101 if idle then
102 socket.sleep(THREAD_IDLEWAIT)
103 end
104 end