Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Introduced a method to adjust static file cache-control headers based on filename #433

Merged
merged 1 commit into from

2 participants

@dave-shawley

I needed this method to adjust the cache control headers for .js files that one of my applications was statically serving. The default expiration is buried in an argument to send_file and is set to 12 hours. There was no good way to adjust this value previously. So I added a new method to _PackageBoundObject named get_static_file_options that returns a dict (empty by default) of keywords to pass into send_file. This can be overridden in the flask.Flask derivative to adjust values based on the debug flag or filename.

@dave-shawley dave-shawley Added _PackageBoundObject.get_static_file_options.
This method receives the name of a static file that is going to be served
up and generates a dict of options to use when serving the file.  The
default set is empty so code will fall back to the existing behavior if
the method is not overridden.

I needed this method to adjust the cache control headers for .js files that
one of my applications was statically serving.  The default expiration is
buried in an argument to send_file and is set to 12 hours.  There was no
good way to adjust this value previously.
06b2246
@rduplain rduplain merged commit f4a31db into mitsuhiko:master
@rduplain rduplain referenced this pull request from a commit
@rduplain rduplain Expose send_file max-age as config value, #433.
Need to add the same hook in a Blueprint, but this is the first such
case where we need app.config in the Blueprint.
d94efc6
@rduplain
Collaborator

This is now fully configurable through SEND_FILE_MAX_AGE_DEFAULT for both Flask and Blueprint static files. Thanks @dave-shawley for introducing this thread of changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 12, 2012
  1. @dave-shawley

    Added _PackageBoundObject.get_static_file_options.

    dave-shawley authored
    This method receives the name of a static file that is going to be served
    up and generates a dict of options to use when serving the file.  The
    default set is empty so code will fall back to the existing behavior if
    the method is not overridden.
    
    I needed this method to adjust the cache control headers for .js files that
    one of my applications was statically serving.  The default expiration is
    buried in an argument to send_file and is set to 12 hours.  There was no
    good way to adjust this value previously.
This page is out of date. Refresh to see the latest.
Showing with 34 additions and 3 deletions.
  1. +9 −2 flask/helpers.py
  2. +25 −1 flask/testsuite/helpers.py
View
11 flask/helpers.py
@@ -495,7 +495,8 @@ def download_file(filename):
filename = safe_join(directory, filename)
if not os.path.isfile(filename):
raise NotFound()
- return send_file(filename, conditional=True, **options)
+ options.setdefault('conditional', True)
+ return send_file(filename, **options)
def get_root_path(import_name):
@@ -651,6 +652,11 @@ def jinja_loader(self):
return FileSystemLoader(os.path.join(self.root_path,
self.template_folder))
+ def get_static_file_options(self, filename):
+ """Function used internally to determine what keyword arguments
+ to send to :func:`send_from_directory` for a specific file."""
+ return {}
+
def send_static_file(self, filename):
"""Function used internally to send static files from the static
folder to the browser.
@@ -659,7 +665,8 @@ def send_static_file(self, filename):
"""
if not self.has_static_folder:
raise RuntimeError('No static folder for this object')
- return send_from_directory(self.static_folder, filename)
+ return send_from_directory(self.static_folder, filename,
+ **self.get_static_file_options(filename))
def open_resource(self, resource, mode='rb'):
"""Opens a resource from the application's resource folder. To see
View
26 flask/testsuite/helpers.py
@@ -17,7 +17,7 @@
from logging import StreamHandler
from StringIO import StringIO
from flask.testsuite import FlaskTestCase, catch_warnings, catch_stderr
-from werkzeug.http import parse_options_header
+from werkzeug.http import parse_cache_control_header, parse_options_header
def has_encoding(name):
@@ -204,6 +204,30 @@ def test_attachment(self):
self.assert_equal(value, 'attachment')
self.assert_equal(options['filename'], 'index.txt')
+ def test_static_file(self):
+ app = flask.Flask(__name__)
+ # default cache timeout is 12 hours (hard-coded)
+ with app.test_request_context():
+ rv = app.send_static_file('index.html')
+ cc = parse_cache_control_header(rv.headers['Cache-Control'])
+ self.assert_equal(cc.max_age, 12 * 60 * 60)
+ # override get_static_file_options with some new values and check them
+ class StaticFileApp(flask.Flask):
+ def __init__(self):
+ super(StaticFileApp, self).__init__(__name__)
+ def get_static_file_options(self, filename):
+ opts = super(StaticFileApp, self).get_static_file_options(filename)
+ opts['cache_timeout'] = 10
+ # this test catches explicit inclusion of the conditional
+ # keyword arg in the guts
+ opts['conditional'] = True
+ return opts
+ app = StaticFileApp()
+ with app.test_request_context():
+ rv = app.send_static_file('index.html')
+ cc = parse_cache_control_header(rv.headers['Cache-Control'])
+ self.assert_equal(cc.max_age, 10)
+
class LoggingTestCase(FlaskTestCase):
Something went wrong with that request. Please try again.