diff --git a/AUTHORS b/AUTHORS index d081d9f8..cc157dc4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,6 +15,7 @@ Patches and Suggestions - Chris Grindstaff - Christopher Grebs - Daniel Neuhäuser +- Dan Sully - David Lord @davidism - Edmond Burnett - Florent Xicluna diff --git a/CHANGES b/CHANGES index a6dd5300..97459baa 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,8 @@ Version 0.12 ------------ - the cli command now responds to `--version`. +- Mimetype guessing for ``send_file`` has been removed, as per issue ``#104``. + See pull request ``#1849``. Version 0.11 ------------ diff --git a/flask/helpers.py b/flask/helpers.py index c744bb8c..e42a6a3c 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -437,11 +437,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False, to ``True`` to directly emit an ``X-Sendfile`` header. This however requires support of the underlying webserver for ``X-Sendfile``. - By default it will try to guess the mimetype for you, but you can - also explicitly provide one. For extra security you probably want - to send certain files as attachment (HTML for instance). The mimetype - guessing requires a `filename` or an `attachment_filename` to be - provided. + You must explicitly provide the mimetype for the filename or file object. Please never pass filenames to this function from user sources; you should use :func:`send_from_directory` instead. @@ -461,6 +457,11 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False, .. versionchanged:: 0.9 cache_timeout pulls its default from application config, when None. + .. versionchanged:: 0.12 + mimetype guessing and etag support removed for file objects. + If no mimetype or attachment_filename is provided, application/octet-stream + will be used. + :param filename_or_fp: the filename of the file to send in `latin-1`. This is relative to the :attr:`~Flask.root_path` if a relative path is specified. @@ -488,25 +489,9 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False, filename = filename_or_fp file = None else: - from warnings import warn file = filename_or_fp filename = getattr(file, 'name', None) - # XXX: this behavior is now deprecated because it was unreliable. - # removed in Flask 1.0 - if not attachment_filename and not mimetype \ - and isinstance(filename, string_types): - warn(DeprecationWarning('The filename support for file objects ' - 'passed to send_file is now deprecated. Pass an ' - 'attach_filename if you want mimetypes to be guessed.'), - stacklevel=2) - if add_etags: - warn(DeprecationWarning('In future flask releases etags will no ' - 'longer be generated for file objects passed to the send_file ' - 'function because this behavior was unreliable. Pass ' - 'filenames instead if possible, otherwise attach an etag ' - 'yourself based on another value'), stacklevel=2) - if filename is not None: if not os.path.isabs(filename): filename = os.path.join(current_app.root_path, filename) @@ -553,7 +538,9 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False, rv.cache_control.max_age = cache_timeout rv.expires = int(time() + cache_timeout) - if add_etags and filename is not None: + if add_etags and filename is not None and file is None: + from warnings import warn + try: rv.set_etag('%s-%s-%s' % ( os.path.getmtime(filename), diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 1fec1d87..8e815ee0 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -349,7 +349,7 @@ class TestSendfile(object): assert rv.mimetype == 'text/html' rv.close() - def test_send_file_object(self, recwarn): + def test_send_file_object(self): app = flask.Flask(__name__) with app.test_request_context(): @@ -361,10 +361,6 @@ class TestSendfile(object): assert rv.mimetype == 'text/html' rv.close() - # mimetypes + etag - recwarn.pop(DeprecationWarning) - recwarn.pop(DeprecationWarning) - app.use_x_sendfile = True with app.test_request_context(): @@ -376,10 +372,6 @@ class TestSendfile(object): os.path.join(app.root_path, 'static/index.html') rv.close() - # mimetypes + etag - recwarn.pop(DeprecationWarning) - recwarn.pop(DeprecationWarning) - app.use_x_sendfile = False with app.test_request_context(): f = StringIO('Test') @@ -389,9 +381,6 @@ class TestSendfile(object): assert rv.mimetype == 'application/octet-stream' rv.close() - # etags - recwarn.pop(DeprecationWarning) - class PyStringIO(object): def __init__(self, *args, **kwargs): self._io = StringIO(*args, **kwargs) @@ -405,11 +394,6 @@ class TestSendfile(object): assert rv.mimetype == 'text/plain' rv.close() - # attachment_filename and etags - a = recwarn.pop(DeprecationWarning) - b = recwarn.pop(DeprecationWarning) - c = recwarn.pop(UserWarning) # file not found - f = StringIO('Test') rv = flask.send_file(f, mimetype='text/plain') rv.direct_passthrough = False @@ -417,9 +401,6 @@ class TestSendfile(object): assert rv.mimetype == 'text/plain' rv.close() - # etags - recwarn.pop(DeprecationWarning) - app.use_x_sendfile = True with app.test_request_context(): @@ -428,10 +409,7 @@ class TestSendfile(object): assert 'x-sendfile' not in rv.headers rv.close() - # etags - recwarn.pop(DeprecationWarning) - - def test_attachment(self, recwarn): + def test_attachment(self): app = flask.Flask(__name__) with app.test_request_context(): with open(os.path.join(app.root_path, 'static/index.html')) as f: @@ -441,10 +419,6 @@ class TestSendfile(object): assert value == 'attachment' rv.close() - # mimetypes + etag - assert len(recwarn.list) == 2 - recwarn.clear() - with app.test_request_context(): assert options['filename'] == 'index.html' rv = flask.send_file('static/index.html', as_attachment=True)