90fdd7ed32dd367cc7a2be9b828cc859916ab426
[project/luci.git] / libs / httpd / luasrc / httpd / server.lua
1 --[[
2
3 HTTP server implementation for LuCI - helper class
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.server", package.seeall)
17 require("luci.util")
18
19 READ_BUFSIZE = 1024
20
21
22 VHost = luci.util.class()
23
24 function VHost.__init__(self, handler)
25         self.handler = handler
26         self.dhandler = {}
27 end
28
29 function VHost.process(self, request, sourcein, sinkout, sinkerr)
30         local handler = self.handler
31
32         local uri = request.env.REQUEST_URI:match("^([^?]*)")
33
34         -- SCRIPT_NAME
35         request.env.SCRIPT_NAME = ""
36
37         -- Call URI part
38         request.env.PATH_INFO = uri
39
40         for k, dhandler in pairs(self.dhandler) do
41                 if k == uri or k.."/" == uri:sub(1, #k+1) then
42                         handler = dhandler
43                         request.env.SCRIPT_NAME = k
44                         request.env.PATH_INFO   = uri:sub(#k+1)
45                         break;
46                 end
47         end
48
49         if handler then
50                 handler:process(request, sourcein, sinkout, sinkerr)
51                 return true
52         else
53                 return false
54         end
55 end
56
57
58 function VHost.set_default_handler(self, handler)
59         self.handler = handler
60 end
61
62
63 function VHost.set_handler(self, match, handler)
64         self.dhandler[match] = handler
65 end
66
67
68
69 Server = luci.util.class()
70
71 function Server.__init__(self, host)
72         self.clhandler = client_handler
73         self.errhandler = error503
74         self.host = host
75         self.vhosts = {}
76 end
77
78 function Server.set_default_vhost(self, vhost)
79         self.host = vhost
80 end
81
82 -- Sets a vhost
83 function Server.set_vhost(self, name, vhost)
84         self.vhosts[name] = vhost
85 end
86
87 function Server.create_daemon_handlers(self)
88         return function(...) return self:process(...) end,
89                 function(...) return self:error503(...) end
90 end
91
92 function Server.create_client_sources(self, client)
93         -- Create LTN12 block source
94         local block_source = function()
95
96                 -- Yielding here may cause chaos in coroutine based modules, be careful
97                 -- coroutine.yield()
98
99                 local chunk, err, part = client:receive( READ_BUFSIZE )
100
101                 if chunk == nil and err == "timeout" then
102                         return part
103                 elseif chunk ~= nil then
104                         return chunk
105                 else
106                         return nil, err
107                 end
108
109         end
110
111
112         -- Create LTN12 line source
113         local line_source = ltn12.source.simplify( function()
114
115                 coroutine.yield()
116
117                 local chunk, err, part = client:receive("*l")
118
119                 -- Line too long
120                 if chunk == nil and err ~= "timeout" then
121
122                         return nil, part
123                                 and "Line exceeds maximum allowed length["..part.."]"
124                                 or  "Unexpected EOF"
125
126                 -- Line ok
127                 elseif chunk ~= nil then
128
129                         -- Strip trailing CR
130                         chunk = chunk:gsub("\r$","")
131
132                         -- We got end of headers, switch to dummy source
133                         if #chunk == 0 then
134                                 return "", function()
135                                         return nil
136                                 end
137                         else
138                                 return chunk, nil
139                         end
140                 end
141         end )
142
143         return block_source, line_source
144 end
145
146
147 function Server.error400(self, socket, msg)
148         socket:send( "HTTP/1.0 400 Bad request\r\n" )
149         socket:send( "Content-Type: text/plain\r\n\r\n" )
150
151         if msg then
152                 socket:send( msg .. "\r\n" )
153         end
154
155         socket:close()
156 end
157
158 function Server.error500(self, socket, msg)
159         socket:send( "HTTP/1.0 500 Internal Server Error\r\n" )
160         socket:send( "Content-Type: text/plain\r\n\r\n" )
161
162         if msg then
163                 socket:send( msg .. "\r\n" )
164         end
165
166         socket:close()
167 end
168
169 function Server.error503(self, socket)
170         socket:send( "HTTP/1.0 503 Server unavailable\r\n" )
171         socket:send( "Content-Type: text/plain\r\n\r\n" )
172         socket:send( "There are too many clients connected, try again later\r\n" )
173         socket:close()
174 end
175
176
177 function Server.process(self, client)
178
179         client:settimeout( 0 )
180         local sourcein, sourcehdr = self:create_client_sources(client)
181         local sinkerr = ltn12.sink.file(io.stderr)
182
183         -- FIXME: Add keep-alive support
184         local sinkout = socket.sink("close-when-done", client)
185
186         coroutine.yield()
187
188         -- parse headers
189         local message, err = luci.http.protocol.parse_message_header( sourcehdr )
190
191         if message then
192                 -- If we have a HTTP/1.1 client and an Expect: 100-continue header then
193                 -- respond with HTTP 100 Continue message
194                 if message.http_version == 1.1 and message.headers['Expect'] and
195                         message.headers['Expect'] == '100-continue'
196                 then
197                         client:send("HTTP/1.1 100 Continue\r\n\r\n")
198                 end
199
200                 local host = self.vhosts[message.env.HTTP_HOST] or self.host
201                 if host then
202                         if host:process(message, sourcein, sinkout, sinkerr) then
203                                 sinkout()
204                         else
205                                 self:error500( client, "No suitable path handler found" )
206                         end
207                 else
208                         self:error500( client, "No suitable host handler found" )
209                 end
210         else
211                 self:error400( client, err )
212                 return nil
213         end
214 end