Browse Source

Refactoring - function for sending headers is now in its own file. All errors are sent using coroutine. Some other memory usage improvements

Marcos Kirsch 9 years ago
parent
commit
ead632d131
5 changed files with 37 additions and 59 deletions
  1. 1 1
      Makefile
  2. 7 14
      httpserver-error.lua
  3. 4 24
      httpserver-static.lua
  4. 24 19
      httpserver.lua
  5. 1 1
      init.lua

+ 1 - 1
Makefile

@@ -11,7 +11,7 @@ SPEED=9600
 # End of user config
 ######################################################################
 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
 usage:

+ 7 - 14
httpserver-error.lua

@@ -2,20 +2,13 @@
 -- Part of nodemcu-httpserver, handles sending error pages to client.
 -- 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
+return function (connection, args)
 
-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
+   local function sendHeader(connection, code, errorString, mimeType)
+      connection:send("HTTP/1.0 " .. code .. " " .. errorString .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nConnection: close\r\n\r\n")
+   end
 
-return function (connection, args)
-   local errorString = getHTTPStatusString(args.code)
-   print("Error " .. args.code .. ": " .. errorString)
-   sendHeader(connection, args.code, errorString, "text/html")
-   connection:send("<html><head><title>" .. args.code .. " - " .. errorString .. "</title></head><body><h1>" .. args.code .. " - " .. errorString .. "</h1></body></html>\r\n")
+   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

+ 4 - 24
httpserver-static.lua

@@ -2,41 +2,20 @@
 -- Part of nodemcu-httpserver, handles sending static files to client.
 -- 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)
-   sendHeader(connection, 200, "OK", getMimeType(args.ext))
+   dofile("httpserver-header.lc")(connection, 200, args.ext)
    --print("Begin sending:", args.file)
    -- Send file in little chunks
    local continue = true
    local bytesSent = 0
    while continue do
+      collectgarbage()
       -- NodeMCU file API lets you open 1 file at a time.
       -- So we need to open, seek, close each time in order
       -- to support multiple simultaneous clients.
       file.open(args.file)
       file.seek("set", bytesSent)
-      local chunk = file.read(512)
+      local chunk = file.read(256)
       file.close()
       if chunk == nil then
          continue = false
@@ -44,6 +23,7 @@ return function (connection, args)
          coroutine.yield()
          connection:send(chunk)
          bytesSent = bytesSent + #chunk
+         chunk = nil
          --print("Sent" .. args.file, bytesSent)
       end
    end

+ 24 - 19
httpserver.lua

@@ -15,32 +15,31 @@ return function (port)
          local connectionThread
 
          local function onGet(connection, uri)
+            collectgarbage()
             local fileServeFunction = nil
             if #(uri.file) > 32 then
                -- nodemcu-firmware cannot handle long filenames.
-               uri.args['code'] = 400
+               uri.args = {code = 400, errorString = "Bad Request"}
                fileServeFunction = dofile("httpserver-error.lc")
             else
                local fileExists = file.open(uri.file, "r")
                file.close()
-               collectgarbage()
                if not fileExists then
-                  uri.args['code'] = 404
+                  uri.args = {code = 404, errorString = "Not Found"}
                   fileServeFunction = dofile("httpserver-error.lc")
                elseif uri.isScript then
                   fileServeFunction = dofile(uri.file)
                else
-                  uri.args['file'] = uri.file
-                  uri.args['ext'] = uri.ext
+                  uri.args = {file = uri.file, ext = uri.ext}
                   fileServeFunction = dofile("httpserver-static.lc")
                end
             end
             connectionThread = coroutine.create(fileServeFunction)
-            --print("Thread created", connectionThread)
             coroutine.resume(connectionThread, connection, uri.args)
          end
 
          local function onReceive(connection, payload)
+            collectgarbage()
             -- print(payload) -- for debugging
             -- parse payload and decide what to serve.
             local req = dofile("httpserver-request.lc")(payload)
@@ -49,23 +48,29 @@ return function (port)
                onGet(connection, req.uri)
             else
                local args = {}
-               if req.methodIsValid then args['code'] = 501 else args['code'] = 400 end
-               dofile("httpserver-error.lc")(connection, args)
+               local fileServeFunction = dofile("httpserver-error.lc")
+               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
 
          local function onSent(connection, payload)
-            local connectionThreadStatus = coroutine.status(connectionThread)
-            -- print (connectionThread, "status is", connectionThreadStatus)
-            if connectionThreadStatus == "suspended" then
-               -- Not finished sending file, resume.
-               -- print("Resume thread", connectionThread)
-               coroutine.resume(connectionThread)
-            elseif connectionThreadStatus == "dead" then
-               -- We're done sending file.
-               -- print("Done thread", connectionThread)
-               connection:close()
-               connectionThread = nil
+            collectgarbage()
+            if connectionThread then
+               local connectionThreadStatus = coroutine.status(connectionThread)
+               if connectionThreadStatus == "suspended" then
+                  -- Not finished sending file, resume.
+                  coroutine.resume(connectionThread)
+               elseif connectionThreadStatus == "dead" then
+                  -- We're done sending file.
+                  connection:close()
+                  connectionThread = nil
+               end
             end
          end
 

+ 1 - 1
init.lua

@@ -43,7 +43,7 @@ local compileAndRemoveIfNeeded = function(f)
    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
 
 compileAndRemoveIfNeeded = nil