* luci/httpd: add initial server implementation
This commit is contained in:
parent
f712a1f2c2
commit
8349a0504e
2 changed files with 184 additions and 0 deletions
69
libs/httpd/luasrc/httpd.lua
Normal file
69
libs/httpd/luasrc/httpd.lua
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
--[[
|
||||||
|
|
||||||
|
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$
|
||||||
|
|
||||||
|
]]--
|
||||||
|
|
||||||
|
require("ltn12")
|
||||||
|
require("socket")
|
||||||
|
|
||||||
|
require("luci.util")
|
||||||
|
require("luci.http.protocol")
|
||||||
|
require("luci.httpd.server")
|
||||||
|
|
||||||
|
|
||||||
|
local srv = luci.httpd.server
|
||||||
|
local host = "0.0.0.0"
|
||||||
|
local port = 50000
|
||||||
|
|
||||||
|
|
||||||
|
server = socket.bind(host, port)
|
||||||
|
server:settimeout( 0, "t" )
|
||||||
|
|
||||||
|
reading = { server }
|
||||||
|
running = { }
|
||||||
|
|
||||||
|
|
||||||
|
while true do
|
||||||
|
|
||||||
|
local input = socket.select( reading, nil, 0.1 )
|
||||||
|
|
||||||
|
-- accept new connections
|
||||||
|
for i, connection in ipairs(input) do
|
||||||
|
|
||||||
|
local sock = connection:accept()
|
||||||
|
|
||||||
|
-- check capacity
|
||||||
|
if #running < srv.MAX_CLIENTS then
|
||||||
|
|
||||||
|
table.insert( running, {
|
||||||
|
coroutine.create( srv.client_handler ),
|
||||||
|
sock
|
||||||
|
} )
|
||||||
|
|
||||||
|
-- reject client
|
||||||
|
else
|
||||||
|
srv.error503( sock )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- create client handler
|
||||||
|
for i, client in ipairs( running ) do
|
||||||
|
|
||||||
|
-- reap dead clients
|
||||||
|
if coroutine.status( client[1] ) == "dead" then
|
||||||
|
table.remove( running, i )
|
||||||
|
end
|
||||||
|
|
||||||
|
coroutine.resume( client[1], client[2] )
|
||||||
|
end
|
||||||
|
end
|
115
libs/httpd/luasrc/httpd/server.lua
Normal file
115
libs/httpd/luasrc/httpd/server.lua
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
--[[
|
||||||
|
|
||||||
|
HTTP server implementation for LuCI - helper class
|
||||||
|
(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.server", package.seeall)
|
||||||
|
|
||||||
|
|
||||||
|
MAX_CLIENTS = 15
|
||||||
|
READ_BUFSIZE = 1024
|
||||||
|
|
||||||
|
|
||||||
|
function error400( client, msg )
|
||||||
|
client:send( "HTTP/1.0 400 Bad request\r\n" )
|
||||||
|
client:send( "Content-Type: text/plain\r\n\r\n" )
|
||||||
|
|
||||||
|
if msg then
|
||||||
|
client:send( msg .. "\r\n" )
|
||||||
|
end
|
||||||
|
|
||||||
|
client:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
function error503( client )
|
||||||
|
client:send( "HTTP/1.0 503 Server unavailable\r\n" )
|
||||||
|
client:send( "Content-Type: text/plain\r\n\r\n" )
|
||||||
|
client:send( "There are too many clients connected, try again later\r\n" )
|
||||||
|
client:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function client_handler(client)
|
||||||
|
|
||||||
|
client:settimeout( 0 )
|
||||||
|
|
||||||
|
-- Create LTN12 block source
|
||||||
|
local block_source = function()
|
||||||
|
|
||||||
|
coroutine.yield()
|
||||||
|
|
||||||
|
local chunk, err, part = client:receive( READ_BUFSIZE )
|
||||||
|
|
||||||
|
if chunk == nil and err == "timeout" then
|
||||||
|
return part
|
||||||
|
elseif chunk ~= nil then
|
||||||
|
return chunk
|
||||||
|
else
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create LTN12 line source
|
||||||
|
local line_source = ltn12.source.simplify( function()
|
||||||
|
|
||||||
|
coroutine.yield()
|
||||||
|
|
||||||
|
local chunk, err, part = client:receive("*l")
|
||||||
|
|
||||||
|
-- Line too long
|
||||||
|
if chunk == nil and err ~= "timeout" then
|
||||||
|
|
||||||
|
return nil, part
|
||||||
|
and "Line exceeds maximum allowed length["..part.."]"
|
||||||
|
or "Unexpected EOF"
|
||||||
|
|
||||||
|
-- Line ok
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Strip trailing CR
|
||||||
|
chunk = chunk:gsub("\r$","")
|
||||||
|
|
||||||
|
-- We got end of headers, switch to dummy source
|
||||||
|
if #chunk == 0 then
|
||||||
|
return "", function()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return chunk, nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end )
|
||||||
|
|
||||||
|
coroutine.yield(client)
|
||||||
|
|
||||||
|
|
||||||
|
-- parse message
|
||||||
|
local message, err = luci.http.protocol.parse_message_header( line_source )
|
||||||
|
|
||||||
|
if message then
|
||||||
|
local s, e = luci.http.protocol.parse_message_body( block_source, message )
|
||||||
|
|
||||||
|
-- XXX: debug
|
||||||
|
luci.util.dumptable( message )
|
||||||
|
|
||||||
|
if not s and e then
|
||||||
|
error400( client, e )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error400( client, err )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- send response
|
||||||
|
error400( client, "Dummy response" )
|
||||||
|
end
|
Loading…
Reference in a new issue