diff options
author | Robert Brewer <fumanchu@aminus.org> | 2007-10-28 18:28:42 +0000 |
---|---|---|
committer | Robert Brewer <fumanchu@aminus.org> | 2007-10-28 18:28:42 +0000 |
commit | a3677089a850e7527e51a8cf5381db89dd04ee9e (patch) | |
tree | d58e2614bb338a221564566ce6b1df11f0c83afa /cherrypy/lib/caching.py | |
parent | 38372cd6eceddb86a07dfdd935844b200917e0de (diff) | |
download | cherrypy-git-a3677089a850e7527e51a8cf5381db89dd04ee9e.tar.gz |
Forward port to trunk from 3.0.x [1703]. Added checking of 'Vary' header before responding with cached content.
Diffstat (limited to 'cherrypy/lib/caching.py')
-rw-r--r-- | cherrypy/lib/caching.py | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/cherrypy/lib/caching.py b/cherrypy/lib/caching.py index c49f315b..2eab8447 100644 --- a/cherrypy/lib/caching.py +++ b/cherrypy/lib/caching.py @@ -123,9 +123,28 @@ def get(invalid_methods=("POST", "PUT", "DELETE"), **kwargs): request.cacheable = not c if c: response = cherrypy.response - s, h, b, create_time = cache_data + s, h, b, create_time, original_req_headers = cache_data - # Make a copy. See http://www.cherrypy.org/ticket/721 + # Check 'Vary' selecting headers. If any headers mentioned in "Vary" + # differ between the cached and current request, bail out and + # let the rest of CP handle the request. This should properly + # mimic the behavior of isolated caches as RFC 2616 assumes: + # "If the selecting request header fields for the cached entry + # do not match the selecting request header fields of the new + # request, then the cache MUST NOT use a cached entry to satisfy + # the request unless it first relays the new request to the origin + # server in a conditional request and the server responds with + # 304 (Not Modified), including an entity tag or Content-Location + # that indicates the entity to be used. + # TODO: can we store multiple variants based on Vary'd headers? + for header_element in h.elements('Vary'): + key = header_element.value + if original_req_headers[key] != request.headers.get(key, 'missing'): + request.cached = False + request.cacheable = True + return False + + # Copy the response headers. See http://www.cherrypy.org/ticket/721. response.headers = rh = http.HeaderMap() for k in h: dict.__setitem__(rh, k, dict.__getitem__(h, k)) @@ -161,8 +180,16 @@ def tee_output(): if response.headers.get('Pragma', None) != 'no-cache': # save the cache data body = ''.join(output) + vary = [he.value for he in + cherrypy.response.headers.elements('Vary')] + if vary: + sel_headers = dict([(k, v) for k, v + in cherrypy.request.headers.iteritems() + if k in vary]) + else: + sel_headers = {} cherrypy._cache.put((response.status, response.headers or {}, - body, response.time)) + body, response.time, sel_headers)) response = cherrypy.response response.body = tee(response.body) |