-- Some basic checks if mg.request_info.request_method ~= "POST" or mg.request_info.content_type:lower():sub(1,19) ~= 'multipart/form-data' then mg.write("HTTP/1.0 400 OK\r\n") mg.write("Connection: close\r\n") mg.write("Content-Type: text/plain; charset=utf-8\r\n") mg.write("Cache-Control: max-age=0, must-revalidate\r\n") mg.write("\r\n") mg.write("Bad request\r\n\r\n") return end -- HTTP headers mg.write("HTTP/1.0 200 OK\r\n") mg.write("Connection: close\r\n") mg.write("Content-Type: text/plain; charset=utf-8\r\n") mg.write("Cache-Control: max-age=0, must-revalidate\r\n") mg.write("\r\n") -- Which form sent the data? mg.write("Read POST data from " .. mg.request_info.http_headers.Referer .. ":\r\n\r\n") -- Count some data fields local fields = 0 local datasize = 0 -- Read the entire body data (POST content) into "bdata" variable. -- Use a string builder pattern for performance reasons stringtab = {} bdata = "" repeat local add_data = mg.read() if add_data then stringtab[#stringtab+1] = add_data end until (add_data == nil); bdata = table.concat(stringtab) stringtab = nil -- Get the boundary string. bs = "--" .. ((mg.request_info.content_type):upper():match("BOUNDARY=(.*)")); -- The POST data has to start with the boundary string. -- Check this and remove the starting boundary. if bdata:sub(1, #bs) ~= bs then error "invalid format of POST data" end bdata = bdata:sub(#bs) -- The boundary now starts with CR LF. bs = "\r\n" .. bs -- Now loop through all the parts while #bdata>4 do -- Find the header of new part. part_header_end = bdata:find("\r\n\r\n", 1, true) -- Parse the header. local form_field_name, file_name h = bdata:sub(1, part_header_end+2) for key,val in h:gmatch("([^%:\r\n]*)%s*%:%s*([^\r\n]*)\r\n") do if key:upper() == "CONTENT-DISPOSITION" then form_field_name = val:match('name=%"([^%"]*)%"') file_name = val:match('filename=%"([^%"]*)%"') end end -- Remove the header from "bdata". bdata = bdata:sub(part_header_end+4) -- Find the end of the body by locating the boundary string. local part_body_end = bdata:find(bs, 1, true) -- Isolate the content, and drop it from "bdata". local form_field_value = bdata:sub(1,part_body_end-1) bdata = bdata:sub(part_body_end+#bs) -- Now the data (file content or field value) is isolated: We know form_field_name and form_field_value. -- Here the script should do something useful with the data. This example just sends it back to the client. if form_field_name then mg.write("Field name: " .. form_field_name .. "\r\n") end local len = #form_field_value mg.write("Field data length: " .. len .. "\r\n") if file_name then mg.write("File name: " .. file_name .. "\r\n") mg.write("File content:\r\n") local maxlen if len>320 then maxlen=320 else maxlen=len end for l=0,maxlen,16 do for m=1,16 do local b = form_field_value:byte(l+m) if (b) then mg.write(string.format("%02x ", b)) else mg.write(" ") end end mg.write(" - " .. form_field_value:sub(l+1,l+16):gsub("[%c%z%s]", " ") .. "\r\n") end if maxlen