@ -25,8 +25,9 @@ try:
except ImportError :
except ImportError :
from urlparse import quote as url_quote
from urlparse import quote as url_quote
from werkzeug . datastructures import Headers
from werkzeug . datastructures import Headers , Range
from werkzeug . exceptions import BadRequest , NotFound
from werkzeug . exceptions import BadRequest , NotFound , \
RequestedRangeNotSatisfiable
# this was moved in 0.7
# this was moved in 0.7
try :
try :
@ -39,7 +40,7 @@ from jinja2 import FileSystemLoader
from . signals import message_flashed
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 , PY2
from . _compat import string_types , text_type
# sentinel
# sentinel
@ -446,6 +447,10 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
ETags will also be attached automatically if a ` filename ` is provided . You
ETags will also be attached automatically if a ` filename ` is provided . You
can turn this off by setting ` add_etags = False ` .
can turn this off by setting ` add_etags = False ` .
If ` conditional = True ` and ` filename ` is provided , this method will try to
upgrade the response stream to support range requests . This will allow
the request to be answered with partial content response .
Please never pass filenames to this function from user sources ;
Please never pass filenames to this function from user sources ;
you should use : func : ` send_from_directory ` instead .
you should use : func : ` send_from_directory ` instead .
@ -500,6 +505,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
If a file was passed , this overrides its mtime .
If a file was passed , this overrides its mtime .
"""
"""
mtime = None
mtime = None
fsize = None
if isinstance ( filename_or_fp , string_types ) :
if isinstance ( filename_or_fp , string_types ) :
filename = filename_or_fp
filename = filename_or_fp
if not os . path . isabs ( filename ) :
if not os . path . isabs ( filename ) :
@ -535,13 +541,15 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
if file is not None :
if file is not None :
file . close ( )
file . close ( )
headers [ ' X-Sendfile ' ] = filename
headers [ ' X-Sendfile ' ] = filename
headers [ ' Content-Length ' ] = os . path . getsize ( filename )
fsize = os . path . getsize ( filename )
headers [ ' Content-Length ' ] = fsize
data = None
data = None
else :
else :
if file is None :
if file is None :
file = open ( filename , ' rb ' )
file = open ( filename , ' rb ' )
mtime = os . path . getmtime ( filename )
mtime = os . path . getmtime ( filename )
headers [ ' Content-Length ' ] = os . path . getsize ( filename )
fsize = os . path . getsize ( filename )
headers [ ' Content-Length ' ] = fsize
data = wrap_file ( request . environ , file )
data = wrap_file ( request . environ , file )
rv = current_app . response_class ( data , mimetype = mimetype , headers = headers ,
rv = current_app . response_class ( data , mimetype = mimetype , headers = headers ,
@ -559,7 +567,7 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
rv . cache_control . max_age = cache_timeout
rv . cache_control . max_age = cache_timeout
rv . expires = int ( time ( ) + cache_timeout )
rv . expires = int ( time ( ) + cache_timeout )
if add_etags and filename is not None and file is None :
if add_etags and filename is not None :
from warnings import warn
from warnings import warn
try :
try :
@ -575,12 +583,22 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
warn ( ' Access %s failed, maybe it does not exist, so ignore etags in '
warn ( ' Access %s failed, maybe it does not exist, so ignore etags in '
' headers ' % filename , stacklevel = 2 )
' headers ' % filename , stacklevel = 2 )
if conditional :
if conditional :
if callable ( getattr ( Range , ' to_content_range_header ' , None ) ) :
# Werkzeug supports Range Requests
# Remove this test when support for Werkzeug <0.12 is dropped
try :
rv = rv . make_conditional ( request , accept_ranges = True ,
complete_length = fsize )
except RequestedRangeNotSatisfiable :
file . close ( )
raise
else :
rv = rv . make_conditional ( request )
rv = rv . make_conditional ( request )
# make sure we don't send x-sendfile for servers that
# make sure we don't send x-sendfile for servers that
# ignore the 304 status code for x-sendfile.
# ignore the 304 status code for x-sendfile.
if rv . status_code == 304 :
if rv . status_code == 304 :
rv . headers . pop ( ' x-sendfile ' , None )
rv . headers . pop ( ' x-sendfile ' , None )
return rv
return rv