Browse Source

Fix bugs for newer nodemcu-firmware: new firmware does not allow queuing multiple connection:send() operations. These changes ensure we yield after every send except the last one.

Marcos Kirsch 8 years ago
parent
commit
1b14a516aa
3 changed files with 32 additions and 24 deletions
  1. 12 8
      httpserver-error.lua
  2. 7 5
      httpserver-header.lua
  3. 13 11
      httpserver-static.lua

+ 12 - 8
httpserver-error.lua

@@ -4,16 +4,20 @@
 
 return function (connection, args)
 
-   local function sendHeader(connection, code, errorString, extraHeaders, mimeType)
-      connection:send("HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n")
-      for i, header in ipairs(extraHeaders) do
-         connection:send(header .. "\r\n")
-      end 
-      connection:send("connection: close\r\n\r\n")
+   local function getHeader(connection, code, errorString, extraHeaders, mimeType)
+      local header = "HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n"
+      for i, extraHeader in ipairs(extraHeaders) do
+         header = header .. extraHeader .. "\r\n"
+      end
+      header = header .. "connection: close\r\n\r\n"
+      return header
    end
 
    print("Error " .. args.code .. ": " .. args.errorString)
    args.headers = args.headers or {}
-   sendHeader(connection, args.code, args.errorString, args.headers, "text/html")
-   connection:send("<html><head><title>" .. args.code .. " - " .. args.errorString .. "</title></head><body><h1>" .. args.code .. " - " .. args.errorString .. "</h1></body></html>\r\n")
+   local html = getHeader(connection, args.code, args.errorString, args.headers, "text/html")
+   html = html .. "<html><head><title>" .. args.code .. " - " .. args.errorString .. "</title></head><body><h1>" .. args.code .. " - " .. args.errorString .. "</h1></body></html>\r\n"
+   connection:send(html)
+   html = nil
+
 end

+ 7 - 5
httpserver-header.lua

@@ -26,10 +26,12 @@ return function (connection, code, extension)
 
    local mimeType = getMimeType(extension)
 
-   connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\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")
+   local header = "HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType["contentType"] .. "\r\n"
+   if mimeType["gzip"] then header = header .. "Content-Encoding: gzip\r\n" end
+   header = header .. "Connection: close\r\n\r\n"
+   connection:send(header)
+   header = nil
+   coroutine.yield()
+
 end
 

+ 13 - 11
httpserver-static.lua

@@ -7,7 +7,9 @@ return function (connection, args)
    --print("Begin sending:", args.file)
    -- Send file in little chunks
    local continue = true
+   local size = file.list()[args.file]
    local bytesSent = 0
+   local chunkSize = 1024 -- @TODO: can chunkSize be larger?
    while continue do
       collectgarbage()
       -- NodeMCU file API lets you open 1 file at a time.
@@ -15,17 +17,17 @@ return function (connection, args)
       -- to support multiple simultaneous clients.
       file.open(args.file)
       file.seek("set", bytesSent)
-      local chunk = file.read(256)
+      local chunk = file.read(chunkSize)
       file.close()
-      if chunk == nil then
-         continue = false
-      else
-         coroutine.yield()
-         connection:send(chunk)
-         bytesSent = bytesSent + #chunk
-         chunk = nil
-         --print("Sent" .. args.file, bytesSent)
-      end
+
+      connection:send(chunk)
+      bytesSent = bytesSent + #chunk
+      chunk = nil
+      --print("Sent: " .. bytesSent .. " of " .. size)
+      -- nodemcu-firmware disallows queueing send operations,
+      -- so we must call coroutine.yield() after every connection:send()
+      -- The onSent() will resume us. But only yield if we aren't done yet!
+      if bytesSent == size then continue = false else coroutine.yield() end
    end
-   --print("Finished sending:", args.file)
+   --print("Finished sending: ", args.file)
 end