1-- Some basic checks 2if mg.request_info.request_method ~= "POST" or mg.request_info.content_type:lower():sub(1,19) ~= 'multipart/form-data' then 3 mg.write("HTTP/1.0 400 OK\r\n") 4 mg.write("Connection: close\r\n") 5 mg.write("Content-Type: text/plain; charset=utf-8\r\n") 6 mg.write("Cache-Control: max-age=0, must-revalidate\r\n") 7 mg.write("\r\n") 8 mg.write("Bad request\r\n\r\n") 9 return 10end 11 12-- HTTP headers 13mg.write("HTTP/1.0 200 OK\r\n") 14mg.write("Connection: close\r\n") 15mg.write("Content-Type: text/plain; charset=utf-8\r\n") 16mg.write("Cache-Control: max-age=0, must-revalidate\r\n") 17mg.write("\r\n") 18 19-- Which form sent the data? 20mg.write("Read POST data from " .. mg.request_info.http_headers.Referer .. ":\r\n\r\n") 21 22-- Count some data fields 23local fields = 0 24local datasize = 0 25 26-- Read the entire body data (POST content) into "bdata" variable. 27-- Use a string builder pattern for performance reasons 28stringtab = {} 29bdata = "" 30repeat 31 local add_data = mg.read() 32 if add_data then 33 stringtab[#stringtab+1] = add_data 34 end 35until (add_data == nil); 36bdata = table.concat(stringtab) 37stringtab = nil 38 39-- Get the boundary string. 40bs = "--" .. ((mg.request_info.content_type):upper():match("BOUNDARY=(.*)")); 41 42-- The POST data has to start with the boundary string. 43-- Check this and remove the starting boundary. 44if bdata:sub(1, #bs) ~= bs then 45 error "invalid format of POST data" 46end 47bdata = bdata:sub(#bs) 48 49-- The boundary now starts with CR LF. 50bs = "\r\n" .. bs 51 52-- Now loop through all the parts 53while #bdata>4 do 54 -- Find the header of new part. 55 part_header_end = bdata:find("\r\n\r\n", 1, true) 56 57 -- Parse the header. 58 local form_field_name, file_name 59 h = bdata:sub(1, part_header_end+2) 60 for key,val in h:gmatch("([^%:\r\n]*)%s*%:%s*([^\r\n]*)\r\n") do 61 if key:upper() == "CONTENT-DISPOSITION" then 62 form_field_name = val:match('name=%"([^%"]*)%"') 63 file_name = val:match('filename=%"([^%"]*)%"') 64 end 65 end 66 67 -- Remove the header from "bdata". 68 bdata = bdata:sub(part_header_end+4) 69 70 -- Find the end of the body by locating the boundary string. 71 local part_body_end = bdata:find(bs, 1, true) 72 73 -- Isolate the content, and drop it from "bdata". 74 local form_field_value = bdata:sub(1,part_body_end-1) 75 bdata = bdata:sub(part_body_end+#bs) 76 77 -- Now the data (file content or field value) is isolated: We know form_field_name and form_field_value. 78 -- Here the script should do something useful with the data. This example just sends it back to the client. 79 if form_field_name then 80 mg.write("Field name: " .. form_field_name .. "\r\n") 81 end 82 83 local len = #form_field_value 84 mg.write("Field data length: " .. len .. "\r\n") 85 86 if file_name then 87 mg.write("File name: " .. file_name .. "\r\n") 88 mg.write("File content:\r\n") 89 local maxlen 90 if len>320 then maxlen=320 else maxlen=len end 91 92 for l=0,maxlen,16 do 93 for m=1,16 do 94 local b = form_field_value:byte(l+m) 95 if (b) then 96 mg.write(string.format("%02x ", b)) 97 else 98 mg.write(" ") 99 end 100 end 101 mg.write(" - " .. form_field_value:sub(l+1,l+16):gsub("[%c%z%s]", " ") .. "\r\n") 102 end 103 if maxlen<len then 104 mg.write(string.format("... (+ %u bytes)\r\n", len-maxlen)) 105 end 106 107 else 108 -- not a file 109 if len<50 then 110 mg.write("Field value: " .. form_field_value .. "\r\n") 111 else 112 mg.write("Field value: " .. form_field_value:sub(1, 40) .. " .. (" .. len .. " bytes)\r\n") 113 end 114 end 115 116 117 mg.write("\r\n") 118 fields = fields + 1 119 datasize = datasize + len 120 121end 122 123mg.write("Got " .. fields .. " input fields with " .. datasize .. " bytes total\r\n"); 124