Refactored server to move request parsing into a separate file. This allows the server to be used in firmware builds with floating point enabled.
This commit is contained in:
parent
dfb2dbecdf
commit
75ed944678
54
httpserver-request.lua
Normal file
54
httpserver-request.lua
Normal file
@ -0,0 +1,54 @@
|
||||
-- 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}
|
||||
if httpMethods[method] then return true else return false end
|
||||
end
|
||||
|
||||
local function uriToFilename(uri)
|
||||
return "http/" .. string.sub(uri, 2, -1)
|
||||
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] = value end
|
||||
i = i + 1
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local function parseUri(uri)
|
||||
local r = {}
|
||||
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
|
||||
_, r.ext = r.file:match("(.+)%.(.+)")
|
||||
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)
|
||||
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)
|
||||
return r
|
||||
end
|
||||
@ -1,59 +1,6 @@
|
||||
-- httpserver
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
module("httpserver", package.seeall)
|
||||
|
||||
-- Functions below aren't part of the public API
|
||||
-- Clients don't need to worry about them.
|
||||
|
||||
-- given an HTTP method, returns it or if invalid returns nil
|
||||
local function validateMethod(method)
|
||||
local httpMethods = {GET=true, HEAD=true, POST=true, PUT=true, DELETE=true, TRACE=true, OPTIONS=true, CONNECT=true, PATCH=true}
|
||||
if httpMethods[method] then return method else return nil end
|
||||
end
|
||||
|
||||
local function parseRequest(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.uri = line:find("^([A-Z]+) (.-) HTTP/[1-9]+.[0-9]+$")
|
||||
return r
|
||||
end
|
||||
|
||||
local function uriToFilename(uri)
|
||||
return "http/" .. string.sub(uri, 2, -1)
|
||||
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] = value end
|
||||
i = i + 1
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local function parseUri(uri)
|
||||
local r = {}
|
||||
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
|
||||
_, r.ext = r.file:match("(.+)%.(.+)")
|
||||
r.isScript = r.ext == "lua" or r.ext == "lc"
|
||||
r.file = uriToFilename(r.file)
|
||||
return r
|
||||
end
|
||||
|
||||
-- Starts web server in the specified port.
|
||||
return function (port)
|
||||
|
||||
@ -68,7 +15,6 @@ return function (port)
|
||||
local connectionThread
|
||||
|
||||
local function onGet(connection, uri)
|
||||
local uri = parseUri(uri)
|
||||
local fileServeFunction = nil
|
||||
if #(uri.file) > 32 then
|
||||
-- nodemcu-firmware cannot handle long filenames.
|
||||
@ -95,14 +41,16 @@ return function (port)
|
||||
end
|
||||
|
||||
local function onReceive(connection, payload)
|
||||
--print(payload) -- for debugging
|
||||
-- print(payload) -- for debugging
|
||||
-- parse payload and decide what to serve.
|
||||
local req = parseRequest(payload)
|
||||
print("Requested URI: " .. req.uri)
|
||||
req.method = validateMethod(req.method)
|
||||
if req.method == "GET" then onGet(connection, req.uri)
|
||||
elseif req.method == nil then dofile("httpserver-static.lc")(conection, {code=400})
|
||||
else dofile("httpserver-static.lc")(conection, {code=501}) end
|
||||
local req = dofile("httpserver-request.lc")(payload)
|
||||
print("Requested URI: " .. req.request)
|
||||
if req.methodIsValid then
|
||||
if req.method == "GET" then onGet(connection, req.uri)
|
||||
else dofile("httpserver-static.lc")(conection, {code=501}) end
|
||||
else
|
||||
dofile("httpserver-static.lc")(conection, {code=400})
|
||||
end
|
||||
end
|
||||
|
||||
local function onSent(connection, payload)
|
||||
|
||||
4
init.lua
4
init.lua
@ -4,7 +4,7 @@ print('set mode=STATION (mode='..wifi.getmode()..')')
|
||||
print('MAC: ',wifi.sta.getmac())
|
||||
print('chip: ',node.chipid())
|
||||
print('heap: ',node.heap())
|
||||
wifi.sta.config("Internet","")
|
||||
wifi.sta.config("Kirsch Extreme","1151511515")
|
||||
|
||||
-- Compile server code and remove original .lua files.
|
||||
-- This only happens the first time afer the .lua files are uploaded.
|
||||
@ -17,7 +17,7 @@ local compileAndRemoveIfNeeded = function(f)
|
||||
end
|
||||
end
|
||||
|
||||
local serverFiles = {'httpserver.lua', 'httpserver-static.lua', 'httpserver-error.lua'}
|
||||
local serverFiles = {'httpserver.lua', 'httpserver-request.lua', 'httpserver-static.lua', 'httpserver-error.lua'}
|
||||
for i, f in ipairs(serverFiles) do compileAndRemoveIfNeeded(f) end
|
||||
|
||||
compileAndRemoveIfNeeded = nil
|
||||
|
||||
2
makefile
2
makefile
@ -10,7 +10,7 @@ PORT=/dev/cu.usbserial-A602HRAZ
|
||||
# End of user config
|
||||
######################################################################
|
||||
HTTP_FILES := $(wildcard http/*)
|
||||
LUA_FILES := init.lua httpserver.lua httpserver-static.lua httpserver-error.lua
|
||||
LUA_FILES := init.lua httpserver.lua httpserver-request.lua httpserver-static.lua httpserver-error.lua
|
||||
|
||||
# Print usage
|
||||
usage:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user