Parsing Nested Multipart Forms

Out of the box, Falcon does not offer official support for parsing nested multipart forms (i.e., where multiple files for a single field are transmitted using a nested multipart/mixed part).

Note

Nested multipart forms are considered deprecated according to the living HTML5 standard and RFC 7578, Section 4.3.

If your app needs to handle nested forms, this can be done in the same fashion as any other part embedded in the form – by installing an appropriate media handler.

Let us extend the multipart form parser media handlers to recursively parse embedded forms of the multipart/mixed content type:

import falcon
import falcon.media

parser = falcon.media.MultipartFormHandler()
parser.parse_options.media_handlers['multipart/mixed'] = (
    falcon.media.MultipartFormHandler())

Note

Here we create a new parser (with default options) for nested parts, effectively disallowing further recursion.

If traversing into even deeper multipart form hierarchy is desired, we can just reuse the same parser.

Let us now use the nesting-aware parser in an app:

import falcon
import falcon.media

class Forms:
    def on_post(self, req, resp):
        example = {}
        for part in req.media:
            if part.content_type.startswith('multipart/mixed'):
                for nested in part.media:
                    example[nested.filename] = nested.text

        resp.media = example


parser = falcon.media.MultipartFormHandler()
parser.parse_options.media_handlers['multipart/mixed'] = (
    falcon.media.MultipartFormHandler())

app = falcon.App()
app.req_options.media_handlers[falcon.MEDIA_MULTIPART] = parser
app.add_route('/forms', Forms())

We should now be able to consume a form containing a nested multipart/mixed part (the example is adapted from the now-obsolete RFC 1867):

--AaB03x
Content-Disposition: form-data; name="field1"

Joe Blow
--AaB03x
Content-Disposition: form-data; name="docs"
Content-Type: multipart/mixed; boundary=BbC04y

--BbC04y
Content-Disposition: attachment; filename="file1.txt"

This is file1.

--BbC04y
Content-Disposition: attachment; filename="file2.txt"

Hello, World!

--BbC04y--

--AaB03x--

Note that all line endings in the form above are assumed to be CRLF.

The form should be POSTed with the Content-Type header set to multipart/form-data; boundary=AaB03x.