Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add explicit file MIME-type when writing with GridFS backend #28

Merged
merged 4 commits into from Apr 19, 2018

Conversation

rclement
Copy link
Contributor

@rclement rclement commented Apr 11, 2018

When using the GridFS backend and trying to serve files with it, the MIME-type cannot be found by Flask on the returned file. When writing a file to GridFS, the MIME-type should be included allowing to retrieve it when serving the file.

Run the following sample app to reproduce the issue:

from flask import Flask, jsonify, request
import flask_fs as fs
import os
from uuid import uuid4

app = Flask(__name__)
app.config.update(
    FS_BACKEND=os.environ.get('STORAGE_BACKEND'),
    FS_GRIDFS_MONGO_URL=os.environ.get('MONGO_URL'),
    FS_GRIDFS_MONGO_DB=os.environ.get('MONGO_DB')
)

uploads = fs.Storage('uploads')
fs.init_app(app, uploads)

@app.route('/upload', methods=['POST'])
def upload():
    content = request.files.get('content')
    if not content or content.filename == '':
        abort(HTTPStatus.BAD_REQUEST)

    filename = str(uuid4())
    uploads.write(filename, content)
    upload_url = uploads.url(filename)
    return jsonify({
        'upload_url': upload_url
    })

if __name__ == '__main__':
    app.run(debug=True)
$ export STORAGE_BACKEND="gridfs"
$ export MONGO_URL="mongodb://localhost:27017"
$ export MONGO_DB="uploads"
$ python app.py

Perform the following requests to observe the issue:

$ http -f POST localhost:5000/upload content@<path/to/file.{png,jpg}>
HTTP/1.0 200 OK
Access-Control-Allow-Origin: *
Content-Length: 68
Content-Type: application/json
Date: Wed, 11 Apr 2018 13:14:41 GMT
Server: Werkzeug/0.14.1 Python/3.6.5

{
    "upload_url": "/uploads/c5c195f1-41a9-41ad-a923-0111e51d4127"
}
$ http GET localhost:5000/uploads/c5c195f1-41a9-41ad-a923-0111e51d4127
HTTP/1.0 500 INTERNAL SERVER ERROR
Connection: close
Content-Type: text/html; charset=utf-8
Date: Wed, 11 Apr 2018 13:15:03 GMT
Server: Werkzeug/0.14.1 Python/3.6.5
X-XSS-Protection: 0

127.0.0.1 - - [11/Apr/2018 15:28:59] "GET /uploads/c5c195f1-41a9-41ad-a923-0111e51d4127 HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/lib/python3.6/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/lib/python3.6/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/lib/python3.6/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/lib/python3.6/site-packages/flask_fs/views.py", line 17, in get_file
    return storage.serve(filename)
  File "/lib/python3.6/site-packages/flask_fs/storage.py", line 354, in serve
    return self.backend.serve(filename)
  File "/lib/python3.6/site-packages/flask_fs/backends/gridfs.py", line 78, in serve
    return send_file(file, mimetype=file.content_type)
  File "/lib/python3.6/site-packages/flask/helpers.py", line 527, in send_file
    'Unable to infer MIME-type because no filename is available. '
ValueError: Unable to infer MIME-type because no filename is available. Please set either `attachment_filename`, pass a filepath to `filename_or_fp` or set your own MIME-type via `mimetype`.

Packages versions
Flask (0.12.2)
flask-fs (0.6.0)

@coveralls
Copy link

coveralls commented Apr 11, 2018

Coverage Status

Coverage increased (+0.02%) to 94.744% when pulling 7b58ff6 on rclement:gridfs-fix-serve-contenttype into 19a895b on noirbizarre:master.

Copy link
Owner

@noirbizarre noirbizarre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test for value not None, I'll merge it, but I think it won't solve the fact that this value is almost never set by Werkzeug

'filename': filename
}

if hasattr(content, 'content_type'):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should test that it's not None because most of the time Werkzeug set it to None (never succed to have another value).

if getattr(content, 'content_type'):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done. On my end, I always get a proper "content_type" in "request.files" if the originating request is set properly (i.e. the "Content-Type" header is set, thus making Werkzeug guess it).

@rclement rclement force-pushed the gridfs-fix-serve-contenttype branch from e1cc98d to 7b58ff6 Compare April 18, 2018 21:44
@noirbizarre noirbizarre merged commit df91779 into noirbizarre:master Apr 19, 2018
@noirbizarre
Copy link
Owner

Thanks! I'll probably release it today.

@rclement
Copy link
Contributor Author

Oh nice! Thanks a lot!

@rclement rclement deleted the gridfs-fix-serve-contenttype branch April 19, 2018 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants