summaryrefslogtreecommitdiff
path: root/cherrypy/lib/caching.py
diff options
context:
space:
mode:
authorRobert Brewer <fumanchu@aminus.org>2009-08-19 04:18:00 +0000
committerRobert Brewer <fumanchu@aminus.org>2009-08-19 04:18:00 +0000
commitaf86de9e4025d73a5afb2ccae19de67c4beff9df (patch)
treea7dbdca0bdd1c8bd96f44eed3e4a563dfbde55e3 /cherrypy/lib/caching.py
parent1665471d0c872ee4f0449d04e5160a02a78f7c2f (diff)
downloadcherrypy-git-af86de9e4025d73a5afb2ccae19de67c4beff9df.tar.gz
Fix for #918 (caching does not respect Cache-Control: max-age header).
Diffstat (limited to 'cherrypy/lib/caching.py')
-rw-r--r--cherrypy/lib/caching.py53
1 files changed, 45 insertions, 8 deletions
diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py
index f9a0e9bf..62949359 100644
--- a/cherrypy/lib/caching.py
+++ b/cherrypy/lib/caching.py
@@ -204,7 +204,6 @@ class MemoryCache(Cache):
uricache[tuple(header_values)] = variant
self.tot_puts += 1
self.cursize = total_size
- return
def delete(self):
"""Remove ALL cached variants of the current resource."""
@@ -258,14 +257,44 @@ def get(invalid_methods=("POST", "PUT", "DELETE"), debug=False, **kwargs):
request.cacheable = False
return False
+ if 'no-cache' in [e.value for e in request.headers.elements('Pragma')]:
+ request.cached = False
+ request.cacheable = True
+ return False
+
cache_data = cherrypy._cache.get()
request.cached = bool(cache_data)
request.cacheable = not request.cached
if request.cached:
# Serve the cached copy.
+ max_age = cherrypy._cache.delay
+ for v in [e.value for e in request.headers.elements('Cache-Control')]:
+ atoms = v.split('=', 1)
+ directive = atoms.pop(0)
+ if directive == 'max-age':
+ if len(atoms) != 1 or not atoms[0].isdigit():
+ raise cherrypy.HTTPError(400, "Invalid Cache-Control header")
+ max_age = int(atoms[0])
+ break
+ elif directive == 'no-cache':
+ if debug:
+ cherrypy.log('Ignoring cache due to Cache-Control: no-cache',
+ 'TOOLS.CACHING')
+ request.cached = False
+ request.cacheable = True
+ return False
+
if debug:
cherrypy.log('Reading response from cache', 'TOOLS.CACHING')
s, h, b, create_time = cache_data
+ age = int(response.time - create_time)
+ if (age > max_age):
+ if debug:
+ cherrypy.log('Ignoring cache due to age > %d' % max_age,
+ 'TOOLS.CACHING')
+ request.cached = False
+ request.cacheable = True
+ return False
# Copy the response headers. See http://www.cherrypy.org/ticket/721.
response.headers = rh = httputil.HeaderMap()
@@ -273,7 +302,7 @@ def get(invalid_methods=("POST", "PUT", "DELETE"), debug=False, **kwargs):
dict.__setitem__(rh, k, dict.__getitem__(h, k))
# Add the required Age header
- response.headers["Age"] = str(int(response.time - create_time))
+ response.headers["Age"] = str(age)
try:
# Note that validate_since depends on a Last-Modified header;
@@ -295,19 +324,27 @@ def get(invalid_methods=("POST", "PUT", "DELETE"), debug=False, **kwargs):
def tee_output():
+ request = cherrypy.serving.request
+ if 'no-store' in request.headers.values('Cache-Control'):
+ return
+
def tee(body):
"""Tee response.body into a list."""
+ if ('no-cache' in response.headers.values('Pragma') or
+ 'no-store' in response.headers.values('Cache-Control')):
+ for chunk in body:
+ yield chunk
+ return
+
output = []
for chunk in body:
output.append(chunk)
yield chunk
- # Might as well do this here; why cache if the body isn't consumed?
- if response.headers.get('Pragma', None) != 'no-cache':
- # save the cache data
- body = ''.join(output)
- cherrypy._cache.put((response.status, response.headers or {},
- body, response.time), len(body))
+ # save the cache data
+ body = ''.join(output)
+ cherrypy._cache.put((response.status, response.headers or {},
+ body, response.time), len(body))
response = cherrypy.serving.response
response.body = tee(response.body)