Set Unicode filename in Flask response header
I am trying to set the Content-Disposition
header to send a file to the client. The file name is Unicode. When I try to set the header, it fails with a UnicodeEncodeError
. I tried various combinations of encode
and decode
but couldn't get it to work. How can I send a file with a Unicode filename?
destination_file = 'python_report.html'
response.headers['Content-Disposition'] = 'attachment; filename=' + destination_file
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/server.py", line 495, in send_header
("%s: %srn" % (keyword, value)).encode('latin-1', 'strict'))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 41-42: ordinal not in range(256)
python python-3.x flask http-headers
add a comment |
I am trying to set the Content-Disposition
header to send a file to the client. The file name is Unicode. When I try to set the header, it fails with a UnicodeEncodeError
. I tried various combinations of encode
and decode
but couldn't get it to work. How can I send a file with a Unicode filename?
destination_file = 'python_report.html'
response.headers['Content-Disposition'] = 'attachment; filename=' + destination_file
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/server.py", line 495, in send_header
("%s: %srn" % (keyword, value)).encode('latin-1', 'strict'))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 41-42: ordinal not in range(256)
python python-3.x flask http-headers
add a comment |
I am trying to set the Content-Disposition
header to send a file to the client. The file name is Unicode. When I try to set the header, it fails with a UnicodeEncodeError
. I tried various combinations of encode
and decode
but couldn't get it to work. How can I send a file with a Unicode filename?
destination_file = 'python_report.html'
response.headers['Content-Disposition'] = 'attachment; filename=' + destination_file
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/server.py", line 495, in send_header
("%s: %srn" % (keyword, value)).encode('latin-1', 'strict'))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 41-42: ordinal not in range(256)
python python-3.x flask http-headers
I am trying to set the Content-Disposition
header to send a file to the client. The file name is Unicode. When I try to set the header, it fails with a UnicodeEncodeError
. I tried various combinations of encode
and decode
but couldn't get it to work. How can I send a file with a Unicode filename?
destination_file = 'python_report.html'
response.headers['Content-Disposition'] = 'attachment; filename=' + destination_file
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/server.py", line 495, in send_header
("%s: %srn" % (keyword, value)).encode('latin-1', 'strict'))
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 41-42: ordinal not in range(256)
python python-3.x flask http-headers
python python-3.x flask http-headers
edited Apr 12 '17 at 15:47
davidism
63.9k12167185
63.9k12167185
asked Apr 12 '17 at 9:30
n33rman33rma
2,248926
2,248926
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
RFC 2231 section 4 describes how to specify an encoding to use instead of Latin-1 for a header value. Use the header option filename*=UTF-8''...
, where ...
is the url-encoded name. You can also include the filename
option to provide a Latin-1 fallback.
Until relatively recently, browsers did not consistently support this. This page has some metrics on browser support. Notably, IE8 will ignore the UTF-8 option, and will fail completely if the UTF-8 option comes before the Latin-1 option.
Flask 1.0 supports calling send_file
with Unicode filenames. If you use Flask 1.0, you can use send_file
with as_attachment=True
and a Unicode filename.
from flask import send_file
@app.route('/send-python-report')
def send_python_report():
return send_file('python_report.html', as_attachment=True)
Until then, you can construct the header manually using the same process Flask will use.
import unicodedata
from flask import send_file
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore'),
'filename*': "UTF-8''{}".format(url_quote(filename)),
}
else:
filenames = {'filename': filename}
rv.headers.set('Content-Disposition', 'attachment', **filenames)
return rv
For security you should use send_from_directory
instead if the filename is provided by user input. The process is the same as above, substituting the function.
WSGI doesn't ensure the order of header options, so if you want to support IE8 you must construct the header value completely manually using dump_options_header
with an OrderedDict
. Otherwise, filename*
may appear before filename
, which as noted above does not work in IE8.
from collections import OrderedDict
import unicodedata
from flask import send_file
from werkzeug.http import dump_options_header
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
filenames = OrderedDict()
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames['filename'] = unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore')
filenames['filename*']: "UTF-8''{}".format(url_quote(filename))
else:
filenames['filename'] = filename
rv.headers.set('Content-Disposition', dump_options_header('attachment', filenames))
return rv
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43365640%2fset-unicode-filename-in-flask-response-header%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
RFC 2231 section 4 describes how to specify an encoding to use instead of Latin-1 for a header value. Use the header option filename*=UTF-8''...
, where ...
is the url-encoded name. You can also include the filename
option to provide a Latin-1 fallback.
Until relatively recently, browsers did not consistently support this. This page has some metrics on browser support. Notably, IE8 will ignore the UTF-8 option, and will fail completely if the UTF-8 option comes before the Latin-1 option.
Flask 1.0 supports calling send_file
with Unicode filenames. If you use Flask 1.0, you can use send_file
with as_attachment=True
and a Unicode filename.
from flask import send_file
@app.route('/send-python-report')
def send_python_report():
return send_file('python_report.html', as_attachment=True)
Until then, you can construct the header manually using the same process Flask will use.
import unicodedata
from flask import send_file
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore'),
'filename*': "UTF-8''{}".format(url_quote(filename)),
}
else:
filenames = {'filename': filename}
rv.headers.set('Content-Disposition', 'attachment', **filenames)
return rv
For security you should use send_from_directory
instead if the filename is provided by user input. The process is the same as above, substituting the function.
WSGI doesn't ensure the order of header options, so if you want to support IE8 you must construct the header value completely manually using dump_options_header
with an OrderedDict
. Otherwise, filename*
may appear before filename
, which as noted above does not work in IE8.
from collections import OrderedDict
import unicodedata
from flask import send_file
from werkzeug.http import dump_options_header
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
filenames = OrderedDict()
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames['filename'] = unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore')
filenames['filename*']: "UTF-8''{}".format(url_quote(filename))
else:
filenames['filename'] = filename
rv.headers.set('Content-Disposition', dump_options_header('attachment', filenames))
return rv
add a comment |
RFC 2231 section 4 describes how to specify an encoding to use instead of Latin-1 for a header value. Use the header option filename*=UTF-8''...
, where ...
is the url-encoded name. You can also include the filename
option to provide a Latin-1 fallback.
Until relatively recently, browsers did not consistently support this. This page has some metrics on browser support. Notably, IE8 will ignore the UTF-8 option, and will fail completely if the UTF-8 option comes before the Latin-1 option.
Flask 1.0 supports calling send_file
with Unicode filenames. If you use Flask 1.0, you can use send_file
with as_attachment=True
and a Unicode filename.
from flask import send_file
@app.route('/send-python-report')
def send_python_report():
return send_file('python_report.html', as_attachment=True)
Until then, you can construct the header manually using the same process Flask will use.
import unicodedata
from flask import send_file
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore'),
'filename*': "UTF-8''{}".format(url_quote(filename)),
}
else:
filenames = {'filename': filename}
rv.headers.set('Content-Disposition', 'attachment', **filenames)
return rv
For security you should use send_from_directory
instead if the filename is provided by user input. The process is the same as above, substituting the function.
WSGI doesn't ensure the order of header options, so if you want to support IE8 you must construct the header value completely manually using dump_options_header
with an OrderedDict
. Otherwise, filename*
may appear before filename
, which as noted above does not work in IE8.
from collections import OrderedDict
import unicodedata
from flask import send_file
from werkzeug.http import dump_options_header
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
filenames = OrderedDict()
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames['filename'] = unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore')
filenames['filename*']: "UTF-8''{}".format(url_quote(filename))
else:
filenames['filename'] = filename
rv.headers.set('Content-Disposition', dump_options_header('attachment', filenames))
return rv
add a comment |
RFC 2231 section 4 describes how to specify an encoding to use instead of Latin-1 for a header value. Use the header option filename*=UTF-8''...
, where ...
is the url-encoded name. You can also include the filename
option to provide a Latin-1 fallback.
Until relatively recently, browsers did not consistently support this. This page has some metrics on browser support. Notably, IE8 will ignore the UTF-8 option, and will fail completely if the UTF-8 option comes before the Latin-1 option.
Flask 1.0 supports calling send_file
with Unicode filenames. If you use Flask 1.0, you can use send_file
with as_attachment=True
and a Unicode filename.
from flask import send_file
@app.route('/send-python-report')
def send_python_report():
return send_file('python_report.html', as_attachment=True)
Until then, you can construct the header manually using the same process Flask will use.
import unicodedata
from flask import send_file
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore'),
'filename*': "UTF-8''{}".format(url_quote(filename)),
}
else:
filenames = {'filename': filename}
rv.headers.set('Content-Disposition', 'attachment', **filenames)
return rv
For security you should use send_from_directory
instead if the filename is provided by user input. The process is the same as above, substituting the function.
WSGI doesn't ensure the order of header options, so if you want to support IE8 you must construct the header value completely manually using dump_options_header
with an OrderedDict
. Otherwise, filename*
may appear before filename
, which as noted above does not work in IE8.
from collections import OrderedDict
import unicodedata
from flask import send_file
from werkzeug.http import dump_options_header
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
filenames = OrderedDict()
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames['filename'] = unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore')
filenames['filename*']: "UTF-8''{}".format(url_quote(filename))
else:
filenames['filename'] = filename
rv.headers.set('Content-Disposition', dump_options_header('attachment', filenames))
return rv
RFC 2231 section 4 describes how to specify an encoding to use instead of Latin-1 for a header value. Use the header option filename*=UTF-8''...
, where ...
is the url-encoded name. You can also include the filename
option to provide a Latin-1 fallback.
Until relatively recently, browsers did not consistently support this. This page has some metrics on browser support. Notably, IE8 will ignore the UTF-8 option, and will fail completely if the UTF-8 option comes before the Latin-1 option.
Flask 1.0 supports calling send_file
with Unicode filenames. If you use Flask 1.0, you can use send_file
with as_attachment=True
and a Unicode filename.
from flask import send_file
@app.route('/send-python-report')
def send_python_report():
return send_file('python_report.html', as_attachment=True)
Until then, you can construct the header manually using the same process Flask will use.
import unicodedata
from flask import send_file
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames = {
'filename': unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore'),
'filename*': "UTF-8''{}".format(url_quote(filename)),
}
else:
filenames = {'filename': filename}
rv.headers.set('Content-Disposition', 'attachment', **filenames)
return rv
For security you should use send_from_directory
instead if the filename is provided by user input. The process is the same as above, substituting the function.
WSGI doesn't ensure the order of header options, so if you want to support IE8 you must construct the header value completely manually using dump_options_header
with an OrderedDict
. Otherwise, filename*
may appear before filename
, which as noted above does not work in IE8.
from collections import OrderedDict
import unicodedata
from flask import send_file
from werkzeug.http import dump_options_header
from werkzeug.urls import url_quote
@app.route('/send-python-report')
def send_python_report():
filename = 'python_report.html'
rv = send_file(filename)
filenames = OrderedDict()
try:
filename = filename.encode('latin-1')
except UnicodeEncodeError:
filenames['filename'] = unicodedata.normalize('NFKD', filename).encode('latin-1', 'ignore')
filenames['filename*']: "UTF-8''{}".format(url_quote(filename))
else:
filenames['filename'] = filename
rv.headers.set('Content-Disposition', dump_options_header('attachment', filenames))
return rv
edited Nov 24 '18 at 17:58
answered Apr 12 '17 at 17:36
davidismdavidism
63.9k12167185
63.9k12167185
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f43365640%2fset-unicode-filename-in-flask-response-header%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown