Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1703

Show
Ignore:
Timestamp:
08/19/07 23:08:27
Author:
fumanchu
Message:

3.0.x: Added checking of 'Vary' header before responding with cached content.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cherrypy-3.0.x/cherrypy/lib/caching.py

    r1637 r1703  
    129129    if c: 
    130130        response = cherrypy.response 
    131         s, response.headers, b, create_time = cache_data 
     131        s, h, b, create_time, original_req_headers = cache_data 
     132         
     133        # Check 'Vary' selecting headers. If any headers mentioned in "Vary" 
     134        # differ between the cached and current request, bail out and 
     135        # let the rest of CP handle the request. This should properly 
     136        # mimic the behavior of isolated caches as RFC 2616 assumes: 
     137        # "If the selecting request header fields for the cached entry 
     138        # do not match the selecting request header fields of the new 
     139        # request, then the cache MUST NOT use a cached entry to satisfy 
     140        # the request unless it first relays the new request to the origin 
     141        # server in a conditional request and the server responds with 
     142        # 304 (Not Modified), including an entity tag or Content-Location 
     143        # that indicates the entity to be used. 
     144        # TODO: can we store multiple variants based on Vary'd headers? 
     145        for header_element in h.elements('Vary'): 
     146            key = header_element.value 
     147            if original_req_headers[key] != request.headers.get(key, 'missing'): 
     148                request.cached = False 
     149                request.cacheable = True 
     150                return False 
    132151         
    133152        # Add the required Age header 
     153        response.headers = h 
    134154        response.headers["Age"] = str(int(response.time - create_time)) 
    135155         
     
    158178            output.append(chunk) 
    159179            yield chunk 
     180         
    160181        # Might as well do this here; why cache if the body isn't consumed? 
    161182        if response.headers.get('Pragma', None) != 'no-cache': 
    162183            # save the cache data 
    163184            body = ''.join([chunk for chunk in output]) 
     185            vary = [he.value for he in 
     186                    cherrypy.response.headers.elements('Vary')] 
     187            if vary: 
     188                sel_headers = dict([(k, v) for k, v 
     189                                    in cherrypy.request.headers.iteritems() 
     190                                    if k in vary]) 
     191            else: 
     192                sel_headers = {} 
    164193            cherrypy._cache.put((response.status, response.headers or {}, 
    165                                  body, response.time)) 
     194                                 body, response.time, sel_headers)) 
    166195    response.body = tee(response.body) 
    167196 
  • branches/cherrypy-3.0.x/cherrypy/test/test_caching.py

    r1595 r1703  
    22test.prefer_parent_path() 
    33 
     4import gzip 
    45import os 
    56curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 
     7import StringIO 
    68 
    79import cherrypy 
     
    5961    cherrypy.tree.mount(Root()) 
    6062    cherrypy.tree.mount(UnCached(), "/expires") 
    61     cherrypy.config.update({'environment': 'test_suite'}) 
     63    cherrypy.config.update({'environment': 'test_suite', 
     64                            'tools.gzip.on': 'True'}) 
    6265 
    6366 
     
    9093        self.getPage("/", method="DELETE") 
    9194        self.assertBody('visit #4') 
     95         
    9296        # The previous request should have invalidated the cache, 
    9397        # so this request will recalc the response. 
     98        zbuf = StringIO.StringIO() 
     99        zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=9) 
     100        zfile.write("visit #5") 
     101        zfile.close() 
     102         
     103        self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')]) 
     104        self.assertHeader('Content-Encoding', 'gzip') 
     105        self.assertInBody(zbuf.getvalue()[:3]) 
     106         
     107        # Now check that a second request gets the gzip header and gzipped body 
     108        self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')]) 
     109        self.assertHeader('Content-Encoding', 'gzip') 
     110        self.assertInBody(zbuf.getvalue()[:3]) 
     111         
     112        # Now check that a third request that doesn't accept gzip 
     113        # gets another hit. 
    94114        self.getPage("/", method="GET") 
    95         self.assertBody('visit #5') 
     115        self.assertNoHeader('Content-Encoding') 
     116        self.assertBody("visit #6") 
    96117     
    97118    def testExpiresTool(self): 
  • branches/cherrypy-3.0.x/cherrypy/test/test_encoding.py

    r1384 r1703  
    118118        self.assertInBody(zbuf.getvalue()[:3]) 
    119119        self.assertHeader("Vary", "Accept-Encoding") 
     120        self.assertHeader('Content-Encoding', 'gzip') 
    120121         
    121122        # Test when gzip is denied. 

Hosted by WebFaction

Log in as guest/cpguest to create tickets