Browse Source

Add example how to handle form data and file upload in Lua

The Lua code example is from the Civetweb discussion group:
https://groups.google.com/forum/#!topic/civetweb/m9ojynOyzU4

This is also an example that might answer a question posted as an issue in Github:
https://github.com/bel2125/civetweb/issues/70
Question: how to get header, parse POSTed content in Lua? (issue #70)
bel 10 years ago
parent
commit
821a36af17
2 changed files with 147 additions and 0 deletions
  1. 83 0
      examples/form.html
  2. 64 0
      examples/handle_form_data.lua

+ 83 - 0
examples/form.html

@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  <title>Example page for HTML form handling</title>
+</head>
+
+<body>
+  <form action="/handle_form_data.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>
+      <legend>Text inputs:</legend>
+      A text: <input type="text" name="textin"><br />
+      A password: <input type="password" name="passwordin"><br />
+    </fieldset>
+
+    <fieldset>
+      <legend>Radio set 1:</legend>
+      <input type="radio" name="radio1" value="val1" checked>val1<br />
+      <input type="radio" name="radio1" value="val2">val2<br />
+      <input type="radio" name="radio1" value="val3">val3<br />
+    </fieldset>
+
+    <fieldset>
+      <legend>Radio set 2:</legend>
+      <input type="radio" name="radio2" value="val1" checked>val1<br />
+      <input type="radio" name="radio2" value="val2">val2<br />
+      <input type="radio" name="radio2" value="val3">val3<br />
+    </fieldset>
+
+    <fieldset>
+      <legend>Checkboxes:</legend>
+      <input type="checkbox" name="check1" value="val1" checked>val1<br />
+      <input type="checkbox" name="check2" value="val2">val2<br />
+      <input type="checkbox" name="check3" value="val3">val3<br />
+    </fieldset>
+
+    <fieldset>
+      <legend>HTML5 inputs:</legend>
+      A number: <input type="number" name="numberin" min="1" max="5"><br />
+      A date: <input type="date" name="datein"><br />
+      A color: <input type="color" name="colorin"><br />
+      A range: <input type="range" name="rangein" min="1" max="5"><br />
+      A month: <input type="month" name="monthin"><br />
+      A week: <input type="week" name="weekin"><br />
+      A time: <input type="time" name="timein"><br />
+      A datetime: <input type="datetime" name="datetimen"><br />
+      A datetime-local: <input type="datetime-local" name="datetimelocalin"><br />
+      An email: <input type="email" name="emailin"><br />
+      A search: <input type="search" name="searchin"><br />
+      A tel: <input type="tel" name="telin"><br />
+      An url: <input type="url" name="urlin"><br />
+    </fieldset>
+
+    <fieldset>
+      <legend>Files:</legend>
+      A file: <input type="file" name="filein"><br />
+      Multiple files: <input type="file" name="filesin" multiple><br>
+    </fieldset>
+
+    <fieldset>
+      <legend>Dropdown:</legend>
+      <select name="selectin">
+        <option value="opt1">opt1</option>
+        <option value="opt2">opt2</option>
+        <option value="opt3">opt3</option>
+      </select>
+    </fieldset>
+
+    <fieldset>
+      <legend>Text area:</legend>
+      <textarea name="message" rows="10" cols="30">Text area default text.</textarea>
+    </fieldset>
+
+    <input type="submit" value="Submit">
+
+  </form>
+</body>
+
+</html>

+ 64 - 0
examples/handle_form_data.lua

@@ -0,0 +1,64 @@
+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.
+bdata = ""
+repeat
+  local add_data = mg.read()
+  if add_data then
+    bdata = bdata .. add_data
+  end
+until (add_data == 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.
+   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.
+   part_body_end = bdata:find(bs, 1, true)
+
+   -- Isolate the content, and drop it from "bdata".
+   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.
+   mg.write("Field name: " .. form_field_name .. "\r\n")
+   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