Browse Source

Added support for conditional responses to send_file

pull/112/head
Armin Ronacher 14 years ago
parent
commit
d0c6ad7d28
  1. 2
      CHANGES
  2. 2
      flask/app.py
  3. 35
      flask/helpers.py

2
CHANGES

@ -17,6 +17,8 @@ Codename to be decided, release date to be announced.
``autoescape`` tag. ``autoescape`` tag.
- refactored Flask internally. It now consists of more than a - refactored Flask internally. It now consists of more than a
single file. single file.
- :func:`flask.send_file` now emits etags and has the ability to
do conditional responses builtin.
Version 0.4 Version 0.4
----------- -----------

2
flask/app.py

@ -328,7 +328,7 @@ class Flask(_PackageBoundObject):
return PackageLoader(self.import_name) return PackageLoader(self.import_name)
def init_jinja_globals(self): 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 some defaults (like `url_for`, `get_flashed_messages` and the
`tojson` filter. `tojson` filter.

35
flask/helpers.py

@ -12,6 +12,8 @@
import os import os
import sys import sys
import mimetypes import mimetypes
from time import time
from zlib import adler32
# try to load the best simplejson implementation available. If JSON # try to load the best simplejson implementation available. If JSON
# is not installed, we add a failing class. # is not installed, we add a failing class.
@ -24,7 +26,7 @@ except ImportError:
except ImportError: except ImportError:
json_available = False 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.globals import session, _request_ctx_stack, current_app, request
from flask.wrappers import Response from flask.wrappers import Response
@ -199,7 +201,8 @@ def get_flashed_messages(with_categories=False):
def send_file(filename_or_fp, mimetype=None, as_attachment=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 """Sends the contents of a file to the client. This will use the
most efficient method available and configured. By default it will most efficient method available and configured. By default it will
try to use the WSGI server's file_wrapper support. Alternatively try to use the WSGI server's file_wrapper support. Alternatively
@ -220,6 +223,10 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
.. versionadded:: 0.2 .. 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 :param filename_or_fp: the filename of the file to send. This is
relative to the :attr:`~Flask.root_path` if a relative to the :attr:`~Flask.root_path` if a
relative path is specified. relative path is specified.
@ -232,6 +239,9 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
a ``Content-Disposition: attachment`` header. a ``Content-Disposition: attachment`` header.
:param attachment_filename: the filename for the attachment if it :param attachment_filename: the filename for the attachment if it
differs from the file's filename. 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): if isinstance(filename_or_fp, basestring):
filename = filename_or_fp filename = filename_or_fp
@ -266,9 +276,28 @@ def send_file(filename_or_fp, mimetype=None, as_attachment=False,
file = open(filename, 'rb') file = open(filename, 'rb')
data = wrap_file(request.environ, file) data = wrap_file(request.environ, file)
return Response(data, mimetype=mimetype, headers=headers, rv = Response(data, mimetype=mimetype, headers=headers,
direct_passthrough=True) 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): def render_template(template_name, **context):
"""Renders a template from the template folder with the given """Renders a template from the template folder with the given

Loading…
Cancel
Save