diff options
author | Robert Brewer <fumanchu@aminus.org> | 2009-08-19 04:18:00 +0000 |
---|---|---|
committer | Robert Brewer <fumanchu@aminus.org> | 2009-08-19 04:18:00 +0000 |
commit | af86de9e4025d73a5afb2ccae19de67c4beff9df (patch) | |
tree | a7dbdca0bdd1c8bd96f44eed3e4a563dfbde55e3 /cherrypy/lib/caching.py | |
parent | 1665471d0c872ee4f0449d04e5160a02a78f7c2f (diff) | |
download | cherrypy-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.py | 53 |
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) |