TAGS :Viewed: 3 - Published at: a few seconds ago

[ flask send_file and unicode filename : broken in IE ]

I wrote a function that generates some csv file on the fly and sends to user for download.

the code is below:

def survey_downloadreport(survey_id):  
    survey, bsonobj = survey_get(survey_id)
    resps = response_get_multi(survey_id)

    fields = ["_id", "sid", "date", "user_ip"]

    csvf = StringIO.StringIO()
    wr = csv.DictWriter(csvf, fields, encoding = 'cp949')
    wr.writerow(dict(zip(fields, fields)))
    for resp in resps :


    now = datetime.datetime.now()
    report_name = survey.name + "(" + \
                  now.strftime("%Y-%m-%d-%H:%M:%S") +\
                  ")" + ".csv"

    report_name = report_name.encode("utf-8")

    return send_file(csvf,
                 as_attachment = True,
                 attachment_filename = report_name)

as you can see, the filename is converted from unicode to string and in utf-8 (to be precise, they are in Korean letters.)

the problem is, filenames are completely broken in when page is viewed in IE(no problem in chrome).

It seems like the header has to be edited to match parsing rules for different browsers, but I have no idea how I can do this in flask.

Answer 1

Try adding

mimetype = 'text/csv; charset=x-EBCDIC-KoreanAndKoreanExtended'

to send_file.

Answer 2

Using Content-Disposition: attachment; filename="..." to set the name of a downloaded file - which is what Flask's send_file does - is not reliable for non-ASCII characters.

Until there is support for RFC 5987 in the werkzeug.http library that Flask uses, and in all the browsers you want to target, this is not fixable.

In the meantime, a more reliable cross-browser method is to put the UTF-8-URL-encoded filename in the trailing part of the URI when you make links to it, ie:

IRI path: /survey/1/report/안녕.csv
URI path: /survey/1/report/%ec%95%88%eb%85%95.csv

See How to encode UTF8 filename for HTTP headers? (Python, Django) for background.