--- Find first MIME boundary
-process_states['mime-init'] = function( msg, chunk, filecb )
-
- if chunk ~= nil then
- if #chunk >= #msg.mime_boundary + 2 then
- local boundary = chunk:sub( 1, #msg.mime_boundary + 4 )
-
- if boundary == "--" .. msg.mime_boundary .. "\r\n" then
-
- -- Store remaining data in buffer
- msg._mimebuffer = chunk:sub( #msg.mime_boundary + 5, #chunk )
-
- -- Switch to header processing state
- return true, function( chunk )
- return process_states['mime-headers']( msg, chunk, filecb )
- end
- else
- return nil, "Invalid MIME boundary"
- end
- else
- return true
- end
- else
- return nil, "Unexpected EOF"
- end
-end
-
-
--- Read MIME part headers
-process_states['mime-headers'] = function( msg, chunk, filecb )
-
- if chunk ~= nil then
-
- -- Combine look-behind buffer with current chunk
- chunk = msg._mimebuffer .. chunk
-
- if not msg._mimeheaders then
- msg._mimeheaders = { }
- end
-
- local function __storehdr( k, v )
- msg._mimeheaders[k] = v
- return ""
- end
-
- -- Read all header lines
- local ok, count = 1, 0
- while ok > 0 do
- chunk, ok = chunk:gsub( "^([A-Z][A-Za-z0-9%-_]+): +([^\r\n]+)\r\n", __storehdr )
- count = count + ok
- end
-
- -- Headers processed, check for empty line
- chunk, ok = chunk:gsub( "^\r\n", "" )
-
- -- Store remaining buffer contents
- msg._mimebuffer = chunk
-
- -- End of headers
- if ok > 0 then
-
- -- When no Content-Type header is given assume text/plain
- if not msg._mimeheaders['Content-Type'] then
- msg._mimeheaders['Content-Type'] = 'text/plain'
- end
-
- -- Check Content-Disposition
- if msg._mimeheaders['Content-Disposition'] then
- -- Check for "form-data" token
- if msg._mimeheaders['Content-Disposition']:match("^form%-data; ") then
- -- Check for field name, filename
- local field = msg._mimeheaders['Content-Disposition']:match('name="(.-)"')
- local file = msg._mimeheaders['Content-Disposition']:match('filename="(.+)"$')
-
- -- Is a file field and we have a callback
- if file and filecb then
- msg.params[field] = file
- msg._mimecallback = function(chunk,eof)
- filecb( {
- name = field;
- file = file;
- headers = msg._mimeheaders
- }, chunk, eof )
- end
-
- -- Treat as form field
- else
- __initval( msg.params, field )
-
- msg._mimecallback = function(chunk,eof)
- __appendval( msg.params, field, chunk )
- end
- end
-
- -- Header was valid, continue with mime-data
- return true, function( chunk )
- return process_states['mime-data']( msg, chunk, filecb )
- end
- else
- -- Unknown Content-Disposition, abort
- return nil, "Unexpected Content-Disposition MIME section header"
- end
- else
- -- Content-Disposition is required, abort without
- return nil, "Missing Content-Disposition MIME section header"
- end
-
- -- We parsed no headers yet and buffer is almost empty
- elseif count > 0 or #chunk < 128 then
- -- Keep feeding me with chunks
- return true, nil
- end
-
- -- Buffer looks like garbage
- return nil, "Malformed MIME section header"
- else
- return nil, "Unexpected EOF"
- end
-end
-
-
--- Read MIME part data
-process_states['mime-data'] = function( msg, chunk, filecb )
-
- if chunk ~= nil then
-
- -- Combine look-behind buffer with current chunk
- local buffer = msg._mimebuffer .. chunk
-
- -- Look for MIME boundary
- local spos, epos = buffer:find( "\r\n--" .. msg.mime_boundary .. "\r\n", 1, true )
-
- if spos then
- -- Content data
- msg._mimecallback( buffer:sub( 1, spos - 1 ), true )
-
- -- Store remainder
- msg._mimebuffer = buffer:sub( epos + 1, #buffer )
-
- -- Next state is mime-header processing
- return true, function( chunk )
- return process_states['mime-headers']( msg, chunk, filecb )
- end
- else
- -- Look for EOF?
- local spos, epos = buffer:find( "\r\n--" .. msg.mime_boundary .. "--\r\n", 1, true )
-
- if spos then
- -- Content data
- msg._mimecallback( buffer:sub( 1, spos - 1 ), true )
-
- -- We processed the final MIME boundary, cleanup
- msg._mimebuffer = nil
- msg._mimeheaders = nil
- msg._mimecallback = nil
-
- -- We won't accept data anymore
- return false
- else
- -- We're somewhere within a data section and our buffer is full
- if #buffer > #chunk then
- -- Flush buffered data
- msg._mimecallback( buffer:sub( 1, #buffer - #chunk ), false )
-
- -- Store new data
- msg._mimebuffer = buffer:sub( #buffer - #chunk + 1, #buffer )
-
- -- Buffer is not full yet, append new data
- else
- msg._mimebuffer = buffer
- end
-
- -- Keep feeding me
- return true
- end
- end
- else
- return nil, "Unexpected EOF"
- end
-end
-
-