-
Notifications
You must be signed in to change notification settings - Fork 0
/
webserver.lua
133 lines (111 loc) · 3.52 KB
/
webserver.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
-- warning: this project was not completed, however the basefile serving over ltn12 should work
local M = {}
local bindhost = 'localhost'
local bindport = 23512
local tcp_socket = nil
local socket = require("socket.socket")
local url = require("socket.url")
local ltn12 = require("socket.ltn12")
ltn12.BLOCKSIZE = 4096
local clients_read = {}
local clients_write = {}
local sinks = {}
local function init(_bindhost, _bindport)
bindhost = _bindhost
bindport = _bindport
tcp_socket = socket.tcp()
res, err = tcp_socket:bind(bindhost, bindport)
if res == nil then
print("unable to create webserver: " .. err)
end
tcp_socket:settimeout(0, 't')
tcp_socket:listen()
print("WebServer running on port "..bindport)
end
local function receiveRequest(c)
-- receive first line only
local line, err = c:receive()
if err then
-- 'timeout'
print("client.receive error: " .. tostring(err))
return
end
-- process URI's in that
for uri in string.gmatch(line, "GET /([^ ]*) HTTP/[0-9].[0-9]") do
local headers = {}
while true do
local line, err = c:receive()
if err then
-- 'timeout'
print("client.receive error: " .. tostring(err))
return nil
end
if line == '' then
break
end
local args = split(line, ':', 1)
if #args == 2 then
local key = string.lower(trim(args[1]))
local value = trim(args[2])
headers[key] = value
end
end
local uri_parsed = url.parse(uri)
return {uri = uri_parsed, headers = headers}
end
return nil
end
local function update()
-- accept new connections
while true do
local new_client = tcp_socket:accept()
if new_client then
--new_client:settimeout(0.1, 't')
table.insert(clients_read, new_client)
table.insert(clients_write, new_client)
else
break
end
end
local read, write, _ = socket.select(clients_read, clients_write, 0) -- _ = 'timeout' or nil, does not matter for our non-blocking usecase
for _, c in ipairs(read) do
if write[c] == nil then
goto continue
end
c:settimeout(0.1, 't')
local request = receiveRequest(c)
if request == nil then
goto continue
end
if request['uri'] == nil or request['uri']['path'] == nil then
print('unable to open file for reading: '.. request['uri']['path'])
goto continue
end
local fileHandle, err = io.open(request['uri']['path'], "rb")
if fileHandle == nil or err then
print('unable to open file for reading: '.. request['uri']['path'])
goto continue
end
local fileSource = ltn12.source.file(fileHandle)
local sink = socket.sink('close-when-done', c)
table.insert(sinks, {c, fileSource, sink})
::continue::
end
-- now pump the data
local newList = {}
for i, sinkData in ipairs(sinks) do
if write[sinkData[1]] then
local res, err = ltn12.pump.step(sinkData[2], sinkData[3])
print(tostring(res))
print(tostring(err))
if res then
table.insert(newList, sinkData)
end
end
end
sinks = newList
end
-- public interface
M.init = init
M.update = update
return M