Fix send_file to work with non-ascii filenames
This commit implements https://tools.ietf.org/html/rfc2231#section-4 in order to support sending unicode characters. Tested on both Firefox and Chromium under Linux. This adds unidecode as a dependency, which might be relaxed by using .encode('latin-1', 'ignore') but wouldn't be as useful. Also, added a test for the correct headers to be added. Previously, using a filename parameter to send_file with unicode characters, it failed with the next error since HTTP headers don't allow non latin-1 characters. Error on request: Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 193, in run_wsgi execute(self.server.app) File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 186, in execute write(b'') File "/usr/lib/python3.6/site-packages/werkzeug/serving.py", line 152, in write self.send_header(key, value) File "/usr/lib64/python3.6/http/server.py", line 509, in send_header ("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict')) UnicodeEncodeError: 'latin-1' codec can't encode character '\uff0f' in position 58: ordinal not in range(256) Fixes #1286
This commit is contained in:
parent
6efea346dd
commit
0049922f2e
4 changed files with 18 additions and 1 deletions
|
|
@ -41,6 +41,7 @@ from .signals import message_flashed
|
|||
from .globals import session, _request_ctx_stack, _app_ctx_stack, \
|
||||
current_app, request
|
||||
from ._compat import string_types, text_type
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
# sentinel
|
||||
|
|
@ -534,8 +535,11 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
|||
if attachment_filename is None:
|
||||
raise TypeError('filename unavailable, required for '
|
||||
'sending as attachment')
|
||||
filename_dict = {
|
||||
'filename': unidecode(attachment_filename),
|
||||
'filename*': "UTF-8''%s" % url_quote(attachment_filename)}
|
||||
headers.add('Content-Disposition', 'attachment',
|
||||
filename=attachment_filename)
|
||||
**filename_dict)
|
||||
|
||||
if current_app.use_x_sendfile and filename:
|
||||
if file is not None:
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -75,6 +75,7 @@ setup(
|
|||
'Jinja2>=2.4',
|
||||
'itsdangerous>=0.21',
|
||||
'click>=2.0',
|
||||
'unidecode',
|
||||
],
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
|
|
|
|||
|
|
@ -560,6 +560,17 @@ class TestSendfile(object):
|
|||
assert options['filename'] == 'index.txt'
|
||||
rv.close()
|
||||
|
||||
def test_attachment_with_utf8_filename(self):
|
||||
app = flask.Flask(__name__)
|
||||
with app.test_request_context():
|
||||
with open(os.path.join(app.root_path, 'static/index.html')) as f:
|
||||
rv = flask.send_file(f, as_attachment=True,
|
||||
attachment_filename='Ñandú/pingüino.txt')
|
||||
value, options = \
|
||||
parse_options_header(rv.headers['Content-Disposition'])
|
||||
assert options == {'filename': 'Nandu/pinguino.txt', 'filename*': "UTF-8''%C3%91and%C3%BA%EF%BC%8Fping%C3%BCino.txt"}
|
||||
rv.close()
|
||||
|
||||
def test_static_file(self):
|
||||
app = flask.Flask(__name__)
|
||||
# default cache timeout is 12 hours
|
||||
|
|
|
|||
1
tox.ini
1
tox.ini
|
|
@ -27,6 +27,7 @@ deps=
|
|||
devel: git+https://github.com/pallets/itsdangerous.git
|
||||
devel: git+https://github.com/jek/blinker.git
|
||||
simplejson: simplejson
|
||||
unidecode
|
||||
|
||||
[testenv:docs]
|
||||
deps = sphinx
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue