Flask: How to handle application/octet-stream

17,723

Solution 1

I was unable to get a request working using application/octet-stream type posts, but have used multipart/form-data type forms in the past to upload images using flask.

I have extended what I have done in the past to support multiple upload files and this has worked leveraging werkzeug's FileStorage objects.

The key here is setting up a post based route that is looking for a request element from a form. This should allow you to POST to the route either via a standard form or an AJAX call.

Below is a simplified example that is using a form:

Template for the view:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>jQuery File Upload Example</title>
</head>
<body>
{% if err %}
    <h4>{{ err }}</h4>
{% endif %}
<form action="/" method=POST enctype=multipart/form-data id="fileupload">
    <input type="file" name="files" data-url="/" multiple>
    <input type=submit value=Post>
</form>
{% if files %}
{% for file in files %}
<p>Uploaded: <b>{{ file }}</b> </p>
{% endfor %}
{% endif %}
</body> 
</html>

Flask App

from flask import Flask, request, render_template
from werkzeug import secure_filename, FileStorage
import os
# Flask functions
app = Flask(__name__) 
app.config.from_object(__name__)
DEBUG = True 
# add this so that flask doesn't swallow error messages
app.config['PROPAGATE_EXCEPTIONS'] = True
@app.route('/', methods=['GET', 'POST'])
def uploader():
    if request.method =='POST' and request.files.getlist('files'):
        up_file_list = []
        # Iterate the through a list of files from the form input field
        for a_file in request.files.getlist('files'):
            if a_file.filename:
                # Validate that what we have been supplied with is infact a file
                if not isinstance(a_file, FileStorage):
                    raise TypeError("storage must be a werkzeug.FileStorage")
                # Sanitise the filename
                a_file_name = secure_filename(a_file.filename)
                # Build target
                a_file_target = os.path.join('/tmp/', a_file_name)
                # Save file 
                a_file.save(a_file_target)
                up_file_list.append(a_file_name)
        # Return template
        if up_file_list:
            return render_template('uploader.html', err=None, files=up_file_list)
        else:
            return render_template('uploader.html', err='No Files Uploaded', files=None)
    else:
        return render_template('uploader.html', err=None, files=None) 
# application execution 
if __name__ == '__main__': 
    app.run()

Solution 2

Regardless of the the data encoding, you should be able to get the raw data with request.data. In the case of application/octet-stream, you can just write request.data to a binary file.

An example handler for various data types:

from flask import json
@app.route('/messages', methods = ['POST'])
def api_message():
    if request.headers['Content-Type'] == 'text/plain':
        return "Text Message: " + request.data
    elif request.headers['Content-Type'] == 'application/json':
        return "JSON Message: " + json.dumps(request.json)
    elif request.headers['Content-Type'] == 'application/octet-stream':
        with open('/tmp/binary', 'wb') as f:
            f.write(request.data)
            f.close()
        return "Binary message written!"
    else:
        return "415 Unsupported Media Type ;)"

The typical scenario of handling form data is already documented here.

Share:
17,723
saidozcan
Author by

saidozcan

Updated on June 05, 2022

Comments

  • saidozcan
    saidozcan 7 months

    I want to make a multiple file-upload form.I use jQuery File Uploader. My server-side code:

    @app.route("/new/photogallery",methods=["POST"])
    def newPhotoGallery():
        print request.files
    

    I tried two things:

    1. Submit form normally:

      When i submit my form normally,it prints:

      ImmutableMultiDict([('post_photo_gallery', FileStorage: u'' ('application/octet-stream'))])

    2. Submit form using AJAX:

      When i submit my form using AJAX,it prints:

      ImmutableMultiDict([])

    My first question is: Why is there a difference between AJAX request and normal request.
    My second question is: How can i handle this application/octet-streamrequest in Flask/Python My third question is: Is this a good way to use application/octet-stream ?

    By the way i do not know much about application/octet-stream.Thank you very much.

  • markmnl
    markmnl over 4 years
    that didn't work for me when sending application/octet-stream, I get: File "...\lib\site-packages\werkzeug\test.py", line 884, in run_wsgi_app app_rv = app(environ, start_response) TypeError: 'int' object is not callable
  • 8.8.8.8
    8.8.8.8 over 4 years
    @markmnl You can use request.stream.read as shown in izmailoff.github.io/web/flask-file-streaming
  • steff_bdh
    steff_bdh over 3 years
    when using multipart/form-data or application/x-www-form-urlencoded to send files, flask stores the file comes in request.files as shown here flask.palletsprojects.com/en/1.1.x/patterns/fileuploads