3 HTTP server implementation for LuCI - helper class
4 (c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
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
10 http://www.apache.org/licenses/LICENSE-2.0
16 module("luci.httpd.server", package.seeall)
22 VHost = luci.util.class()
24 function VHost.__init__(self, handler)
25 self.handler = handler
29 function VHost.process(self, request, sourcein, sinkout, sinkerr)
30 local handler = self.handler
32 local uri = request.env.REQUEST_URI:match("^([^?]*)")
35 request.env.SCRIPT_NAME = ""
38 request.env.PATH_INFO = uri
40 for k, dhandler in pairs(self.dhandler) do
41 if k == uri or k.."/" == uri:sub(1, #k+1) then
43 request.env.SCRIPT_NAME = k
44 request.env.PATH_INFO = uri:sub(#k+1)
50 handler:process(request, sourcein, sinkout, sinkerr)
58 function VHost.set_default_handler(self, handler)
59 self.handler = handler
63 function VHost.set_handler(self, match, handler)
64 self.dhandler[match] = handler
69 Server = luci.util.class()
71 function Server.__init__(self, host)
72 self.clhandler = client_handler
73 self.errhandler = error503
78 function Server.set_default_vhost(self, vhost)
83 function Server.set_vhost(self, name, vhost)
84 self.vhosts[name] = vhost
87 function Server.create_daemon_handlers(self)
88 return function(...) return self:process(...) end,
89 function(...) return self:error503(...) end
92 function Server.create_client_sources(self, client)
93 -- Create LTN12 block source
94 local block_source = function()
96 -- Yielding here may cause chaos in coroutine based modules, be careful
99 local chunk, err, part = client:receive( READ_BUFSIZE )
101 if chunk == nil and err == "timeout" then
103 elseif chunk ~= nil then
112 -- Create LTN12 line source
113 local line_source = ltn12.source.simplify( function()
117 local chunk, err, part = client:receive("*l")
120 if chunk == nil and err ~= "timeout" then
123 and "Line exceeds maximum allowed length["..part.."]"
127 elseif chunk ~= nil then
130 chunk = chunk:gsub("\r$","")
132 -- We got end of headers, switch to dummy source
134 return "", function()
143 return block_source, line_source
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" )
152 socket:send( msg .. "\r\n" )
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" )
163 socket:send( msg .. "\r\n" )
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" )
177 function Server.process(self, client)
179 client:settimeout( 0 )
180 local sourcein, sourcehdr = self:create_client_sources(client)
181 local sinkerr = ltn12.sink.file(io.stderr)
183 -- FIXME: Add keep-alive support
184 local sinkout = socket.sink("close-when-done", client)
189 local message, err = luci.http.protocol.parse_message_header( sourcehdr )
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'
197 client:send("HTTP/1.1 100 Continue\r\n\r\n")
200 local host = self.vhosts[message.env.HTTP_HOST] or self.host
202 if host:process(message, sourcein, sinkout, sinkerr) then
205 self:error500( client, "No suitable path handler found" )
208 self:error500( client, "No suitable host handler found" )
211 self:error400( client, err )