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

Changeset 1796

Show
Ignore:
Timestamp:
10/28/07 13:28:42
Author:
fumanchu
Message:

Forward port to trunk from 3.0.x [1703]. Added checking of 'Vary' header before responding with cached content.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/lib/caching.py

    r1795 r1796  
    124124    if c: 
    125125        response = cherrypy.response 
    126         s, h, b, create_time = cache_data 
    127          
    128         # Make a copy. See http://www.cherrypy.org/ticket/721 
     126        s, h, b, create_time, original_req_headers = cache_data 
     127         
     128        # Check 'Vary' selecting headers. If any headers mentioned in "Vary" 
     129        # differ between the cached and current request, bail out and 
     130        # let the rest of CP handle the request. This should properly 
     131        # mimic the behavior of isolated caches as RFC 2616 assumes: 
     132        # "If the selecting request header fields for the cached entry 
     133        # do not match the selecting request header fields of the new 
     134        # request, then the cache MUST NOT use a cached entry to satisfy 
     135        # the request unless it first relays the new request to the origin 
     136        # server in a conditional request and the server responds with 
     137        # 304 (Not Modified), including an entity tag or Content-Location 
     138        # that indicates the entity to be used. 
     139        # TODO: can we store multiple variants based on Vary'd headers? 
     140        for header_element in h.elements('Vary'): 
     141            key = header_element.value 
     142            if original_req_headers[key] != request.headers.get(key, 'missing'): 
     143                request.cached = False 
     144                request.cacheable = True 
     145                return False 
     146         
     147        # Copy the response headers. See http://www.cherrypy.org/ticket/721. 
    129148        response.headers = rh = http.HeaderMap() 
    130149        for k in h: 
     
    162181            # save the cache data 
    163182            body = ''.join(output) 
     183            vary = [he.value for he in 
     184                    cherrypy.response.headers.elements('Vary')] 
     185            if vary: 
     186                sel_headers = dict([(k, v) for k, v 
     187                                    in cherrypy.request.headers.iteritems() 
     188                                    if k in vary]) 
     189            else: 
     190                sel_headers = {} 
    164191            cherrypy._cache.put((response.status, response.headers or {}, 
    165                                  body, response.time)) 
     192                                 body, response.time, sel_headers)) 
    166193     
    167194    response = cherrypy.response 
  • trunk/cherrypy/test/test_caching.py

    r1790 r1796  
    22test.prefer_parent_path() 
    33 
     4import gzip 
    45import os 
    56curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 
     7import StringIO 
    68 
    79import cherrypy 
     
    6971    cherrypy.tree.mount(Root()) 
    7072    cherrypy.tree.mount(UnCached(), "/expires") 
    71     cherrypy.config.update({'environment': 'test_suite'}) 
     73    cherrypy.config.update({'environment': 'test_suite', 
     74                            'tools.gzip.on': True}) 
    7275 
    7376 
     
    100103        self.getPage("/", method="DELETE") 
    101104        self.assertBody('visit #4') 
     105         
    102106        # The previous request should have invalidated the cache, 
    103107        # so this request will recalc the response. 
     108        zbuf = StringIO.StringIO() 
     109        zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=9) 
     110        zfile.write("visit #5") 
     111        zfile.close() 
     112         
     113        self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')]) 
     114        self.assertHeader('Content-Encoding', 'gzip') 
     115        self.assertInBody(zbuf.getvalue()[:3]) 
     116         
     117        # Now check that a second request gets the gzip header and gzipped body 
     118        self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')]) 
     119        self.assertHeader('Content-Encoding', 'gzip') 
     120        self.assertInBody(zbuf.getvalue()[:3]) 
     121         
     122        # Now check that a third request that doesn't accept gzip 
     123        # gets another hit. 
    104124        self.getPage("/", method="GET") 
    105         self.assertBody('visit #5') 
     125        self.assertNoHeader('Content-Encoding') 
     126        self.assertBody('visit #6') 
    106127     
    107128    def testExpiresTool(self): 
  • trunk/cherrypy/test/test_encoding.py

    r1384 r1796  
    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