From b4a2d02431213d82da56c3c80351b0e96219f5a8 Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Sun, 22 Nov 2015 13:39:03 -0500 Subject: [PATCH] Fix the problem with the more modern SDK only allowing one outstanding connection:send at a time. Long and short of it, don't use coroutine.yield any more when serving content. --- README.md | 5 ----- http/file_list.lua | 3 --- httpserver-static.lua | 1 - httpserver.lua | 43 ++++++++++++++++++++++++++++++++++++------- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index aadf9c5..8162cf3 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,6 @@ A (very) simple web server written in Lua for the ESP8266 running the NodeMCU fi For example, if the client requests _http://2.2.2.2/foo.lua?color=red_ then the server will execute the function in your Lua script _foo.lua_ and pass in _connection_ and _args_, where _args.color = "red"_. - If you are going to be sending lots (as in over a KB) of data in your script, you should yield the thread/coroutine - every now and then in order to avoid overflowing the send buffer in the microcontroller. Use: - - coroutine.yield() - Look at the included example scripts for more ideas. ### Example: Garage door opener diff --git a/http/file_list.lua b/http/file_list.lua index 9e92a23..6879900 100644 --- a/http/file_list.lua +++ b/http/file_list.lua @@ -2,7 +2,6 @@ return function (connection, req, args) connection:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nCache-Control: private, no-store\r\n\r\n") connection:send('Server File Listing') connection:send('') - coroutine.yield() connection:send('

Server File Listing

') local remaining, used, total=file.fsinfo() @@ -20,8 +19,6 @@ return function (connection, req, args) if isHttpFile then local url = string.match(name, ".*/(.*)") connection:send('
  • ' .. url .. " (" .. size .. " bytes)
  • \n") - -- this list could be very long, so we'll yield in order to avoid overflowing the send buffer. - coroutine.yield() end end connection:send("\n") diff --git a/httpserver-static.lua b/httpserver-static.lua index 5a57bd5..d7cb86f 100644 --- a/httpserver-static.lua +++ b/httpserver-static.lua @@ -20,7 +20,6 @@ return function (connection, req, args) if chunk == nil then continue = false else - coroutine.yield() connection:send(chunk) bytesSent = bytesSent + #chunk chunk = nil diff --git a/httpserver.lua b/httpserver.lua index 1f8f818..e0970c6 100644 --- a/httpserver.lua +++ b/httpserver.lua @@ -13,9 +13,37 @@ return function (port) -- 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. local connectionThread - + local allowStatic = {GET=true, HEAD=true, POST=false, PUT=false, DELETE=false, TRACE=false, OPTIONS=false, CONNECT=false, PATCH=false} + local function startServing(fileServeFunction, connection, req, args) + local bufferedConnection = {} + connectionThread = coroutine.create(function(fileServeFunction, connection, req, args) + fileServeFunction(connection, req, args) + connection:flush() + end) + function bufferedConnection:flush() + connection:send(table.concat(self.data, "")) + self.data = {} + self.size = 0 + end + function bufferedConnection:send(payload) + local l = payload:len() + if l + self.size > 1400 then + self:flush() + coroutine.yield() + end + table.insert(self.data, payload) + self.size = self.size + l + end + bufferedConnection.size = 0 + bufferedConnection.data = {} + local status, err = coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args) + if not status then + print(err) + end + end + local function onRequest(connection, req) collectgarbage() local method = req.method @@ -59,8 +87,7 @@ return function (port) end end end - connectionThread = coroutine.create(fileServeFunction) - coroutine.resume(connectionThread, connection, req, uri.args) + startServing(fileServeFunction, connection, req, uri.args) end local function onReceive(connection, payload) @@ -89,18 +116,20 @@ return function (port) else args = {code = 400, errorString = "Bad Request"} end - connectionThread = coroutine.create(fileServeFunction) - coroutine.resume(connectionThread, connection, req, args) + startServing(fileServeFunction, connection, req, args) end end local function onSent(connection, payload) collectgarbage() if connectionThread then - local connectionThreadStatus = coroutine.status(connectionThread) + local connectionThreadStatus = coroutine.status(connectionThread) if connectionThreadStatus == "suspended" then -- Not finished sending file, resume. - coroutine.resume(connectionThread) + local status, err = coroutine.resume(connectionThread) + if not status then + print(err) + end elseif connectionThreadStatus == "dead" then -- We're done sending file. connection:close()