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

Changeset 1506

Show
Ignore:
Timestamp:
12/10/06 16:48:58
Author:
fumanchu
Message:

2.x backport of [1202], [1203] (new expires function, plus Response.time attribute).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cherrypy-2.x/cherrypy/_cphttptools.py

    r1504 r1506  
    44import os 
    55import sys 
     6import time 
    67import types 
    78 
     
    365366        self.header_list = None 
    366367        self.body = None 
     368        self.time = time.time() 
    367369         
    368370        self.headers = httptools.HeaderMap() 
     
    372374            "Content-Type": content_type, 
    373375            "Server": "CherryPy/" + cherrypy.__version__, 
    374             "Date": httptools.HTTPDate(), 
     376            "Date": httptools.HTTPDate(time.gmtime(self.time)), 
    375377            "Set-Cookie": [], 
    376378            "Content-Length": None 
  • branches/cherrypy-2.x/cherrypy/filters/cachefilter.py

    r1494 r1506  
    1  
     1import datetime 
     2import Queue 
    23import threading 
    3 import Queue 
    44import time 
    55 
    66import cherrypy 
     7from cherrypy.lib import httptools 
    78import basefilter 
    89 
     
    212213        yield "Total non-modified content: %d\n" % cache.totNonModified 
    213214    index.exposed = True 
     215 
     216 
     217def expires(secs=0, force=False): 
     218    """Tool for influencing cache mechanisms using the 'Expires' header. 
     219     
     220    'secs' must be either an int or a datetime.timedelta, and indicates the 
     221    number of seconds between response.time and when the response should 
     222    expire. The 'Expires' header will be set to (response.time + secs). 
     223     
     224    If 'secs' is zero, the following "cache prevention" headers are also set: 
     225       'Pragma': 'no-cache' 
     226       'Cache-Control': 'no-cache' 
     227     
     228    If 'force' is False (the default), the following headers are checked: 
     229    'Etag', 'Last-Modified', 'Age', 'Expires'. If any are already present, 
     230    none of the above response headers are set. 
     231    """ 
     232     
     233    response = cherrypy.response 
     234     
     235    cacheable = False 
     236    if not force: 
     237        # some header names that indicate that the response can be cached 
     238        for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'): 
     239            if indicator in response.headers: 
     240                cacheable = True 
     241                break 
     242     
     243    if not cacheable: 
     244        if isinstance(secs, datetime.timedelta): 
     245            secs = (86400 * secs.days) + secs.seconds 
     246         
     247        if secs == 0: 
     248            if force or ("Pragma" not in response.headers): 
     249                response.headers["Pragma"] = "no-cache" 
     250            if cherrypy.response.version >= "1.1": 
     251                if force or ("Cache-Control" not in response.headers): 
     252                    response.headers["Cache-Control"] = "no-cache" 
     253         
     254        expiry = httptools.HTTPDate(time.gmtime(response.time + secs)) 
     255        if force or ("Expires" not in response.headers): 
     256            response.headers["Expires"] = expiry 
  • branches/cherrypy-2.x/cherrypy/test/test_cache_filter.py

    r1494 r1506  
    33 
    44import cherrypy 
    5 import time 
     5from cherrypy.filters.cachefilter import expires 
    66 
    77 
     
    1616            return msg 
    1717        index.exposed = True 
    18  
     18     
     19    class UnCached(object): 
     20         
     21        use_force = False 
     22         
     23        def force(self): 
     24            self.use_force = True 
     25            expires(force=self.use_force) 
     26            return "being forceful" 
     27        force.exposed = True 
     28         
     29        def dynamic(self): 
     30            cherrypy.response.headers['Cache-Control'] = 'private' 
     31            expires(force=self.use_force) 
     32            return "D-d-d-dynamic!" 
     33        dynamic.exposed = True 
     34         
     35        def cacheable(self): 
     36            cherrypy.response.headers['Etag'] = 'bibbitybobbityboo' 
     37            expires(force=self.use_force) 
     38            return "Hi, I'm cacheable." 
     39        cacheable.exposed = True 
     40         
     41        def specific(self): 
     42            expires(secs=86400, force=self.use_force) 
     43            return "I am being specific" 
     44        specific.exposed = True 
     45     
    1946    cherrypy.root = Root() 
     47    cherrypy.root.expires = UnCached() 
    2048    cherrypy.config.update({ 
    21             'server.log_to_screen': False, 
    22             'server.environment': 'production', 
    23             'cache_filter.on': True, 
     49        'global': {'server.log_to_screen': False, 
     50                   'server.environment': 'production', 
     51                   'cache_filter.on': True, 
     52                   }, 
     53        '/expires': {'cache_filter.on': False}, 
    2454    }) 
    2555 
     
    5181        self.getPage("/", method="GET") 
    5282        self.assertBody('visit #5') 
     83     
     84    def testExpiresTool(self): 
     85         
     86        # test setting an expires header 
     87        self.getPage("/expires/specific") 
     88        self.assertStatus("200 OK") 
     89        self.assertHeader("Expires") 
     90         
     91        # dynamic content that sets indicators should not have 
     92        # "cache prevention" headers 
     93        self.getPage("/expires/cacheable") 
     94        self.assertStatus("200 OK") 
     95        self.assertNoHeader("Pragma") 
     96        self.assertNoHeader("Cache-Control") 
     97         
     98        self.getPage('/expires/dynamic') 
     99        self.assertBody("D-d-d-dynamic!") 
     100        # the Cache-Control header should be untouched 
     101        self.assertHeader("Cache-Control", "private") 
     102         
     103        # configure the tool to ignore indicators and replace existing headers 
     104        self.getPage("/expires/force") 
     105        self.assertStatus("200 OK") 
     106        # This also gives us a chance to test 0 expiry with no other headers 
     107        self.assertHeader("Pragma", "no-cache") 
     108        conf = cherrypy.config.get 
     109        if conf('server.protocol_version', '') == "HTTP/1.1": 
     110            self.assertHeader("Cache-Control", "no-cache") 
     111        d = self.assertHeader("Date") 
     112        self.assertHeader("Expires", d) 
     113         
     114        # the cacheable handler should now have "cache prevention" headers 
     115        self.getPage("/expires/cacheable") 
     116        self.assertStatus("200 OK") 
     117        self.assertHeader("Pragma", "no-cache") 
     118        if conf('server.protocol_version', '') == "HTTP/1.1": 
     119            self.assertHeader("Cache-Control", "no-cache") 
     120        d = self.assertHeader("Date") 
     121        self.assertHeader("Expires", d) 
     122         
     123        self.getPage('/expires/dynamic') 
     124        self.assertBody("D-d-d-dynamic!") 
     125        # dynamic sets Cache-Control to private but it should  be 
     126        # overwritten here ... 
     127        self.assertHeader("Pragma", "no-cache") 
     128        if conf('server.protocol_version', '') == "HTTP/1.1": 
     129            self.assertHeader("Cache-Control", "no-cache") 
     130        d = self.assertHeader("Date") 
     131        self.assertHeader("Expires", d) 
    53132 
    54133 

Hosted by WebFaction

Log in as guest/cpguest to create tickets