Browse Source

Move things around, add the real tree of httpserver as a module. Add also add uploader as a module

Godzil 6 years ago
parent
commit
c3ab446c0b

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+*.gz
+

+ 6 - 0
.gitmodules

@@ -0,0 +1,6 @@
+[submodule "httpserver"]
+	path = httpserver
+	url = https://github.com/marcoskirsch/nodemcu-httpserver.git
+[submodule "uploader"]
+	path = uploader
+	url = https://github.com/kmpm/nodemcu-uploader.git

+ 42 - 0
Makefile

@@ -0,0 +1,42 @@
+######################################################################
+# Makefile user configuration
+######################################################################
+
+# Path to nodemcu-uploader (https://github.com/kmpm/nodemcu-uploader)
+NODEMCU-UPLOADER=../nodemcu-uploader/nodemcu-uploader.py
+
+# Serial port
+PORT=/dev/ttyUSB0
+SPEED=115200
+
+NODEMCU-COMMAND=$(NODEMCU-UPLOADER) -b $(SPEED) --start_baud $(SPEED) -p $(PORT) upload
+
+######################################################################
+
+HTTP_FILES := $(wildcard http/*)
+LUA_FILES := $(wildcard *.lua)
+
+# Print usage
+usage:
+	@echo "make upload FILE:=<file>  to upload a specific file (i.e make upload FILE:=init.lua)"
+	@echo "make upload_http          to upload files to be served"
+	@echo "make upload_server        to upload the server code and init.lua"
+	@echo "make upload_all           to upload all"
+	@echo $(TEST)
+
+# Upload one files only
+upload:
+	@python $(NODEMCU-COMMAND) $(FILE)
+
+# Upload HTTP files only
+upload_http: $(HTTP_FILES)
+	@python $(NODEMCU-COMMAND) $(foreach f, $^, $(f))
+
+# Upload httpserver lua files (init and server module)
+upload_server: $(LUA_FILES)
+	@python $(NODEMCU-COMMAND) $(foreach f, $^, $(f))
+
+# Upload all
+upload_all: $(LUA_FILES) $(HTTP_FILES)
+	@python $(NODEMCU-COMMAND) $(foreach f, $^, $(f))
+

+ 0 - 34
bin/config.lua

@@ -1,34 +0,0 @@
--- Part of nodemcu-httpserver, contains static configuration for httpserver.
--- Author: Sam Dieck
-
-conf = {}
-
-conf.hostname = "NODEMCU-WEBIDE" -- DNS host name send to DHCP server (don't use underscore)
-
--- Basic Authentication Conf
-conf.auth = {}
-conf.auth.enabled = true
-conf.auth.realm = "nodemcu-httpserver" -- displayed in the login dialog users get
-conf.auth.user = "login" -- PLEASE change this
-conf.auth.password = "Passw0rd" -- PLEASE change this
-
--- WiFi configuration
-conf.wifi = {}
--- wifi.STATION (join a WiFi network)
--- wifi.SOFTAP (create a WiFi network)
--- wifi.STATIONAP (STATION + SOFTAP)
-conf.wifi.mode = wifi.SOFTAP -- default: SOFTAP (avoid try to connect an invalid AP)
-
--- STATION config
---conf.wifi.stassid = "YourSSID" -- Name of the WiFi network you want to join
---conf.wifi.stapwd = "PleaseInputYourPasswordHere" -- Password for the WiFi network
-
--- SOFTAP config
-conf.wifi.ap = {}
-conf.wifi.ap.ssid = "ESP-"..node.chipid() -- Name of the SSID you want to create
-conf.wifi.ap.pwd = "Pass"..node.chipid() -- PLEASE change this (at least 8 characters)
-
-conf.wifi.apip = {}
-conf.wifi.apip.ip = "192.168.111.1"
-conf.wifi.apip.netmask = "255.255.255.0"
-conf.wifi.apip.gateway = "0.0.0.0" -- avoid mobile cannot access internet issue

+ 0 - 29
bin/httpserver-basicauth.lua

@@ -1,29 +0,0 @@
--- httpserver-basicauth.lua
--- Part of nodemcu-httpserver, authenticates a user using http basic auth.
--- Author: Sam Dieck
-
-basicAuth = {}
-
--- Parse basic auth http header.
--- Returns the username if header contains valid credentials,
--- nil otherwise.
-function basicAuth.authenticate(header)
-   local credentials_enc = header:match("Authorization: Basic ([A-Za-z0-9+/=]+)")
-   if not credentials_enc then
-      return nil
-   end
-   local credentials = encoder.fromBase64(credentials_enc)
-   local user, pwd = credentials:match("^(.*):(.*)$")
-   if user ~= conf.auth.user or pwd ~= conf.auth.password then
-      print("httpserver-basicauth: User \"" .. user .. "\": Access denied.")
-      return nil
-   end
-   print("httpserver-basicauth: User \"" .. user .. "\": Authenticated.")
-   return user
-end
-
-function basicAuth.authErrorHeader()
-   return "WWW-Authenticate: Basic realm=\"" .. conf.auth.realm .. "\""
-end
-
-return basicAuth

+ 0 - 67
bin/httpserver-connection.lua

@@ -1,67 +0,0 @@
--- httpserver-connection
--- Part of nodemcu-httpserver, provides a buffered connection object that can handle multiple
--- consecutive send() calls, and buffers small payloads to send once they get big.
--- For this to work, it must be used from a coroutine and owner is responsible for the final
--- flush() and for closing the connection.
--- Author: Philip Gladstone, Marcos Kirsch
-
-BufferedConnection = {}
-
--- parameter is the nodemcu-firmware connection
-function BufferedConnection:new(connection)
-   local newInstance = {}
-   newInstance.connection = connection
-   newInstance.size = 0
-   newInstance.data = {}
-
-   function newInstance:flush()
-      if self.size > 0 then
-         self.connection:send(table.concat(self.data, ""))
-         self.data = {}
-         self.size = 0
-         return true
-      end
-      return false
-   end
-
-   function newInstance:send(payload)
-      local flushthreshold = 1400
-
-      local newsize = self.size + payload:len()
-      while newsize > flushthreshold do
-          --STEP1: cut out piece from payload to complete threshold bytes in table
-          local piecesize = flushthreshold - self.size
-          local piece = payload:sub(1, piecesize)
-          payload = payload:sub(piecesize + 1, -1)
-          --STEP2: insert piece into table
-          table.insert(self.data, piece)
-          self.size = self.size + piecesize --size should be same as flushthreshold
-          --STEP3: flush entire table
-          if self:flush() then
-              coroutine.yield()
-          end
-          --at this point, size should be 0, because the table was just flushed
-          newsize = self.size + payload:len()
-      end
-            
-      --at this point, whatever is left in payload should be <= flushthreshold
-      local plen = payload:len()
-      if plen == flushthreshold then
-          --case 1: what is left in payload is exactly flushthreshold bytes (boundary case), so flush it
-          table.insert(self.data, payload)
-          self.size = self.size + plen
-          if self:flush() then
-              coroutine.yield()
-          end
-      elseif payload:len() then
-          --case 2: what is left in payload is less than flushthreshold, so just leave it in the table
-          table.insert(self.data, payload)
-          self.size = self.size + plen
-      --else, case 3: nothing left in payload, so do nothing
-      end
-   end
-
-   return newInstance
-end
-
-return BufferedConnection

+ 0 - 22
bin/httpserver-error.lua

@@ -1,22 +0,0 @@
--- httpserver-error.lua
--- Part of nodemcu-httpserver, handles sending error pages to client.
--- Author: Marcos Kirsch
-
-return function (connection, req, args)
-
-   -- @TODO: would be nice to use httpserver-header.lua
-   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 {}
-   connection:send(getHeader(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")
-
-end

+ 0 - 31
bin/httpserver-header.lua

@@ -1,31 +0,0 @@
--- httpserver-header.lua
--- Part of nodemcu-httpserver, knows how to send an HTTP header.
--- Author: Marcos Kirsch
-
-return function (connection, code, extension, isGzipped)
-
-   local function getHTTPStatusString(code)
-      local codez = {[200]="OK", [304]="Not Modified", [400]="Bad Request", [404]="Not Found", [500]="Internal Server Error",}
-      local myResult = codez[code]
-      -- enforce returning valid http codes all the way throughout?
-      if myResult then return myResult else return "Not Implemented" end
-   end
-
-   local function getMimeType(ext)
-      -- 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", xml = "text/xml", svg = "image/svg+xml"}
-      if mt[ext] then return mt[ext] else return "text/plain" end
-   end
-
-   local mimeType = getMimeType(extension)
-
-   connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\n")
-   if isGzipped then
-      connection:send("Cache-Control: max-age=2592000\r\nContent-Encoding: gzip\r\n")
-      --TODO: handle Last-Modified for each file instead of use a fixed dummy date time
-      connection:send("Last-Modified: Fri, 01 Jan 2016 00:00:00 GMT\r\n")
-   else
-      connection:send("Cache-Control: private, no-store\r\n")
-   end
-   connection:send("Connection: close\r\n\r\n")
-end

+ 0 - 127
bin/httpserver-request.lua

@@ -1,127 +0,0 @@
--- httpserver-request
--- Part of nodemcu-httpserver, parses incoming client requests.
--- Author: Marcos Kirsch
-
-local function validateMethod(method)
-   local httpMethods = {GET=true, HEAD=true, POST=true, PUT=true, DELETE=true, TRACE=true, OPTIONS=true, CONNECT=true, PATCH=true}
-   -- default for non-existent attributes returns nil, which evaluates to false
-   return httpMethods[method]
-end
-
-local function uriToFilename(uri)
-   return string.sub(uri, 2, -1)
-end
-
-local function hex_to_char(x)
-  return string.char(tonumber(x, 16))
-end
-
-local function uri_decode(input)
-  return input:gsub("%+", " "):gsub("%%(%x%x)", hex_to_char)
-end
-
-local function parseArgs(args)
-   local r = {}; i=1
-   if args == nil or args == "" then return r end
-   for arg in string.gmatch(args, "([^&]+)") do
-      local name, value = string.match(arg, "(.*)=(.*)")
-      if name ~= nil then r[name] = uri_decode(value) end
-      i = i + 1
-   end
-   return r
-end
-
-local function parseFormData(body)
-   local data = {}
-   --print("Parsing Form Data")
-   for kv in body.gmatch(body, "%s*&?([^=]+=[^&]+)") do
-      local key, value = string.match(kv, "(.*)=(.*)")
-      --print("Parsed: " .. key .. " => " .. value)
-      data[key] = uri_decode(value)
-   end
-   return data
-end
-
-local function isCheckModifiedRequest(payload)
-   return function ()
-      local checkResult = (string.find(payload, 'If%-Modified%-Since: ') ~= nil)
-      return checkResult
-   end
-end
-
-local function getRequestData(payload)
-   local requestData
-   return function ()
-      --print("Getting Request Data")
-      if requestData then
-         return requestData
-      else
-         --print("payload = [" .. payload .. "]")
-         local mimeType = string.match(payload, "Content%-Type: ([%w/-]+)")
-         local bodyStart = payload:find("\r\n\r\n", 1, true)
-         local body = payload:sub(bodyStart, #payload)
-         payload = nil
-         collectgarbage()
-         --print("mimeType = [" .. mimeType .. "]")
-         --print("bodyStart = [" .. bodyStart .. "]")
-         --print("body = [" .. body .. "]")
-         if mimeType == "application/json" then
-            --print("JSON: " .. body)
-            requestData = cjson.decode(body)
-         elseif mimeType == "application/x-www-form-urlencoded" then
-            requestData = parseFormData(body)
-         else
-            requestData = {}
-         end
-         return requestData
-      end
-   end
-end
-
-local function parseUri(uri)
-   local r = {}
-   local filename
-   local ext
-   local fullExt = {}
-
-   if uri == nil then return r end
-   if uri == "/" then uri = "/index.html" end
-   questionMarkPos, b, c, d, e, f = uri:find("?")
-   if questionMarkPos == nil then
-      r.file = uri:sub(1, questionMarkPos)
-      r.args = {}
-   else
-      r.file = uri:sub(1, questionMarkPos - 1)
-      r.args = parseArgs(uri:sub(questionMarkPos+1, #uri))
-   end
-   filename = r.file
-   while filename:match("%.") do
-      filename,ext = filename:match("(.+)%.(.+)")
-      table.insert(fullExt,1,ext)
-   end
-   if #fullExt > 1 and fullExt[#fullExt] == 'gz' then
-      r.ext = fullExt[#fullExt-1]
-      r.isGzipped = true
-   elseif #fullExt >= 1 then
-      r.ext = fullExt[#fullExt]
-   end
-   r.isScript = r.ext == "lua" or r.ext == "lc"
-   r.file = uriToFilename(r.file)
-   return r
-end
-
--- Parses the client's request. Returns a dictionary containing pretty much everything
--- the server needs to know about the uri.
-return function (request)
-   --print("Request: \n", request)
-   local e = request:find("\r\n", 1, true)
-   if not e then return nil end
-   local line = request:sub(1, e - 1)
-   local r = {}
-   _, i, r.method, r.request = line:find("^([A-Z]+) (.-) HTTP/[1-9]+.[0-9]+$")
-   r.methodIsValid = validateMethod(r.method)
-   r.uri = parseUri(r.request)
-   r.isCheckModifiedRequest = isCheckModifiedRequest(request)
-   r.getRequestData = getRequestData(request)
-   return r
-end

+ 0 - 39
bin/httpserver-static.lua

@@ -1,39 +0,0 @@
--- httpserver-static.lua
--- Part of nodemcu-httpserver, handles sending static files to client.
--- Author: Marcos Kirsch
-
-return function (connection, req, args)
-   --print("Begin sending:", args.file)
-   --print("node.heap(): ", node.heap())
-   if args.isGzipped and req.isCheckModifiedRequest() then
-      -- todo: really check if file updated
-      dofile("httpserver-header.lc")(connection, 304, args.ext, args.isGzipped)
-   else
-      dofile("httpserver-header.lc")(connection, 200, args.ext, args.isGzipped)
-      -- Send file in little chunks
-      local continue = true
-      local size = file.list()[args.file]
-      local bytesSent = 0
-      -- Chunks larger than 1024 don't work.
-      -- https://github.com/nodemcu/nodemcu-firmware/issues/1075
-      local chunkSize = 1024
-      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(chunkSize)
-         file.close()
-
-         connection:send(chunk)
-         bytesSent = bytesSent + #chunk
-         chunk = nil
-         --print("Sent: " .. bytesSent .. " of " .. size)
-         if bytesSent == size then continue = false end
-      end
-      --print("Finished sending: ", args.file)
-   end
-end

+ 0 - 135
bin/httpserver-websocket.lua

@@ -1,135 +0,0 @@
---rewrite from https://github.com/creationix/nodemcu-webide
-
-local function decode(chunk)
-  if #chunk < 2 then return end
-  local second = string.byte(chunk, 2)
-  local len = bit.band(second, 0x7f)
-  local offset
-  if len == 126 then
-    if #chunk < 4 then return end
-    len = bit.bor(
-      bit.lshift(string.byte(chunk, 3), 8),
-      string.byte(chunk, 4))
-    offset = 4
-  elseif len == 127 then
-    if #chunk < 10 then return end
-    len = bit.bor(
-      -- Ignore lengths longer than 32bit
-      bit.lshift(string.byte(chunk, 7), 24),
-      bit.lshift(string.byte(chunk, 8), 16),
-      bit.lshift(string.byte(chunk, 9), 8),
-      string.byte(chunk, 10))
-    offset = 10
-  else
-    offset = 2
-  end
-  local mask = bit.band(second, 0x80) > 0
-  if mask then
-    offset = offset + 4
-  end
-  if #chunk < offset + len then return end
-
-  local first = string.byte(chunk, 1)
-  local payload = string.sub(chunk, offset + 1, offset + len)
-  assert(#payload == len, "Length mismatch")
-  if mask then
-    payload = crypto.mask(payload, string.sub(chunk, offset - 3, offset))
-  end
-  local extra = string.sub(chunk, offset + len + 1)
-  local opcode = bit.band(first, 0xf)
-  return extra, payload, opcode
-end
-
-local function encode(payload, opcode)
-  opcode = opcode or 2
-  assert(type(opcode) == "number", "opcode must be number")
-  assert(type(payload) == "string", "payload must be string")
-  local len = #payload
-  local head = string.char(
-    bit.bor(0x80, opcode),
-    bit.bor(len < 126 and len or len < 0x10000 and 126 or 127)
-  )
-  if len >= 0x10000 then
-    head = head .. string.char(
-    0,0,0,0, -- 32 bit length is plenty, assume zero for rest
-    bit.band(bit.rshift(len, 24), 0xff),
-    bit.band(bit.rshift(len, 16), 0xff),
-    bit.band(bit.rshift(len, 8), 0xff),
-    bit.band(len, 0xff)
-  )
-  elseif len >= 126 then
-    head = head .. string.char(bit.band(bit.rshift(len, 8), 0xff), bit.band(len, 0xff))
-  end
-  return head .. payload
-end
-
-local guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-local function acceptKey(key)
-  return crypto.toBase64(crypto.hash("sha1", key .. guid))
-end
-
-return function (connection, payload)
-  local buffer = false
-  local socket = {}
-  local queue = {}
-  local waiting = false
-  local function onSend()
-    if queue[1] then
-      local data = table.remove(queue, 1)
-      return connection:send(data, onSend)
-    end
-    waiting = false
-  end
-  function socket.send(...)
-    local data = encode(...)
-    if not waiting then
-      waiting = true
-      connection:send(data, onSend)
-    else
-      queue[#queue + 1] = data
-    end
-    collectgarbage()
-    print(node.heap())
-  end
-
-  connection:on("receive", function(_, chunk)
-    if buffer then
-      buffer = buffer .. chunk
-      while true do
-        local extra, payload, opcode = decode(buffer)
-        if not extra then return end
-        buffer = extra
-        socket.onmessage(payload, opcode)
-      end
-    end
-  end)
-
-  connection:on("sent", function(_, _)
-    if socket.onsent ~= nil then
-      socket.onsent()
-    end
-  end)
-
-  connection:on("disconnection", function(_, _)
-    if socket.onclose ~= nil then
-      socket.onclose()
-    end
-  end)
-
-  local req = dofile("httpserver-request.lc")(payload)
-  local key = payload:match("Sec%-WebSocket%-Key: ([A-Za-z0-9+/=]+)")
-  local fileExists = file.open(req.uri.file, "r")
-  file.close()
-  if req.method == "GET" and key and fileExists then
-    connection:send(
-      "HTTP/1.1 101 Switching Protocols\r\n" ..
-      "Upgrade: websocket\r\nConnection: Upgrade\r\n" ..
-      "Sec-WebSocket-Accept: " .. acceptKey(key) .. "\r\n\r\n",
-      function () dofile(req.uri.file)(socket) end)
-    buffer = ""
-  else
-    connection:send(
-      "HTTP/1.1 404 Not Found\r\nConnection: Close\r\n\r\n",
-      connection.close)
-  end
-end

+ 0 - 171
bin/httpserver.lua

@@ -1,171 +0,0 @@
--- httpserver
--- Author: Marcos Kirsch
-
--- Starts web server in the specified port.
-return function (port)
-
-   local s = net.createServer(net.TCP, 10) -- 10 seconds client timeout
-   s:listen(
-      port,
-      function (connection)
-
-         -- This variable holds the thread (actually a Lua coroutine) used for sending data back to the user.
-         -- 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 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)
-            connectionThread = coroutine.create(function(fileServeFunction, bufferedConnection, req, args)
-               fileServeFunction(bufferedConnection, req, args)
-               -- The bufferedConnection may still hold some data that hasn't been sent. Flush it before closing.
-               if not bufferedConnection:flush() then
-                  connection:close()
-                  connectionThread = nil
-               end
-            end)
-
-            local BufferedConnectionClass = dofile("httpserver-connection.lc")
-            local bufferedConnection = BufferedConnectionClass:new(connection)
-            local status, err = coroutine.resume(connectionThread, fileServeFunction, bufferedConnection, req, args)
-            if not status then
-               print("Error: ", err)
-            end
-         end
-
-         local function handleRequest(connection, req)
-            collectgarbage()
-            local method = req.method
-            local uri = req.uri
-            local fileServeFunction = nil
-
-            if #(uri.file) > 32 then
-               -- nodemcu-firmware cannot handle long filenames.
-               uri.args = {code = 400, errorString = "Bad Request"}
-               fileServeFunction = dofile("httpserver-error.lc")
-            else
-               local fileExists = file.open(uri.file, "r")
-               file.close()
-
-               if not fileExists then
-                  -- gzip check
-                  fileExists = file.open(uri.file .. ".gz", "r")
-                  file.close()
-
-                  if fileExists then
-                     --print("gzip variant exists, serving that one")
-                     uri.file = uri.file .. ".gz"
-                     uri.isGzipped = true
-                  end
-               end
-
-               if not fileExists then
-                  uri.args = {code = 404, errorString = "Not Found"}
-                  fileServeFunction = dofile("httpserver-error.lc")
-               elseif uri.isScript then
-                  fileServeFunction = dofile(uri.file)
-               else
-                  if allowStatic[method] then
-                     uri.args = {file = uri.file, ext = uri.ext, isGzipped = uri.isGzipped}
-                     fileServeFunction = dofile("httpserver-static.lc")
-                  else
-                     uri.args = {code = 405, errorString = "Method not supported"}
-                     fileServeFunction = dofile("httpserver-error.lc")
-                  end
-               end
-            end
-            startServing(fileServeFunction, connection, req, uri.args)
-         end
-
-         local function onReceive(connection, payload)
-            --websocket
-            if payload:find("Upgrade: websocket") then
-              dofile('httpserver-websocket.lc')(connection, payload)
-              return
-            end
-
-            collectgarbage()
-            local auth
-            local user = "Anonymous"
-
-            -- as suggest by anyn99 (https://github.com/marcoskirsch/nodemcu-httpserver/issues/36#issuecomment-167442461)
-            -- Some browsers send the POST data in multiple chunks.
-            -- Collect data packets until the size of HTTP body meets the Content-Length stated in header
-            if payload:find("Content%-Length:") or bBodyMissing then
-               if fullPayload then fullPayload = fullPayload .. payload else fullPayload = payload end
-               if (tonumber(string.match(fullPayload, "%d+", fullPayload:find("Content%-Length:")+16)) > #fullPayload:sub(fullPayload:find("\r\n\r\n", 1, true)+4, #fullPayload)) then
-                  bBodyMissing = true
-                  return
-               else
-                  --print("HTTP packet assembled! size: "..#fullPayload)
-                  payload = fullPayload
-                  fullPayload, bBodyMissing = nil
-               end
-            end
-            collectgarbage()
-
-            -- parse payload and decide what to serve.
-            local req = dofile("httpserver-request.lc")(payload)
-            print(req.method .. ": " .. req.request)
-            if conf.auth.enabled then
-               auth = dofile("httpserver-basicauth.lc")
-               user = auth.authenticate(payload) -- authenticate returns nil on failed auth
-               req.user = user -- store authenticated user to req table
-            end
-
-            if user and req.methodIsValid and (req.method == "GET" or req.method == "POST" or req.method == "PUT") then
-               handleRequest(connection, req)
-            else
-               local args = {}
-               local fileServeFunction = dofile("httpserver-error.lc")
-               if not user then
-                  args = {code = 401, errorString = "Not Authorized", headers = {auth.authErrorHeader()}}
-               elseif req.methodIsValid then
-                  args = {code = 501, errorString = "Not Implemented"}
-               else
-                  args = {code = 400, errorString = "Bad Request"}
-               end
-               startServing(fileServeFunction, connection, req, args)
-            end
-         end
-
-         local function onSent(connection, payload)
-            collectgarbage()
-            if connectionThread then
-               local connectionThreadStatus = coroutine.status(connectionThread)
-               if connectionThreadStatus == "suspended" then
-                  -- Not finished sending file, resume.
-                  local status, err = coroutine.resume(connectionThread)
-                  if not status then
-                     print(err)
-                  end
-               elseif connectionThreadStatus == "dead" then
-                  -- We're done sending file.
-                  connection:close()
-                  connectionThread = nil
-               end
-            end
-         end
-
-         local function onDisconnect(connection, payload)
-            if connectionThread then
-               connectionThread = nil
-               collectgarbage()
-            end
-         end
-
-         connection:on("receive", onReceive)
-         connection:on("sent", onSent)
-         connection:on("disconnection", onDisconnect)
-
-      end
-   )
-   -- false and nil evaluate as false
-   local ip = wifi.sta.getip()
-   if not ip then ip = wifi.ap.getip() end
-   if not ip then ip = "unknown IP" end
-   print("nodemcu-httpserver running at http://" .. ip .. ":" ..  port)
-   return s
-
-end

+ 0 - 115
bin/init.lua

@@ -1,115 +0,0 @@
--- init adc
-if adc.force_init_mode(adc.INIT_VDD33) then
-  node.restart()
-end
-
--- init and clear ws2812
-ws2812.init()
-ws2812.write(string.char(0):rep(3096))
-
--- init config
-dofile('config.lua')
-
--- init WiFi
--- Tell the chip to connect to the access point
-wifi.setmode(conf.wifi.mode)
-print('set (mode='..wifi.getmode()..')')
-
-if (conf.wifi.mode == wifi.SOFTAP) or (conf.wifi.mode == wifi.STATIONAP) then
-    print('AP MAC: ', wifi.ap.getmac())
-    wifi.ap.config(conf.wifi.ap)
-    wifi.ap.setip(conf.wifi.apip)
-end
-if (conf.wifi.mode == wifi.STATION) or (conf.wifi.mode == wifi.STATIONAP) then
-    print('Client MAC: ', wifi.sta.getmac())
-    wifi.sta.sethostname(conf.hostname)
-    wifi.sta.config(conf.wifi.stassid, conf.wifi.stapwd, 1)
-end
-collectgarbage()
-
--- show system info
-print('chip: ',node.chipid())
-print('heap: ',node.heap())
-
--- Compile server code and remove original .lua files.
--- This only happens the first time afer the .lua files are uploaded.
-local compileAndRemoveIfNeeded = function(f)
-   if file.open(f) then
-      file.close()
-      print('Compiling:', f)
-      node.compile(f)
-      file.remove(f)
-      collectgarbage()
-   end
-end
-
-local serverFiles = {
-   'httpserver.lua',
-   'httpserver-basicauth.lua',
-   'httpserver-connection.lua',
-   'httpserver-error.lua',
-   'httpserver-header.lua',
-   'httpserver-request.lua',
-   'httpserver-static.lua',
-   'httpserver-websocket.lua',
-   'file-api.lua'
-}
-for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end
-
-compileAndRemoveIfNeeded = nil
-serverFiles = nil
-i = nil
-f = nil
-collectgarbage()
-
--- pre-compile other lua files
-local l, f, s
-l = file.list();
-for f, s in pairs(l) do
-  if ((string.sub(f, -4) == '.lua') and (f ~= 'config.lua') and (f ~= 'init.lua')) then
-    print('Pre-compiling:', f)
-    node.compile(f)
-    collectgarbage()
-  end
-end
-l = nil
-f = nil
-s = nil
-collectgarbage()
-
--- check and show STATION mode obtained IP
-if (wifi.getmode() == wifi.STATION) or (wifi.getmode() == wifi.STATIONAP) then
-    local joinCounter = 0
-    local joinMaxAttempts = 5
-    tmr.alarm(0, 3000, 1, function()
-       local ip = wifi.sta.getip()
-       if ip == nil and joinCounter < joinMaxAttempts then
-          print('Connecting to WiFi Access Point ...')
-          joinCounter = joinCounter + 1
-       else
-          if joinCounter == joinMaxAttempts then
-             print('Failed to connect to WiFi Access Point.')
-             print('Fall back to SOFTAP.')
-             wifi.setmode(wifi.SOFTAP)
-             wifi.ap.config(conf.wifi.ap)
-             wifi.ap.setip(conf.wifi.apip)
-          else
-             print('IP: ',ip)
-             mdns.register(conf.hostname, { description="NodeMCU WebIDE", service="http", port=80, location='In your ESP board' })
-             sntp.sync('pool.ntp.org')
-          end
-          tmr.stop(0)
-          joinCounter = nil
-          joinMaxAttempts = nil
-          collectgarbage()
-       end
-    end)
-end
-
--- start the nodemcu-httpserver in port 80
-if (not not wifi.sta.getip()) or (not not wifi.ap.getip()) then
-    dofile("httpserver.lc")(80)
-    collectgarbage()
-end
-
---dofile('led-stick.lc')()

+ 0 - 0
bin/hello-world.lua → examples/hello-world.lua


+ 0 - 0
bin/led-matrix.html → examples/led-matrix.html


+ 0 - 0
bin/led-matrix.lua → examples/led-matrix.lua


+ 0 - 0
bin/led-stick.html → examples/led-stick.html


+ 0 - 0
bin/led-stick.lua → examples/led-stick.lua


+ 0 - 0
bin/led-text.html → examples/led-text.html


+ 0 - 0
bin/led-text.lua → examples/led-text.lua


+ 0 - 0
bin/robot.lua → examples/robot.lua


+ 0 - 0
bin/system-info.lua → examples/system-info.lua


+ 0 - 0
bin/ws-echo.html → examples/ws-echo.html


+ 0 - 0
bin/ws-echo.lua → examples/ws-echo.lua


+ 0 - 0
bin/ws-led.html → examples/ws-led.html


+ 0 - 0
bin/ws-led.lua → examples/ws-led.lua


+ 0 - 0
bin/ws-robot.html → examples/ws-robot.html


+ 0 - 0
bin/ws-robot.lua → examples/ws-robot.lua


+ 1 - 0
httpserver

@@ -0,0 +1 @@
+Subproject commit 0f852665eca74f744954b9fff56cb9d2e8d6049a

+ 0 - 0
bin/file-api.lua → src/file-api.lua


+ 1 - 0
uploader

@@ -0,0 +1 @@
+Subproject commit 70f5ae5b5dbf08b66de8b23e0b1af7363f1d0072