Refactoring - function for sending headers is now in its own file. All errors are sent using coroutine. Some other memory usage improvements
This commit is contained in:
parent
453f38b52f
commit
ead632d131
2
Makefile
2
Makefile
@ -11,7 +11,7 @@ SPEED=9600
|
|||||||
# End of user config
|
# End of user config
|
||||||
######################################################################
|
######################################################################
|
||||||
HTTP_FILES := $(wildcard http/*)
|
HTTP_FILES := $(wildcard http/*)
|
||||||
LUA_FILES := init.lua httpserver.lua httpserver-request.lua httpserver-static.lua httpserver-error.lua
|
LUA_FILES := init.lua httpserver.lua httpserver-request.lua httpserver-static.lua httpserver-header.lua httpserver-error.lua
|
||||||
|
|
||||||
# Print usage
|
# Print usage
|
||||||
usage:
|
usage:
|
||||||
|
|||||||
@ -2,20 +2,13 @@
|
|||||||
-- Part of nodemcu-httpserver, handles sending error pages to client.
|
-- Part of nodemcu-httpserver, handles sending error pages to client.
|
||||||
-- Author: Marcos Kirsch
|
-- Author: Marcos Kirsch
|
||||||
|
|
||||||
local function getHTTPStatusString(code)
|
|
||||||
if code == 404 then return "Not Found" end
|
|
||||||
if code == 400 then return "Bad Request" end
|
|
||||||
if code == 501 then return "Not Implemented" end
|
|
||||||
return "Unknown HTTP status"
|
|
||||||
end
|
|
||||||
|
|
||||||
local function sendHeader(connection, code, codeString, mimeType)
|
|
||||||
connection:send("HTTP/1.0 " .. code .. " " .. codeString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nConnection: close\r\n\r\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
return function (connection, args)
|
return function (connection, args)
|
||||||
local errorString = getHTTPStatusString(args.code)
|
|
||||||
print("Error " .. args.code .. ": " .. errorString)
|
local function sendHeader(connection, code, errorString, mimeType)
|
||||||
sendHeader(connection, args.code, errorString, "text/html")
|
connection:send("HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nConnection: close\r\n\r\n")
|
||||||
connection:send("<html><head><title>" .. args.code .. " - " .. errorString .. "</title></head><body><h1>" .. args.code .. " - " .. errorString .. "</h1></body></html>\r\n")
|
end
|
||||||
|
|
||||||
|
print("Error " .. args.code .. ": " .. args.errorString)
|
||||||
|
sendHeader(connection, args.code, args.errorString, "text/html")
|
||||||
|
connection:send("<html><head><title>" .. args.code .. " - " .. args.errorString .. "</title></head><body><h1>" .. args.code .. " - " .. args.errorString .. "</h1></body></html>\r\n")
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,41 +2,20 @@
|
|||||||
-- Part of nodemcu-httpserver, handles sending static files to client.
|
-- Part of nodemcu-httpserver, handles sending static files to client.
|
||||||
-- Author: Marcos Kirsch
|
-- Author: Marcos Kirsch
|
||||||
|
|
||||||
local function getMimeType(ext)
|
|
||||||
local gzip = false
|
|
||||||
-- A few MIME types. Keep list short. If you need something that is missing, let's add it.
|
|
||||||
local mt = {css = "text/css", gif = "image/gif", html = "text/html", ico = "image/x-icon", jpeg = "image/jpeg", jpg = "image/jpeg", js = "application/javascript", json = "application/json", png = "image/png"}
|
|
||||||
-- add comressed flag if file ends with gz
|
|
||||||
if ext:find("%.gz$") then
|
|
||||||
ext = ext:sub(1, -4)
|
|
||||||
gzip = true
|
|
||||||
end
|
|
||||||
if mt[ext] then contentType = mt[ext] else contentType = "text/plain" end
|
|
||||||
return {contentType = contentType, gzip = gzip }
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function sendHeader(connection, code, codeString, mimeType)
|
|
||||||
connection:send("HTTP/1.0 " .. code .. " " .. codeString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType["contentType"] .. "\r\n")
|
|
||||||
if mimeType["gzip"] then
|
|
||||||
connection:send("Content-Encoding: gzip\r\n")
|
|
||||||
end
|
|
||||||
connection:send("Connection: close\r\n\r\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
return function (connection, args)
|
return function (connection, args)
|
||||||
sendHeader(connection, 200, "OK", getMimeType(args.ext))
|
dofile("httpserver-header.lc")(connection, 200, args.ext)
|
||||||
--print("Begin sending:", args.file)
|
--print("Begin sending:", args.file)
|
||||||
-- Send file in little chunks
|
-- Send file in little chunks
|
||||||
local continue = true
|
local continue = true
|
||||||
local bytesSent = 0
|
local bytesSent = 0
|
||||||
while continue do
|
while continue do
|
||||||
|
collectgarbage()
|
||||||
-- NodeMCU file API lets you open 1 file at a time.
|
-- NodeMCU file API lets you open 1 file at a time.
|
||||||
-- So we need to open, seek, close each time in order
|
-- So we need to open, seek, close each time in order
|
||||||
-- to support multiple simultaneous clients.
|
-- to support multiple simultaneous clients.
|
||||||
file.open(args.file)
|
file.open(args.file)
|
||||||
file.seek("set", bytesSent)
|
file.seek("set", bytesSent)
|
||||||
local chunk = file.read(512)
|
local chunk = file.read(256)
|
||||||
file.close()
|
file.close()
|
||||||
if chunk == nil then
|
if chunk == nil then
|
||||||
continue = false
|
continue = false
|
||||||
@ -44,6 +23,7 @@ return function (connection, args)
|
|||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
connection:send(chunk)
|
connection:send(chunk)
|
||||||
bytesSent = bytesSent + #chunk
|
bytesSent = bytesSent + #chunk
|
||||||
|
chunk = nil
|
||||||
--print("Sent" .. args.file, bytesSent)
|
--print("Sent" .. args.file, bytesSent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -15,32 +15,31 @@ return function (port)
|
|||||||
local connectionThread
|
local connectionThread
|
||||||
|
|
||||||
local function onGet(connection, uri)
|
local function onGet(connection, uri)
|
||||||
|
collectgarbage()
|
||||||
local fileServeFunction = nil
|
local fileServeFunction = nil
|
||||||
if #(uri.file) > 32 then
|
if #(uri.file) > 32 then
|
||||||
-- nodemcu-firmware cannot handle long filenames.
|
-- nodemcu-firmware cannot handle long filenames.
|
||||||
uri.args['code'] = 400
|
uri.args = {code = 400, errorString = "Bad Request"}
|
||||||
fileServeFunction = dofile("httpserver-error.lc")
|
fileServeFunction = dofile("httpserver-error.lc")
|
||||||
else
|
else
|
||||||
local fileExists = file.open(uri.file, "r")
|
local fileExists = file.open(uri.file, "r")
|
||||||
file.close()
|
file.close()
|
||||||
collectgarbage()
|
|
||||||
if not fileExists then
|
if not fileExists then
|
||||||
uri.args['code'] = 404
|
uri.args = {code = 404, errorString = "Not Found"}
|
||||||
fileServeFunction = dofile("httpserver-error.lc")
|
fileServeFunction = dofile("httpserver-error.lc")
|
||||||
elseif uri.isScript then
|
elseif uri.isScript then
|
||||||
fileServeFunction = dofile(uri.file)
|
fileServeFunction = dofile(uri.file)
|
||||||
else
|
else
|
||||||
uri.args['file'] = uri.file
|
uri.args = {file = uri.file, ext = uri.ext}
|
||||||
uri.args['ext'] = uri.ext
|
|
||||||
fileServeFunction = dofile("httpserver-static.lc")
|
fileServeFunction = dofile("httpserver-static.lc")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
connectionThread = coroutine.create(fileServeFunction)
|
connectionThread = coroutine.create(fileServeFunction)
|
||||||
--print("Thread created", connectionThread)
|
|
||||||
coroutine.resume(connectionThread, connection, uri.args)
|
coroutine.resume(connectionThread, connection, uri.args)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onReceive(connection, payload)
|
local function onReceive(connection, payload)
|
||||||
|
collectgarbage()
|
||||||
-- print(payload) -- for debugging
|
-- print(payload) -- for debugging
|
||||||
-- parse payload and decide what to serve.
|
-- parse payload and decide what to serve.
|
||||||
local req = dofile("httpserver-request.lc")(payload)
|
local req = dofile("httpserver-request.lc")(payload)
|
||||||
@ -49,25 +48,31 @@ return function (port)
|
|||||||
onGet(connection, req.uri)
|
onGet(connection, req.uri)
|
||||||
else
|
else
|
||||||
local args = {}
|
local args = {}
|
||||||
if req.methodIsValid then args['code'] = 501 else args['code'] = 400 end
|
local fileServeFunction = dofile("httpserver-error.lc")
|
||||||
dofile("httpserver-error.lc")(connection, args)
|
if req.methodIsValid then
|
||||||
|
args = {code = 501, errorString = "Not Implemented"}
|
||||||
|
else
|
||||||
|
args = {code = 400, errorString = "Bad Request"}
|
||||||
|
end
|
||||||
|
connectionThread = coroutine.create(fileServeFunction)
|
||||||
|
coroutine.resume(connectionThread, connection, args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function onSent(connection, payload)
|
local function onSent(connection, payload)
|
||||||
|
collectgarbage()
|
||||||
|
if connectionThread then
|
||||||
local connectionThreadStatus = coroutine.status(connectionThread)
|
local connectionThreadStatus = coroutine.status(connectionThread)
|
||||||
-- print (connectionThread, "status is", connectionThreadStatus)
|
|
||||||
if connectionThreadStatus == "suspended" then
|
if connectionThreadStatus == "suspended" then
|
||||||
-- Not finished sending file, resume.
|
-- Not finished sending file, resume.
|
||||||
-- print("Resume thread", connectionThread)
|
|
||||||
coroutine.resume(connectionThread)
|
coroutine.resume(connectionThread)
|
||||||
elseif connectionThreadStatus == "dead" then
|
elseif connectionThreadStatus == "dead" then
|
||||||
-- We're done sending file.
|
-- We're done sending file.
|
||||||
-- print("Done thread", connectionThread)
|
|
||||||
connection:close()
|
connection:close()
|
||||||
connectionThread = nil
|
connectionThread = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
connection:on("receive", onReceive)
|
connection:on("receive", onReceive)
|
||||||
connection:on("sent", onSent)
|
connection:on("sent", onSent)
|
||||||
|
|||||||
2
init.lua
2
init.lua
@ -43,7 +43,7 @@ local compileAndRemoveIfNeeded = function(f)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local serverFiles = {'httpserver.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-error.lua'}
|
local serverFiles = {'httpserver.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-header.lua', 'httpserver-error.lua'}
|
||||||
for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end
|
for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end
|
||||||
|
|
||||||
compileAndRemoveIfNeeded = nil
|
compileAndRemoveIfNeeded = nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user