Skip to content

Instantly share code, notes, and snippets.

@ayourtch
Created June 6, 2010 14:40
Show Gist options
  • Save ayourtch/427622 to your computer and use it in GitHub Desktop.
Save ayourtch/427622 to your computer and use it in GitHub Desktop.
-- http://lua-users.org/lists/lua-l/2002-04/msg00180.html
require 'socket'
local header =
[[HTTP/1.1 200 OK
Date: Fri, 19 Apr 2002 20:37:57 GMT
Server: Apache/1.3.23 (Darwin) mod_ssl/2.8.7 OpenSSL/0.9.6b
Cache-Control: max-age=60
Expires: Fri, 19 Apr 2002 20:38:57 GMT
Last-Modified: Tue, 16 Apr 2002 02:00:34 GMT
ETag: "3c57e-1e47-3cbb85c2"
Accept-Ranges: bytes
Connection: close
]]
WebServer =
{
_port = 8080,
_header = header,
}
function WebServer:run()
self._server = socket.bind("localhost", self._port)
self._server:settimeout(.01)
self._clients = {}
self._sendClients = {}
print("WebServer running on port "..self._port)
self:mainLoop()
end
function WebServer:lookForNewClients()
local client = self._server:accept()
if client then
client:settimeout(0.3)
table.insert(self._clients, client)
end
end
function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
-- http://lua-users.org/lists/lua-l/2009-06/msg00572.html
function read(client, pattern, prefix)
local data, emsg, partial = client:receive(pattern, prefix)
if data then
return data
end
if partial and #partial > 0 then
return partial
end
return nil, emsg
end
cache = {}
function runfile(fname, req, resp)
local newgt = {} -- create new environment
setmetatable(newgt, {__index = _G})
local text = ""
local oldprint = print
local printfunc = function(...)
for i, v in ipairs(arg) do
resp.text = resp.text .. tostring(v)
end
end
local redirfunc = function(uri)
resp.text = "HTTP/1.1 302 Moved\r\nLocation: /" .. fname .. uri .. "\r\n\r\n"
end
local errtext = nil
local errhandler = function(...)
print("Error!")
-- page:write("<pre>\n")
-- e(debug.traceback())
errtext = debug.traceback()
print(errtext)
-- page:write("</pre>\n")
end
-- print("runfile: about to switch environment...")
newgt.request = req
newgt.response = resp
newgt.global_params = {}
newgt.web_send = printfunc
newgt.web_redirect = redirfunc
setfenv(1, newgt) -- set it
-- print("Request:", request.url)
request.url = string.sub(request.url, #fname + 1 + 1)
local func, message
if cache[fname] then
func = cache[fname]
else
func, message = loadfile(fname)
end
-- print("Loadfunc results:", func, message)
if func then
setfenv(func, newgt)
-- TODO: proper caching
-- cache[fname] = func
local res, err = xpcall(func, errhandler)
if not res then
print("result of pcall: ", err)
end
else
if message then
print("Error in loadfile:", message)
end
end
_G.print = oldprint
_G.page = page
setfenv(1, _G._G)
if resp.text == "" then
if errtext then
resp.text = "HTTP/1.0 500 Error\r\n\r\n" .. errtext
elseif page then
resp.text = page:full_response()
end
end
return resp
end
function WebServer:handleRequest(req)
local text = ""
local response = self._header.. "Content-length: " .. string.len(text) .. "\n\n" .. text
return response
end
function WebServer:mainLoop()
local clients = self._clients
while 1 do
self:lookForNewClients()
local receivingClients, _, error = socket.select(clients, nil, .01)
if error and error ~= "timeout" then
print("error = "..tostring(error))
end
for i, client in ipairs(receivingClients) do
local clientdata = {}
repeat
local data, error = client:receive()
if data then
table.insert(clientdata, data)
-- print("Data:", data)
end
until data == "" or not data
local req = {}
if clientdata[1] then
local data = clientdata[1]
-- print("Data: " .. data)
req.firstline = split(data, "[ ]")
req.method = req.firstline[1]
req.full_url = req.firstline[2]
-- print("Full URL", req.full_url)
if req.full_url then
req.url, req.query_string = string.match(req.full_url, "^([^?]+)[?]*(.*)$")
req.query_string = req.query_string or ""
else
error = "no url in request"
end
end
if error then
print("error: "..tostring(error).." on client "..tostring(client))
table.remove(clients, i)
else
bytesSent = client:send(WebServer:handleRequest(req))
if bytesSent then
-- print("bytesSent = ".. bytesSent.." bytes = ".. #response)
end
client:close()
table.remove(clients, i)
end
end
end
end
WebServer:run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment