?_ttl= parameter and default_cache_ttl config

Refs #285, Closes #289
This commit is contained in:
Simon Willison 2018-05-26 15:17:33 -07:00
commit b463f60158
No known key found for this signature in database
GPG key ID: 17E2DEA2588B7F52
5 changed files with 39 additions and 1 deletions

View file

@ -83,6 +83,9 @@ CONFIG_OPTIONS = (
ConfigOption("allow_sql", True, """ ConfigOption("allow_sql", True, """
Allow arbitrary SQL queries via ?sql= parameter Allow arbitrary SQL queries via ?sql= parameter
""".strip()), """.strip()),
ConfigOption("default_cache_ttl", 365 * 24 * 60 * 60, """
Default HTTP cache TTL (used in Cache-Control: max-age= header)
""".strip()),
) )
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
option.name: option.default option.name: option.default

View file

@ -257,7 +257,17 @@ class BaseView(RenderMixin):
r.status = status_code r.status = status_code
# Set far-future cache expiry # Set far-future cache expiry
if self.ds.cache_headers: if self.ds.cache_headers:
r.headers["Cache-Control"] = "max-age={}".format(365 * 24 * 60 * 60) ttl = request.args.get("_ttl", None)
if ttl is None or not ttl.isdigit():
ttl = self.ds.config["default_cache_ttl"]
else:
ttl = int(ttl)
if ttl == 0:
ttl_header = 'no-cache'
else:
ttl_header = 'max-age={}'.format(ttl)
r.headers["Cache-Control"] = ttl_header
r.headers["Referrer-Policy"] = "no-referrer"
return r return r
async def custom_sql( async def custom_sql(

View file

@ -92,3 +92,12 @@ allow_sql
Enable/disable the ability for users to run custom SQL directly against a database. To disable this feature, run:: Enable/disable the ability for users to run custom SQL directly against a database. To disable this feature, run::
datasette mydatabase.db --config allow_sql:off datasette mydatabase.db --config allow_sql:off
default_cache_ttl
-----------------
Default HTTP caching max-age header in seconds, used for ``Cache-Control: max-age=X``. Can be over-ridden on a per-request basis using the ``?_ttl=`` querystring parameter. Set this to ``0`` to disable HTTP caching entirely. Defaults to 365 days (31536000 seconds).
::
datasette mydatabase.db --config default_cache_ttl:10

View file

@ -164,6 +164,10 @@ The Datasette table view takes a number of special querystring arguments:
long, for example if you want to implement autocomplete search but only if long, for example if you want to implement autocomplete search but only if
it can be executed in less than 10ms. it can be executed in less than 10ms.
``?_ttl=SECONDS``
For how many seconds should this response be cached by HTTP proxies? Use
``?_ttl=0`` to disable HTTP caching entirely for this request.
``?_next=TOKEN`` ``?_next=TOKEN``
Pagination by continuation token - pass the token that was returned in the Pagination by continuation token - pass the token that was returned in the
``"next"`` property by the previous page. ``"next"`` property by the previous page.

View file

@ -928,6 +928,7 @@ def test_config_json(app_client):
"allow_facet": True, "allow_facet": True,
"suggest_facets": True, "suggest_facets": True,
"allow_sql": True, "allow_sql": True,
"default_cache_ttl": 365 * 24 * 60 * 60,
} == response.json } == response.json
@ -1127,3 +1128,14 @@ def test_suggest_facets_off():
"/test_tables/facetable.json", "/test_tables/facetable.json",
gather_request=False gather_request=False
).json["suggested_facets"] ).json["suggested_facets"]
@pytest.mark.parametrize('path,expected_cache_control', [
("/test_tables/facetable.json", "max-age=31536000"),
("/test_tables/facetable.json?_ttl=invalid", "max-age=31536000"),
("/test_tables/facetable.json?_ttl=10", "max-age=10"),
("/test_tables/facetable.json?_ttl=0", "no-cache"),
])
def test_ttl_parameter(app_client, path, expected_cache_control):
response = app_client.get(path, gather_request=False)
assert expected_cache_control == response.headers['Cache-Control']