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

Changeset 1203

Show
Ignore:
Timestamp:
07/17/06 16:34:54
Author:
fumanchu
Message:

More work on tools.expires:

  1. Now takes 'secs' arg instead of 'e_time'.
  2. The 'force' arg defaults to False now.
  3. Set 'force' to True to imply ignore_indicators.
  4. New cherrypy.reponse.time attribute: the time.time() which is used for the 'Date' response header.
Files:

Legend:

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

    r1141 r1203  
    7070         
    7171        # RFC 2616 indicates a 301 response code fits our goal; however, 
    72         # browser support for 301 is quite messy. Do 302 instead. See 
     72        # browser support for 301 is quite messy. Do 302/303 instead. See 
    7373        # http://ppewww.ph.gla.ac.uk/~flavell/www/post-redirect.html 
    7474        if status is None: 
  • trunk/cherrypy/_cprequest.py

    r1201 r1203  
    44import os 
    55import sys 
     6import time 
    67import types 
    78 
     
    642643        self.header_list = None 
    643644        self.body = None 
     645        self.time = time.time() 
    644646         
    645647        self.headers = http.HeaderMap() 
     
    650652            "Content-Type": content_type, 
    651653            "Server": "CherryPy/" + cherrypy.__version__, 
    652             "Date": http.HTTPDate(), 
     654            "Date": http.HTTPDate(self.time), 
    653655            "Set-Cookie": [], 
    654656            "Content-Length": None 
  • trunk/cherrypy/lib/caching.py

    r1202 r1203  
    167167    cherrypy.request.hooks.attach('before_main', _wrapper) 
    168168 
    169 def expires(e_time=0, ignore_indicators=False, force=True): 
     169def expires(secs=0, force=False): 
    170170    """Tool for influencing cache mechanisms using the 'Expires' header. 
    171  
    172     e_time can either be a datetime.datetime instance or number zero. 
    173  
    174     If a datetime.datetime instance is supplied, the 'Expires' header will be 
    175     set to that value. 
    176  
    177     If a number zero is supplied, the following "cache prevention" headers 
    178     are set: 
    179        'Expires': '0' 
     171     
     172    'secs' must be either an int or a datetime.timedelta, and indicates the 
     173    number of seconds between response.time and when the response should 
     174    expire. The 'Expires' header will be set to (response.time + secs). 
     175     
     176    If 'secs' is zero, the following "cache prevention" headers are also set: 
    180177       'Pragma': 'no-cache' 
    181        'Cache-Control: 'no-cache' 
    182  
    183     By default, if e_time is set to zero, the tool checks to see if the 
    184     response already includes some common "cacheability indicator" headers. 
    185     If they are present, the "cache prevention" headers are not set.  This 
    186     behavior can be overridden by setting the ignore_indicators parameter 
    187     to True. 
    188  
    189     Setting force to False will keep the tool from overwriting any headers 
    190     that are already present in the response. 
     178       'Cache-Control': 'no-cache' 
     179     
     180    If 'force' is False (the default), the following headers are checked: 
     181    'Etag', 'Last-Modified', 'Age', 'Expires'. If any are already present, 
     182    none of the "cache prevention" headers are set. 
    191183    """ 
    192  
    193     if e_time and isinstance(e_time, datetime.datetime): 
    194         e_time = http.HTTPDate(time.mktime(e_time.timetuple())) 
    195         cptools.response_headers([("Expires", e_time)], force) 
    196         return 
    197  
    198     try: 
    199         if not(int(e_time)): 
     184     
     185    if isinstance(secs, datetime.timedelta): 
     186        secs = (86400 * secs.days) + secs.seconds 
     187    expiry = http.HTTPDate(cherrypy.response.time + secs) 
     188    cptools.response_headers([("Expires", expiry)], force) 
     189     
     190    if secs == 0: 
     191        cacheable = False 
     192        if not force: 
    200193            # some header names that indicate that the response can be cached 
    201             indicators = set(('Etag', 'Last-Modified', 'Age', 'Expires')) 
    202             cacheable = indicators.intersection(set(cherrypy.response.headers)) 
    203             if not e_time and (ignore_indicators or not cacheable): 
    204                 cptools.response_headers([("Pragma", "no-cache"), 
    205                                           ("Expires", "0")], force) 
    206                 if cherrypy.request.version >= (1, 1): 
    207                     cptools.response_headers([("Cache-Control", "no-cache")], force) 
    208  
    209         else: 
    210             raise ValueError("e_time value must be number zero or a datetime." 
    211                              "datetime instance") 
    212  
    213     except TypeError, e: 
    214         e.args = ["e_time value must be datetime.datetime instance or number" 
    215                   "zero."] 
    216         raise 
     194            for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'): 
     195                if indicator in cherrypy.response.headers: 
     196                    cacheable = True 
     197                    break 
     198        if not cacheable: 
     199            cptools.response_headers([("Pragma", "no-cache")], force) 
     200            if cherrypy.request.version >= (1, 1): 
     201                cptools.response_headers([("Cache-Control", "no-cache")], force) 
  • trunk/cherrypy/lib/cptools.py

    r1171 r1203  
    6363 
    6464def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For'): 
    65     """Change the base URL (scheme://host[:port]). 
     65    """Change the base URL (scheme://host[:port][/path]). 
    6666     
    6767    Useful when running a CP server behind Apache. 
     68     
     69    If you want the new request.base to include path info (not just the host), 
     70    you must explicitly set base to the full base path, and ALSO set 'local' 
     71    to '', so that the X-Forwarded-Host request header (which never includes 
     72    path info) does not override it. 
    6873    """ 
    6974     
  • trunk/cherrypy/test/test_caching.py

    r1202 r1203  
    66 
    77import cherrypy 
    8 import datetime 
    9 import time 
    108 
    119 
    1210def setup_server(): 
     11     
    1312    class Root: 
    1413         
     
    3130                      } 
    3231 
    33         def gentle(self): 
    34             self._cp_config['tools.expires.force'] = Fals
     32        def force(self): 
     33            self._cp_config['tools.expires.force'] = Tru
    3534            return "being forceful" 
    36         gentle.exposed = True 
    37  
    38         def ignorant(self): 
    39             self._cp_config['tools.expires.ignore_indicators'] = True 
    40             return "being ignorant" 
    41         ignorant.exposed = True 
     35        force.exposed = True 
    4236 
    4337        def dynamic(self): 
     
    5145        cacheable.exposed = True 
    5246 
    53         expire_on = datetime.datetime(2006, 7, 17, 8, 55, 59, 171000) 
    54  
    5547        def specific(self): 
    5648            return "I am being specific" 
    5749        specific.exposed = True 
    58         specific._cp_config = {'tools.expires.e_time': expire_on
     50        specific._cp_config = {'tools.expires.secs': 86400
    5951 
    6052        class Foo(object):pass 
     
    6355            return "Woops" 
    6456        wrongtype.exposed = True 
    65         wrongtype._cp_config = {'tools.expires.e_time': Foo()} 
    66  
    67         def wrongvalue(self): 
    68             return "Uh oh" 
    69         wrongvalue.exposed = True 
    70         wrongvalue._cp_config = {'tools.expires.e_time': 42} 
    71  
    72  
     57        wrongtype._cp_config = {'tools.expires.secs': Foo()} 
     58     
    7359    cherrypy.tree.mount(Root()) 
    7460    cherrypy.tree.mount(UnCached(), "/expires") 
     
    10591 
    10692    def testExpiresTool(self): 
    107  
    108         # test setting a specific expires header 
     93         
     94        # test setting an expires header 
    10995        self.getPage("/expires/specific") 
    11096        self.assertStatus("200 OK") 
    111         self.assertHeader("Expires", "Mon, 17 Jul 2006 12:55:59 GMT"
    112  
    113         # test exceptions for bad e_time values 
     97        self.assertHeader("Expires"
     98         
     99        # test exceptions for bad time values 
    114100        self.getPage("/expires/wrongtype") 
    115101        self.assertStatus("500 Internal error") 
    116102        self.assertInBody("TypeError") 
    117  
    118         self.getPage("/expires/wrongvalue") 
    119         self.assertStatus("500 Internal error") 
    120         self.assertInBody("ValueError") 
    121  
    122         self.getPage('/expires/dynamic') 
    123         self.assertBody("D-d-d-dynamic!") 
    124         # dynamic sets Cache-Control to private but it should  be 
    125         # overwritten here ... 
    126         self.assertHeader("Cache-Control", "no-cache") 
    127         self.assertHeader("Expires", "0") 
    128         self.assertHeader("Pragma", "no-cache") 
    129  
    130         # configure the tool to keep existing headers 
    131         self.getPage("/expires/gentle") 
    132         self.assertStatus("200 OK") 
    133  
    134         self.getPage('/expires/dynamic') 
    135         self.assertBody("D-d-d-dynamic!") 
    136         # the Cache-Control header should now be untouched 
    137         self.assertHeader("Cache-Control", "private") 
    138  
     103         
    139104        # static content should not have "cache prevention" headers 
    140105        self.getPage("/expires/index.html") 
     
    142107        self.assertNoHeader("Pragma") 
    143108        self.assertNoHeader("Cache-Control") 
    144         self.assertNoHeader("Expires") 
    145  
     109         
    146110        # dynamic content that sets indicators should not have 
    147111        # "cache prevention" headers 
     
    150114        self.assertNoHeader("Pragma") 
    151115        self.assertNoHeader("Cache-Control") 
    152         self.assertNoHeader("Expires") 
    153  
    154         # configure the tool to ignore indicators 
    155         self.getPage("/expires/ignorant") 
     116         
     117        self.getPage('/expires/dynamic') 
     118        self.assertBody("D-d-d-dynamic!") 
     119        # the Cache-Control header should be untouched 
     120        self.assertHeader("Cache-Control", "private") 
     121         
     122        # configure the tool to ignore indicators and replace existing headers 
     123        self.getPage("/expires/force") 
    156124        self.assertStatus("200 OK") 
    157  
     125         
    158126        # static content should now have "cache prevention" headers 
    159127        self.getPage("/expires/index.html") 
     
    161129        self.assertHeader("Pragma", "no-cache") 
    162130        self.assertHeader("Cache-Control", "no-cache") 
    163         self.assertHeader("Expires", "0") 
    164  
     131        d = self.assertHeader("Date") 
     132        self.assertHeader("Expires", d) 
     133         
    165134        # the cacheable handler should now have "cache prevention" headers 
    166135        self.getPage("/expires/cacheable") 
     
    168137        self.assertHeader("Pragma", "no-cache") 
    169138        self.assertHeader("Cache-Control", "no-cache") 
    170         self.assertHeader("Expires", "0") 
     139        d = self.assertHeader("Date") 
     140        self.assertHeader("Expires", d) 
     141         
     142        self.getPage('/expires/dynamic') 
     143        self.assertBody("D-d-d-dynamic!") 
     144        # dynamic sets Cache-Control to private but it should  be 
     145        # overwritten here ... 
     146        self.assertHeader("Pragma", "no-cache") 
     147        self.assertHeader("Cache-Control", "no-cache") 
     148        d = self.assertHeader("Date") 
     149        self.assertHeader("Expires", d) 
    171150 
    172151if __name__ == '__main__': 

Hosted by WebFaction

Log in as guest/cpguest to create tickets