From 67e5ff5c203a58eaae52bd986c95d14f4e63c271 Mon Sep 17 00:00:00 2001 From: Balazs Hollosi Date: Fri, 27 May 2016 01:12:57 +0200 Subject: [PATCH 1/3] typo fix at Cache-Control header, new http response code: 500 / internal server error --- httpserver-header.lua | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/httpserver-header.lua b/httpserver-header.lua index d218722..9e52784 100644 --- a/httpserver-header.lua +++ b/httpserver-header.lua @@ -2,28 +2,27 @@ -- Part of nodemcu-httpserver, knows how to send an HTTP header. -- Author: Marcos Kirsch -return function (connection, code, extension, isGzipped) +return function(connection, code, extension, isGzipped) - local function getHTTPStatusString(code) - local codez = {[200]="OK", [400]="Bad Request", [404]="Not Found",} - 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 getHTTPStatusString(code) + local codez = { [200] = "OK", [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"} - if mt[ext] then return mt[ext] else return "text/plain" 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" } + 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\nnCache-Control: private, no-store\r\n") - if isGzipped then - connection:send("Cache-Control: max-age=2592000\r\nContent-Encoding: gzip\r\n") - end - connection:send("Connection: close\r\n\r\n") + local mimeType = getMimeType(extension) + connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nCache-Control: private, no-store\r\n") + if isGzipped then + connection:send("Cache-Control: max-age=2592000\r\nContent-Encoding: gzip\r\n") + end + connection:send("Connection: close\r\n\r\n") end From 2b75289dfc22955764e5f6069a8c94ebeb31f82e Mon Sep 17 00:00:00 2001 From: Balazs Hollosi Date: Fri, 27 May 2016 01:35:10 +0200 Subject: [PATCH 2/3] typo fix at Cache-Control header, new http response code: 500 / internal server error --- httpserver-header.lua | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/httpserver-header.lua b/httpserver-header.lua index 9e52784..9c52b8c 100644 --- a/httpserver-header.lua +++ b/httpserver-header.lua @@ -4,25 +4,25 @@ return function(connection, code, extension, isGzipped) - local function getHTTPStatusString(code) - local codez = { [200] = "OK", [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 getHTTPStatusString(code) + local codez = { [200] = "OK", [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" } - if mt[ext] then return mt[ext] else return "text/plain" 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" } + if mt[ext] then return mt[ext] else return "text/plain" end + end - local mimeType = getMimeType(extension) + local mimeType = getMimeType(extension) - connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nCache-Control: private, no-store\r\n") - if isGzipped then - connection:send("Cache-Control: max-age=2592000\r\nContent-Encoding: gzip\r\n") - end - connection:send("Connection: close\r\n\r\n") + connection:send("HTTP/1.0 " .. code .. " " .. getHTTPStatusString(code) .. "\r\nServer: nodemcu-httpserver\r\nContent-Type: " .. mimeType .. "\r\nCache-Control: private, no-store\r\n") + if isGzipped then + connection:send("Cache-Control: max-age=2592000\r\nContent-Encoding: gzip\r\n") + end + connection:send("Connection: close\r\n\r\n") end From bc3ffffa0c28ddbae029bfa83c9d0fcc81116528 Mon Sep 17 00:00:00 2001 From: ATAMAH Date: Mon, 23 Jan 2017 12:36:46 +0300 Subject: [PATCH 3/3] Upload form for nodemcu-httpserver Now you can update your files in /http directory of your tiny webserver over Wi-Fi! Drag&drop or browse one or multiple files. List uploaded files. Delete files. Automatically rename files to http/(filename) Automatically compile .lua files. Shows total/used memory. You must compile upload.lua file! Have some bugs but works pretty well even for uploading lot of files. --- http/index.html | 1 + http/upload.full.html | 568 ++++++++++++++++++++++++++++++++++++++++++ http/upload.html.gz | Bin 0 -> 4926 bytes http/upload.lua | 127 ++++++++++ 4 files changed, 696 insertions(+) create mode 100644 http/upload.full.html create mode 100644 http/upload.html.gz create mode 100644 http/upload.lua diff --git a/http/index.html b/http/index.html index 5bd9224..94a8b51 100644 --- a/http/index.html +++ b/http/index.html @@ -29,6 +29,7 @@
  • NodeMCU info: Shows some basic NodeMCU(Lua)
  • List all server files: Displays a list of all the server files. (Lua)
  • Foo: A file that doesn't exist. Should error (404 error)
  • +
  • Upload: update, remove, list files on the server.
  • diff --git a/http/upload.full.html b/http/upload.full.html new file mode 100644 index 0000000..1b1a47b --- /dev/null +++ b/http/upload.full.html @@ -0,0 +1,568 @@ + + + + + + + +
    +
    +
    + Drop Here + + Browse + Upload + +
    + +
      +
    +
    Files on device:
    +
      +
    +
    +
    + + diff --git a/http/upload.html.gz b/http/upload.html.gz new file mode 100644 index 0000000000000000000000000000000000000000..3dc89bffd254a382316e5f2dac5b826f8a679c10 GIT binary patch literal 4926 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 literal 0 HcmV?d00001 diff --git a/http/upload.lua b/http/upload.lua new file mode 100644 index 0000000..acf12bf --- /dev/null +++ b/http/upload.lua @@ -0,0 +1,127 @@ +return function (connection, req, args) + dofile("httpserver-header.lc")(connection, 200, 'application/json') + connection:send('{') + + local mbOffset = nil + local mbLen = nil + local mbData = nil + local mbCmd = nil + local mbFilename = nil + local fieldsCount = 0 + local fileSize = 0 + local i = 0 + local binaryData = '' + local currentByte = nil + + for name, value in pairs(args) do + if (name == "offset") then + mbOffset = tonumber(value, 10) + + fieldsCount = fieldsCount + 1 + end + if (name == "len") then + mbLen = tonumber(value, 10) + + fieldsCount = fieldsCount + 1 + end + if (name == "data") then + mbData = value + + fieldsCount = fieldsCount + 1 + end + if (name == "filename") then + mbFilename = value + + fieldsCount = fieldsCount + 1 + end + if (name == "filesize") then + fileSize = tonumber(value, 10) + + fieldsCount = fieldsCount + 1 + end + if (name == "cmd") then + mbCmd = value + + fieldsCount = fieldsCount + 1 + end + end + + if (mbCmd == 'upload') then + if (fieldsCount > 5) then + if (mbFilename ~= 'upload.lua') then + connection:send('"offset":"' .. mbOffset .. '",') + connection:send('"len":"' .. mbLen .. '",') + connection:send('"filename":"' .. mbFilename .. '"') + + mbFilename = 'http/' .. mbFilename + + for i=1,string.len(mbData),2 do + currentByte = tonumber(string.sub(mbData, i, i + 1), 16) + binaryData = binaryData .. string.char(currentByte) + end + + if (mbOffset > 0) then + file.open(mbFilename .. '.dnl','a+') + else + file.remove(mbFilename .. '.dnl') + file.open(mbFilename .. '.dnl','w+') + end + file.seek("set", mbOffset) + file.write(binaryData) + file.close() + + binaryData = nil + + if (fileSize == mbLen + mbOffset) then + file.remove(mbFilename) + file.rename(mbFilename .. '.dnl', mbFilename) + file.remove(mbFilename .. '.dnl') + + if (string.sub(mbFilename, -4) == '.lua') then + file.remove(string.sub(mbFilename, 0, -3) .. "lc") + node.compile(mbFilename) + file.remove(mbFilename) + end + end + end + end + elseif (mbCmd == 'list') then + local remaining, used, total=file.fsinfo() + + local headerExist = 0 + + connection:send('"files":{') + + for name, size in pairs(file.list()) do + local isHttpFile = string.match(name, "(http/)") ~= nil + + if isHttpFile then + if (headerExist > 0) then + connection:send(',') + end + + local url = string.match(name, ".*/(.*)") + + connection:send('"' .. url .. '":"' .. size .. '"') + + headerExist = 1 + end + end + + connection:send('},') + + connection:send('"total":"' .. total .. '",') + connection:send('"used":"' .. used .. '",') + connection:send('"free":"' .. remaining .. '"') + elseif (mbCmd == 'remove') then + if (fieldsCount > 1) then + if (mbFilename ~= 'upload.lua') and (mbFilename ~= 'upload.lc') and (mbFilename ~= 'upload.html.gz') then + file.remove('http/' .. mbFilename) + end + end + end + + connection:send('}') + collectgarbage() +end +