python – parse multipart/form-data, received from requests post

python – parse multipart/form-data, received from requests post

If youre receiving a multipart/form-data response, you can parse it using the requests-toolbelt library like so:

$ pip install requests-toolbelt

After installing it

from requests_toolbelt.multipart import decoder

testEnrollResponse =
multipart_data = decoder.MultipartDecoder.from_response(testEnrollResponse)

for part in
    print(part.content)  # Alternatively, part.text if you want unicode

Code sample for Flask, uses

import multipart as mp
from multipart import tob

    from io import BytesIO
except ImportError:
    from StringIO import StringIO as BytesIO

@app.route(/, methods=[GET,POST])
def index():
        elif flask.request.method == POST:
                data =
                s = data.split(r)[0][2:]
                p = mp.MultipartParser(BytesIO(tob(data)),s)
                blob =[0].value
                f = open(file.bin,wb)

python – parse multipart/form-data, received from requests post

A working example of parsing multipart data follows. You can try it out at the interactive python prompt.

import email

msg = email.message_from_string(
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=    XXXX

--    XXXX
Content-Type: text/plain

--    XXXX
Content-Type: text/plain

--    XXXX--


Once you know its working on your system, you can build your own email message out of the POST data and parse it the same way. If you have the raw post body as a string the rest of the necessary information can be found in the request headers. I added indentation here for clarity, you should not have extraneous indentation in the block string.

    epost_data = 
MIME-Version: 1.0
Content-Type: %s

%s % (self.headers[content-type], post_data)

    msg = email.message_from_string(post_data)

    if msg.is_multipart():
        for part in msg.get_payload():
            name = part.get_param(name, header=content-disposition)
            filename = part.get_param(filename, header=content-disposition)
            # print name %s % name # always there
            # print filename %s % filename # only there for files...
            payload = part.get_payload(decode=True)
            print payload[:100] # output first 100 characters

The first %s will be replaced with the content type, and the second with post_data. You can then write the payload to a file, etc.

Be careful to consider security implications of saving a file. You may not be able to trust the file name posted, it could start with ../../ for example on some web servers, so if you try to write /my-folder/../../ the attacker could potentially place a malicious file outside of the location where you are trying to store files. Strong validation of the file being the allowed type before trusting the file itself is also recommended. You do not want to let attackers overwrite any file on your system.

Leave a Reply

Your email address will not be published. Required fields are marked *