瀏覽代碼

Fix example for form handling and file upload in Lua (example for #70)

bel 10 年之前
父節點
當前提交
50c2f4f11f
共有 3 個文件被更改,包括 75 次插入115 次删除
  1. 74 0
      examples/handle_form.lua
  2. 1 1
      test/form.html
  3. 0 114
      test/handle_form_data.lua

+ 74 - 0
examples/handle_form.lua

@@ -0,0 +1,74 @@
+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")
+
+-- 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
+   if file_name then
+     mg.write("File name: " .. file_name .. "\r\n")
+   end
+   local len = #form_field_value
+   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
+   mg.write("\r\n")
+
+end

+ 1 - 1
test/form.html

@@ -8,7 +8,7 @@
 </head>
 
 <body>
-  <form action="/handle_form_data.lua" method="POST" enctype="multipart/form-data">
+  <form action="/handle_form.lua" method="POST" enctype="multipart/form-data">
     See <a href="http://www.w3schools.com/html/html_form_input_types.asp">HTML form tutorial</a>.<br />
 
     <fieldset>

+ 0 - 114
test/handle_form_data.lua

@@ -1,114 +0,0 @@
-function add_data(data)
-  local additional_data = mg.read()
-  if additional_data then
-    return data .. additional_data, true
-  end
-  return data, false
-end
-
-function parse_multipart_form(got_field)
-
-    local data, ok = add_data("")
-    if not ok then
-      return "Can not read data"
-    end
-
-    --[[
-    local b = mg.request_info.content_type:upper():find("BOUNDARY=");
-    if b then
-      b = mg.request_info.content_type:sub(b+9)
-    end
-    if not b or #b<16 or #b>1024 then
-      return false, "Boundary string not reasonable"
-    end
-    ]]
-    local b = "--" .. mg.request_info.content_type:upper():match("BOUNDARY=(.*)");
-    
-    --b = "--" .. b
-    if data:sub(1, #b) ~= b then
-      return false, "Multipart body does not start properly"
-    end
-    data = data:sub(#b)
-    b = "\r\n" .. b
-
-    -- while there are unread parts
-    while #data>0 and data~="--\r\n" do
-
-      local name = nil
-      local value = nil
-      local file_name = nil
-      local file_type = nil
-
-      -- isolate the header of the new part
-      local part_header_end
-      repeat
-        part_header_end = data:find("\r\n\r\n", 1, true)
-        if not part_header_end then
-          data, ok = add_data(data)
-          if not ok then
-            return false, "protocol violation: header does not end properly"
-          end
-        end
-      until part_header_end
-
-      -- parse the header of the new part
-      local header = {}
-      for k,v in data:sub(1,part_header_end+2):gmatch("([^%:\r\n]*)%s*%:%s*([^\r\n]*)\r\n") do
-        header[k] = v
-        local kupper = k:upper()
-        if (kupper=="CONTENT-DISPOSITION") then
-          name = v:match('name=%"([^%"]*)%"')
-          file_name = v:match('filename=%"([^%"]*)%"')
-        elseif (kupper=="CONTENT-TYPE") then
-          file_type = v
-        end
-      end
-
-      -- isolate the body of the new part
-      local part_body_end
-      data = data:sub(part_header_end+4)
-      repeat
-        part_body_end = data:find(b, 1, true)
-        if not part_body_end then
-          data, ok = add_data(data)
-          if not ok then
-            return false, "protocol violation: body does not end properly"
-          end
-        end
-      until part_body_end
-      local value = data:sub(1,part_body_end-1)
-      data = data:sub(part_body_end+#b)
-      data = add_data(data)
-
-      -- send the result to the caller
-      got_field(name, value, file_name, file_type)
-
-    end
-
-    return true, ""
-  end
-
-
-
-
-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")
-
-
-mg.write("Parse request:\r\n")
-
-function fetch(k, v, fn, ft)
-    mg.write(k .. " = " .. v .. "\r\n")
-end
-
-ok, errtxt = parse_multipart_form(fetch)
-
-if not ok then
-    mg.write("Error: " .. errtxt .. "\r\n")
-else
-    mg.write("Parsing OK\r\n")
-end
-