Multipart form handling should be performant, straightforward, and leave full control of the parsing process to the user, i.e. no surprising magic such as automatic creation of large files and saving anything there by default (although tools/helpers may exist to assist in that too).
The interface has also been discussed (and refined) at PyCon US '19 sprints between me and kgriffs.
Multipart forms would be treated as yet another type of request media. A new
handler, MultipartFormHandler
is introduced for these. However, in
contrast to existing JSON, Msgpack etc handlers, it would not consume all the
stream by default.
Instead, one would iterate the multipart form object (now found in
req.media
):
for part in req.media:
# Do something with the body part
print("* {} ({})".format(part.name, part.content_type))
# ...
The BodyPart
class, but currently exposes the following properties:
- stream -- stream wrapper just for the current body part
- data -- body part content bytes
- content_type, would default to
text/plain
if not specified, as per RFC - text -- the current body part decoded as text string (only
provided it is of type
text/plain
,None
otherwise) - media -- automatically parsed by media handlers in the same way as
req.media
- name, filename -- relevant parts from the
Content-Disposition
header - secure_filename -- sanitized filename that could safely be used on the server filesystem, a-la Werkzeug
The code has now been merged to Falcon master as part of this PR.
Warning
The code is currently slated for an alpha release.
As such, the code is not production ready. There may be bugs lurking in the code, and the interface may change based on community feedback.
Try also the test.py
below.
(from (hopefully) the future FAQ)
The stream of a body part is a file-like object implementing the read()
method that may be used with boto3
's
upload_fileobj:
import boto3
s3 = boto3.client('s3')
# ...
for part in req.media:
if part.name == 'myfile':
s3.upload_fileobj(part.stream, 'mybucket', 'mykey')
Note
Falcon is not endorsing any particular cloud service provider, and AWS S3
and boto3
are referenced here just as a popular example. The same
principles hopefully apply to other cloud storage APIs implementing upload
of arbitrary file-like objects.
See also the unit test case in my extended WiP test suite illustrating the concepts presented above: https://github.com/vytas7/falcon-multipart-tests/blob/master/tests/test_cloud_upload.py