9 [206] = "Partial Content",
10 [301] = "Moved Permanently",
12 [304] = "Not Modified",
13 [400] = "Bad Request",
16 [405] = "Method Not Allowed",
17 [408] = "Request Time-out",
18 [411] = "Length Required",
19 [412] = "Precondition Failed",
20 [416] = "Requested range not satisfiable",
21 [500] = "Internal Server Error",
22 [503] = "Server Unavailable",
25 -- call this function passing an empy table. use that table for successive calls.
27 req.content_length = os.getenv("CONTENT_LENGTH")
28 req.request_method = os.getenv("REQUEST_METHOD")
29 if req.request_method == "POST" then
30 req.content_type, req.boundary = string.match(os.getenv("CONTENT_TYPE"),"^(multipart/form%-data); boundary=\"?(.+)\"?$")
31 req.boundary = "--" .. req.boundary
33 -- this is useful only if you have /tmp on tmpfs like in openwrt. otherwise can be set to ""
38 -- this function is needed to clean temp file since and hide implementation details
39 function _M.cleanup(req)
40 for k, v in pairs(req.post) do
41 for j, v in pairs(req.post[k]) do
42 if req.post[k][j].tempname then
43 os.remove(req.post[k][j].tempname) -- if file unused
44 os.remove("/tmp/" .. string.match(req.post[k][j].tempname,"^" .. req.tempdir .. "(.+)"))
51 -- return chunk (string), found (boolean)
52 local function chunkread(del)
54 local del = del or "\r\n"
56 buf = io.read(math.max(0,blocksize + #del - #prevbuf))
57 if prevbuf ~= "" then buf = prevbuf .. ( buf or "" ); prevbuf = "" end
58 if not buf then return end
60 s, e = string.find(buf,del,1,true)
63 prevbuf = string.sub(buf,e+1)
64 buf = string.sub(buf,1,s-1)
66 prevbuf = string.sub(buf,math.min(blocksize,#buf)+1)
67 buf = string.sub(buf,1,math.min(blocksize,#buf))
74 function _M.parse_request_body (req)
75 local chunk, found, type, tempname, tempfile
78 -- read first boundary line
79 chunk, found = chunkread(req.boundary)
80 chunk, found = chunkread("\r\n")
82 -- read part headers and get parameters value
84 chunk, found = chunkread("\r\n")
85 if not found then return 400, "Malformed POST. Missing Part Header or Part Header too long." end
86 string.gsub(chunk, ';%s*([^%s=]+)="(.-[^\\])"', function(k, v) param[k] = v end)
87 param.type = param.type or string.match(chunk, "^Content%-Type: (.+)$")
90 -- prepare file data read
91 if not param.name then return 400, "Malformed POST. Check Header parameters." end
93 param.tempname = req.tempdir .. string.match(os.tmpname(), "^/tmp(.+)")
94 tempfile = io.open(param.tempname, "w")
96 -- read part body content until boundary
98 chunk, found = chunkread("\r\n" .. req.boundary)
99 if not chunk then return 400, "Malformed POST. Incomplete Part received." end
100 tempfile:write(chunk)
101 param.size = param.size + #chunk
104 req.post[param.name] = req.post[param.name] or {}
105 table.insert(req.post[param.name], 1, param)
108 -- read after boundary. if CRLF ("") repeat. if "--" end POST processing
109 chunk, found = chunkread("\r\n")
112 if found and chunk == "--" then return 0, "OK" end
113 return 400, "Malformed POST. Boundary not properly ended with CRLF or --."