Skip to content

Commit

Permalink
Added support for conditional responses to send_file
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Jul 4, 2010
1 parent 88d9315 commit d0c6ad7
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Expand Up @@ -17,6 +17,8 @@ Codename to be decided, release date to be announced.
``autoescape`` tag.
- refactored Flask internally. It now consists of more than a
single file.
- :func:`flask.send_file` now emits etags and has the ability to
do conditional responses builtin.

Version 0.4
-----------
Expand Down
2 changes: 1 addition & 1 deletion flask/app.py
Expand Up @@ -328,7 +328,7 @@ def create_jinja_loader(self):
return PackageLoader(self.import_name)

def init_jinja_globals(self):
"""Callde directly after the environment was created to inject
"""Called directly after the environment was created to inject
some defaults (like `url_for`, `get_flashed_messages` and the
`tojson` filter.
Expand Down
37 changes: 33 additions & 4 deletions flask/helpers.py
Expand Up @@ -12,6 +12,8 @@
import os
import sys
import mimetypes
from time import time
from zlib import adler32

# try to load the best simplejson implementation available. If JSON
# is not installed, we add a failing class.
Expand All @@ -24,7 +26,7 @@
except ImportError:
json_available = False

from werkzeug import Headers, wrap_file
from werkzeug import Headers, wrap_file, is_resource_modified

from flask.globals import session, _request_ctx_stack, current_app, request
from flask.wrappers import Response
Expand Down Expand Up @@ -199,7 +201,8 @@ def get_flashed_messages(with_categories=False):


def send_file(filename_or_fp, mimetype=None, as_attachment=False,
attachment_filename=None):
attachment_filename=None, add_etags=True,
cache_timeout=60 * 60 * 12, conditional=False):
"""Sends the contents of a file to the client. This will use the
most efficient method available and configured. By default it will
try to use the WSGI server's file_wrapper support. Alternatively
Expand All @@ -220,6 +223,10 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
.. versionadded:: 0.2
.. versionadded:: 0.5
The `add_etags`, `cache_timeout` and `conditional` parameters were added.
The default behaviour is now to attach etags.
:param filename_or_fp: the filename of the file to send. This is
relative to the :attr:`~Flask.root_path` if a
relative path is specified.
Expand All @@ -232,6 +239,9 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
a ``Content-Disposition: attachment`` header.
:param attachment_filename: the filename for the attachment if it
differs from the file's filename.
:param add_etags: set to `False` to disable attaching of etags.
:param conditional: set to `True` to enable conditional responses.
:param cache_timeout: the timeout in seconds for the headers.
"""
if isinstance(filename_or_fp, basestring):
filename = filename_or_fp
Expand Down Expand Up @@ -266,8 +276,27 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
file = open(filename, 'rb')
data = wrap_file(request.environ, file)

return Response(data, mimetype=mimetype, headers=headers,
direct_passthrough=True)
rv = Response(data, mimetype=mimetype, headers=headers,
direct_passthrough=True)

rv.cache_control.public = True
if cache_timeout:
rv.cache_control.max_age = cache_timeout
rv.expires = int(time() + cache_timeout)

if add_etags and filename is not None:
rv.set_etag('flask-%s-%s-%s' % (
os.path.getmtime(filename),
os.path.getsize(filename),
adler32(filename) & 0xffffffff
))
if conditional:
rv = rv.make_conditional(request)
# make sure we don't send x-sendfile for servers that
# ignore the 304 status code for x-sendfile.
if rv.status_code == 304:
rv.headers.pop('x-sendfile', None)
return rv


def render_template(template_name, **context):
Expand Down

0 comments on commit d0c6ad7

Please sign in to comment.