+ if enc[1] then
+ enc[n] = "&"
+ n = n + 1
+ end
+
+ enc[n+0] = lhttp.urlencode(k)
+ enc[n+1] = "="
+ enc[n+2] = lhttp.urlencode(v)
+ n = n + 3
+ end
+ end
+
+ return table.concat(enc, "")
+end
+
+-- Content-Type. Stores all extracted data associated with its parameter name
+-- in the params table within the given message object. Multiple parameter
+-- values are stored as tables, ordinary ones as strings.
+-- If an optional file callback function is given then it is feeded with the
+-- file contents chunk by chunk and only the extracted file name is stored
+-- within the params table. The callback function will be called subsequently
+-- with three arguments:
+-- o Table containing decoded (name, file) and raw (headers) mime header data
+-- o String value containing a chunk of the file data
+-- o Boolean which indicates wheather the current chunk is the last one (eof)
+function mimedecode_message_body(src, msg, file_cb)
+ local parser, header, field
+ local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil)
+
+ parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length)
+ if what == parser.PART_INIT then
+ field = { }
+
+ elseif what == parser.HEADER_NAME then
+ header = buffer:lower()
+
+ elseif what == parser.HEADER_VALUE and header then
+ if header:lower() == "content-disposition" and
+ lhttp.header_attribute(buffer, nil) == "form-data"
+ then
+ field.name = lhttp.header_attribute(buffer, "name")
+ field.file = lhttp.header_attribute(buffer, "filename")
+ field[1] = field.file
+ end
+
+ if field.headers then
+ field.headers[header] = buffer
+ else
+ field.headers = { [header] = buffer }
+ end
+
+ elseif what == parser.PART_BEGIN then
+ return not field.file
+
+ elseif what == parser.PART_DATA and field.name and length > 0 then
+ if field.file then
+ if file_cb then
+ file_cb(field, buffer, false)
+ msg.params[field.name] = msg.params[field.name] or field
+ else
+ if not field.fd then
+ field.fd = nixio.mkstemp(field.name)
+ end
+
+ if field.fd then
+ field.fd:write(buffer)
+ msg.params[field.name] = msg.params[field.name] or field
+ end
+ end
+ else
+ field.value = buffer
+ end
+
+ elseif what == parser.PART_END and field.name then
+ if field.file and msg.params[field.name] then
+ if file_cb then
+ file_cb(field, "", true)
+ elseif field.fd then
+ field.fd:seek(0, "set")
+ end
+ else
+ local val = msg.params[field.name]
+
+ if type(val) == "table" then
+ val[#val+1] = field.value or ""
+ elseif val ~= nil then
+ msg.params[field.name] = { val, field.value or "" }
+ else
+ msg.params[field.name] = field.value or ""