forked from orbit-oss/flask
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, \
|
from .globals import session, _request_ctx_stack, _app_ctx_stack, \
|
||||||
current_app, request
|
current_app, request
|
||||||
from ._compat import string_types, text_type
|
from ._compat import string_types, text_type
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
|
|
||||||
# sentinel
|
# sentinel
|
||||||
|
|
@ -534,8 +535,11 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||||
if attachment_filename is None:
|
if attachment_filename is None:
|
||||||
raise TypeError('filename unavailable, required for '
|
raise TypeError('filename unavailable, required for '
|
||||||
'sending as attachment')
|
'sending as attachment')
|
||||||
|
filename_dict = {
|
||||||
|
'filename': unidecode(attachment_filename),
|
||||||
|
'filename*': "UTF-8''%s" % url_quote(attachment_filename)}
|
||||||
headers.add('Content-Disposition', 'attachment',
|
headers.add('Content-Disposition', 'attachment',
|
||||||
filename=attachment_filename)
|
**filename_dict)
|
||||||
|
|
||||||
if current_app.use_x_sendfile and filename:
|
if current_app.use_x_sendfile and filename:
|
||||||
if file is not None:
|
if file is not None:
|
||||||
|
|
|
||||||
1
setup.py
1
setup.py
|
|
@ -75,6 +75,7 @@ setup(
|
||||||
'Jinja2>=2.4',
|
'Jinja2>=2.4',
|
||||||
'itsdangerous>=0.21',
|
'itsdangerous>=0.21',
|
||||||
'click>=2.0',
|
'click>=2.0',
|
||||||
|
'unidecode',
|
||||||
],
|
],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
|
|
|
||||||
|
|
@ -560,6 +560,17 @@ class TestSendfile(object):
|
||||||
assert options['filename'] == 'index.txt'
|
assert options['filename'] == 'index.txt'
|
||||||
rv.close()
|
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):
|
def test_static_file(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
# default cache timeout is 12 hours
|
# 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/pallets/itsdangerous.git
|
||||||
devel: git+https://github.com/jek/blinker.git
|
devel: git+https://github.com/jek/blinker.git
|
||||||
simplejson: simplejson
|
simplejson: simplejson
|
||||||
|
unidecode
|
||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
deps = sphinx
|
deps = sphinx
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue