summaryrefslogtreecommitdiffstats
path: root/src/civetweb/test/handle_form.lua
blob: c3694ae2e9a271f4668147be63f8e6e5be5a907a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
-- 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<len then
       mg.write(string.format("... (+ %u bytes)\r\n", len-maxlen))
     end

   else
     -- not a file
     if len<50 then
       mg.write("Field value: " .. form_field_value .. "\r\n")
     else
       mg.write("Field value: " .. form_field_value:sub(1, 40) .. " .. (" .. len .. " bytes)\r\n")
     end
   end


   mg.write("\r\n")
   fields = fields + 1
   datasize = datasize + len

end

mg.write("Got " .. fields .. " input fields with " .. datasize .. " bytes total\r\n");