forked from marcoskirsch/nodemcu-httpserver
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttpserver.lua
More file actions
Latest commit
165 lines (147 loc) · 6.25 KB
/
Copy pathhttpserver.lua
File metadata and controls
165 lines (147 loc) · 6.25 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
-- httpserver
-- Author: Marcos Kirsch
-- Starts web server in the specified port.
returnfunction (port)
locals=net.createServer(net.TCP, 10) -- 10 seconds client timeout
s:listen(
port,
function (connection)
-- This variable holds the thread used for sending data back to the user.
-- We do it in a separate thread because we need to yield when sending lots
-- of data in order to avoid overflowing the mcu's buffer.
localconnectionThread
localallowStatic= {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false}
localfunctionstartServing(fileServeFunction, connection, req, args)
localbufferedConnection= {}
connectionThread=coroutine.create(function(fileServeFunction, bconnection, req, args)
fileServeFunction(bconnection, req, args)
ifnotbconnection:flush() then
connection:close()
connectionThread=nil
end
end)
functionbufferedConnection:flush()
ifself.size>0then
connection:send(table.concat(self.data, ""))
self.data= {}
self.size=0
returntrue
end
returnfalse
end
functionbufferedConnection:send(payload)
locall=payload:len()
ifl+self.size>1000then
ifself:flush() then
coroutine.yield()
end
end
ifl>800then
connection:send(payload)
coroutine.yield()
else
table.insert(self.data, payload)
self.size=self.size+l
end
end
bufferedConnection.size=0
bufferedConnection.data= {}
localstatus, err=coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args)
ifnotstatusthen
print(err)
end
end
localfunctiononRequest(connection, req)
collectgarbage()
localmethod=req.method
localuri=req.uri
localfileServeFunction=nil
print("Method: " ..method);
if#(uri.file) >32then
-- nodemcu-firmware cannot handle long filenames.
uri.args= {code=400, errorString="Bad Request"}
fileServeFunction=dofile("httpserver-error.lc")
else
localfileExists=file.open(uri.file, "r")
file.close()
ifnotfileExiststhen
-- gzip check
fileExists=file.open(uri.file..".gz", "r")
file.close()
iffileExiststhen
print("gzip variant exists, serving that one")
uri.file=uri.file..".gz"
uri.isGzipped=true
end
end
ifnotfileExiststhen
uri.args= {code=404, errorString="Not Found"}
fileServeFunction=dofile("httpserver-error.lc")
elseifuri.isScriptthen
fileServeFunction=dofile(uri.file)
else
ifallowStatic[method] then
uri.args= {file=uri.file, ext=uri.ext, gzipped=uri.isGzipped}
fileServeFunction=dofile("httpserver-static.lc")
else
uri.args= {code=405, errorString="Method not supported"}
fileServeFunction=dofile("httpserver-error.lc")
end
end
end
startServing(fileServeFunction, connection, req, uri.args)
end
localfunctiononReceive(connection, payload)
collectgarbage()
localconf=dofile("httpserver-conf.lc")
localauth
localuser="Anonymous"
-- parse payload and decide what to serve.
localreq=dofile("httpserver-request.lc")(payload)
print("Requested URI: " ..req.request)
ifconf.auth.enabledthen
auth=dofile("httpserver-basicauth.lc")
user=auth.authenticate(payload) -- authenticate returns nil on failed auth
end
ifuserandreq.methodIsValidand (req.method=="GET" orreq.method=="POST" orreq.method=="PUT") then
onRequest(connection, req)
else
localargs= {}
localfileServeFunction=dofile("httpserver-error.lc")
ifnotuserthen
args= {code=401, errorString="Not Authorized", headers= {auth.authErrorHeader()}}
elseifreq.methodIsValidthen
args= {code=501, errorString="Not Implemented"}
else
args= {code=400, errorString="Bad Request"}
end
startServing(fileServeFunction, connection, req, args)
end
end
localfunctiononSent(connection, payload)
collectgarbage()
ifconnectionThreadthen
localconnectionThreadStatus=coroutine.status(connectionThread)
ifconnectionThreadStatus=="suspended" then
-- Not finished sending file, resume.
localstatus, err=coroutine.resume(connectionThread)
ifnotstatusthen
print(err)
end
elseifconnectionThreadStatus=="dead" then
-- We're done sending file.
connection:close()
connectionThread=nil
end
end
end
connection:on("receive", onReceive)
connection:on("sent", onSent)
end
)
-- false and nil evaluate as false
localip=wifi.sta.getip()
ifnotipthenip=wifi.ap.getip() end
print("nodemcu-httpserver running at http://" ..ip..":" ..port)
returns
end