Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions http/cars.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ return function (connection, req, args)
It works with three embedded images of cars, but the server crashes with four. Select the number of cars you want to see below.<br>
Whoever manages to modify nodemcu-httpserver to load all four images without crashing wins a prize!
</p>
<p>
OK I guess I win the prize, as now you can load five cars.<br>
Cheers HHHartmann
</p>
<p>
choose: <a href="?n=1">show one car</a>
<a href="?n=2">show two cars</a>
Expand Down
48 changes: 48 additions & 0 deletions httpserver-buffer.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
-- httpserver-buffer
-- Part of nodemcu-httpserver, provides a buffer that behaves like a connection object
-- that can handle multiple consecutive send() calls, and buffers small payloads up to 1400 bytes.
-- This is primarily user to collect the send requests done by the head script.
-- The owner is responsible to call getBuffer and send its result
-- Author: Gregor Hartmann

local Buffer = {}

-- parameter is the nodemcu-firmware connection
function Buffer:new()
local newInstance = {}
newInstance.size = 0
newInstance.data = {}

-- Returns true if there was any data to be sent.
function newInstance:getBuffer()
local buffer = table.concat(self.data, "")
self.data = {}
self.size = 0
return buffer
end

function newInstance:getpeer()
return "no peer"
end

function newInstance:send(payload)
local flushThreshold = 1400
if (not payload) then print("nop payload") end
local newSize = self.size + payload:len()
if newSize >= flushThreshold then
print("Buffer is full. Cutting off "..newSize-flushThreshold.." chars")
--STEP1: cut out piece from payload to complete threshold bytes in table
local pieceSize = flushThreshold - self.size
if pieceSize then
payload = payload:sub(1, pieceSize)
end
end
table.insert(self.data, payload)
self.size = self.size + #payload
end

return newInstance

end

return Buffer
30 changes: 8 additions & 22 deletions httpserver-static.lua
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
-- httpserver-static.lua
-- Part of nodemcu-httpserver, handles sending static files to client.
-- Author: Marcos Kirsch
-- Author: Gregor Hartmann

return function (connection, req, args)
dofile("httpserver-header.lc")(connection, 200, args.ext, args.isGzipped)
-- Send file in little chunks
local bytesRemaining = file.list()[args.file]
-- Chunks larger than 1024 don't work.
-- https://github.com/nodemcu/nodemcu-firmware/issues/1075
local chunkSize = 1024
local fileHandle = file.open(args.file)
while bytesRemaining > 0 do
local bytesToRead = 0
if bytesRemaining > chunkSize then bytesToRead = chunkSize else bytesToRead = bytesRemaining end
local chunk = fileHandle:read(bytesToRead)
connection:send(chunk)
bytesRemaining = bytesRemaining - #chunk
--print(args.file .. ": Sent "..#chunk.. " bytes, " .. bytesRemaining .. " to go.")
chunk = nil
collectgarbage()
end
-- print("Finished sending: ", args.file)
fileHandle:close()
fileHandle = nil
collectgarbage()

local buffer = dofile("httpserver-buffer.lc"):new()
dofile("httpserver-header.lc")(buffer, req.code or 200, args.ext, args.isGzipped)
-- Send header and return fileInfo
connection:send(buffer:getBuffer())

return { file = args.file, sent = 0}
end
38 changes: 35 additions & 3 deletions httpserver.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ return function (port)
-- We do it in a separate thread because we need to send in little chunks and wait for the onSent event
-- before we can send more, or we risk overflowing the mcu's buffer.
local connectionThread
local fileInfo

local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false}

Expand All @@ -26,6 +27,10 @@ return function (port)
end
end

local function startServingStatic(connection, req, args)
fileInfo = dofile("httpserver-static.lc")(connection, req, args)
end

local function startServing(fileServeFunction, connection, req, args)
connectionThread = coroutine.create(function(fileServeFunction, bufferedConnection, req, args)
fileServeFunction(bufferedConnection, req, args)
Expand All @@ -40,6 +45,7 @@ return function (port)

local BufferedConnectionClass = dofile("httpserver-connection.lc")
local bufferedConnection = BufferedConnectionClass:new(connection)
BufferedConnectionClass = nil
local status, err = coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args)
if not status then
log(connection, "Error: "..err)
Expand All @@ -50,7 +56,7 @@ return function (port)
end
end

local function handleRequest(connection, req)
local function handleRequest(connection, req, handleError)
collectgarbage()
local method = req.method
local uri = req.uri
Expand Down Expand Up @@ -84,7 +90,8 @@ return function (port)
else
if allowStatic[method] then
uri.args = {file = uri.file, ext = uri.ext, isGzipped = uri.isGzipped}
fileServeFunction = dofile("httpserver-static.lc")
startServingStatic(connection, req, uri.args)
return
else
uri.args = {code = 405, errorString = "Method not supported", logFunction = log}
fileServeFunction = dofile("httpserver-error.lc")
Expand All @@ -95,7 +102,7 @@ return function (port)
end

local function onReceive(connection, payload)
collectgarbage()
-- collectgarbage()
local conf = dofile("httpserver-conf.lc")
local auth
local user = "Anonymous"
Expand Down Expand Up @@ -162,6 +169,27 @@ return function (port)
connectionThread = nil
collectgarbage()
end
elseif fileInfo then
local fileSize = file.list()[fileInfo.file]
-- Chunks larger than 1024 don't work.
-- https://github.com/nodemcu/nodemcu-firmware/issues/1075
local chunkSize = 512
local fileHandle = file.open(fileInfo.file)
if fileSize > fileInfo.sent then
fileHandle:seek("set", fileInfo.sent)
local chunk = fileHandle:read(chunkSize)
fileHandle:close()
fileHandle = nil
fileInfo.sent = fileInfo.sent + #chunk
connection:send(chunk)
-- print(fileInfo.file .. ": Sent "..#chunk.. " bytes, " .. fileSize - fileInfo.sent .. " to go.")
chunk = nil
else
log(connection, "closing connetion", "Finished sending: "..fileInfo.file)
connection:close()
fileInfo = nil
end
collectgarbage()
end
end

Expand All @@ -172,6 +200,10 @@ return function (port)
connectionThread = nil
collectgarbage()
end
if fileInfo then
fileInfo = nil
collectgarbage()
end
end

connection:on("receive", onReceive)
Expand Down