mirror of https://github.com/pallets/flask.git
				
				
				
			Merge pull request #2223 from antlarr/master
Fix send_file's attachment_filename to work with non-ascii filenames
This commit is contained in:
		
						commit
						8b45009dbc
					
				| 
						 | 
				
			
			@ -17,6 +17,7 @@ import mimetypes
 | 
			
		|||
from time import time
 | 
			
		||||
from zlib import adler32
 | 
			
		||||
from threading import RLock
 | 
			
		||||
import unicodedata
 | 
			
		||||
from werkzeug.routing import BuildError
 | 
			
		||||
from functools import update_wrapper
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -478,6 +479,11 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
 | 
			
		|||
       The `attachment_filename` is preferred over `filename` for MIME-type
 | 
			
		||||
       detection.
 | 
			
		||||
       
 | 
			
		||||
    .. versionchanged:: 0.13
 | 
			
		||||
        UTF-8 filenames, as specified in `RFC 2231`_, are supported.
 | 
			
		||||
        
 | 
			
		||||
    .. _RFC 2231: https://tools.ietf.org/html/rfc2231#section-4
 | 
			
		||||
 | 
			
		||||
    :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.
 | 
			
		||||
| 
						 | 
				
			
			@ -534,8 +540,22 @@ 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')
 | 
			
		||||
        headers.add('Content-Disposition', 'attachment',
 | 
			
		||||
                    filename=attachment_filename)
 | 
			
		||||
 | 
			
		||||
        normalized = unicodedata.normalize(
 | 
			
		||||
            'NFKD', text_type(attachment_filename)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            normalized.encode('ascii')
 | 
			
		||||
        except UnicodeEncodeError:
 | 
			
		||||
            filenames = {
 | 
			
		||||
                'filename': normalized.encode('ascii', 'ignore'),
 | 
			
		||||
                'filename*': "UTF-8''%s" % url_quote(attachment_filename),
 | 
			
		||||
            }
 | 
			
		||||
        else:
 | 
			
		||||
            filenames = {'filename': attachment_filename}
 | 
			
		||||
 | 
			
		||||
        headers.add('Content-Disposition', 'attachment', **filenames)
 | 
			
		||||
 | 
			
		||||
    if current_app.use_x_sendfile and filename:
 | 
			
		||||
        if file is not None:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -540,10 +540,11 @@ class TestSendfile(object):
 | 
			
		|||
                value, options = \
 | 
			
		||||
                    parse_options_header(rv.headers['Content-Disposition'])
 | 
			
		||||
                assert value == 'attachment'
 | 
			
		||||
                assert options['filename'] == 'index.html'
 | 
			
		||||
                assert 'filename*' not in rv.headers['Content-Disposition']
 | 
			
		||||
                rv.close()
 | 
			
		||||
 | 
			
		||||
        with app.test_request_context():
 | 
			
		||||
            assert options['filename'] == 'index.html'
 | 
			
		||||
            rv = flask.send_file('static/index.html', as_attachment=True)
 | 
			
		||||
            value, options = parse_options_header(rv.headers['Content-Disposition'])
 | 
			
		||||
            assert value == 'attachment'
 | 
			
		||||
| 
						 | 
				
			
			@ -560,6 +561,19 @@ 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():
 | 
			
		||||
            rv = flask.send_file('static/index.html', as_attachment=True, attachment_filename=u'Ñandú/pingüino.txt')
 | 
			
		||||
            content_disposition = set(rv.headers['Content-Disposition'].split('; '))
 | 
			
		||||
            assert content_disposition == set((
 | 
			
		||||
                'attachment',
 | 
			
		||||
                '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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue