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

Changeset 1117

Show
Ignore:
Timestamp:
06/03/06 00:42:24
Author:
fumanchu
Message:

Fix for #531 (Make an ETag tool). Also refactored If-Modified-Since validation.

Files:

Legend:

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

    r1102 r1117  
    44 
    55import cherrypy 
     6from cherrypy.lib import cptools 
    67 
    78 
     
    105106    if c: 
    106107        expirationTime, lastModified, obj = cacheData 
    107         s, h, b = obj 
    108         modifiedSince = cherrypy.request.headers.get('If-Modified-Since', None) 
    109         if modifiedSince is not None and modifiedSince == lastModified: 
    110             cherrypy._cache.totNonModified += 1 
    111             cherrypy.response.status = "304 Not Modified" 
    112             ct = h.get("Content-Type") 
    113             if ct: 
    114                 cherrypy.response.header_list["Content-Type"] = ct 
    115             cherrypy.response.body = None 
    116         else: 
    117             # serve it & get out from the request 
    118             cherrypy.response.status, cherrypy.response.header_list, body = s, h, b 
    119             cherrypy.response.body = body 
     108        s, cherrypy.response.header_list, b = obj 
     109        try: 
     110            cptools.validate_since() 
     111        except cherrypy.HTTPError, x: 
     112            if x.status == 304: 
     113                cherrypy._cache.totNonModified += 1 
     114            raise 
     115         
     116        # serve it & get out from the request 
     117        cherrypy.response.status = s 
     118        cherrypy.response.body = b 
    120119    return c 
    121120 
  • trunk/cherrypy/lib/cptools.py

    r1106 r1117  
    22 
    33import inspect 
     4import md5 
    45import os 
    56import sys 
     
    178179 
    179180 
    180 # Tool code 
     181#                     Conditional HTTP request support                     # 
     182 
     183def validate_etags(autotags=False): 
     184    """Validate the current ETag against If-Match, If-None-Match headers.""" 
     185    # Guard against being run twice. 
     186    if hasattr(cherrypy.response, "ETag"): 
     187        return 
     188     
     189    etag = cherrypy.response.headers.get('ETag') 
     190     
     191    if (not etag) and autotags: 
     192        etag = '"%s"' % md5.new(cherrypy.response.collapse_body()).hexdigest() 
     193        cherrypy.response.headers['ETag'] = etag 
     194     
     195    if etag: 
     196        cherrypy.response.ETag = etag 
     197         
     198        status, reason, msg = httptools.validStatus(cherrypy.response.status) 
     199         
     200        conditions = cherrypy.request.headers.elements('If-Match') or [] 
     201        conditions = [str(x) for x in conditions] 
     202        if conditions and not (conditions == ["*"] or etag in conditions): 
     203            if (status >= 200 and status < 299) or status == 412: 
     204                raise cherrypy.HTTPError(412) 
     205         
     206        conditions = cherrypy.request.headers.elements('If-None-Match') or [] 
     207        conditions = [str(x) for x in conditions] 
     208        if conditions == ["*"] or etag in conditions: 
     209            if (status >= 200 and status < 299) or status == 304: 
     210                if cherrypy.request.method in ("GET", "HEAD"): 
     211                    raise cherrypy.HTTPRedirect([], 304) 
     212                else: 
     213                    raise cherrypy.HTTPError(412) 
     214 
     215def validate_since(): 
     216    """Validate the current Last-Modified against If-Modified-Since headers.""" 
     217    lastmod = cherrypy.response.headers.get('Last-Modified') 
     218    if lastmod: 
     219        status, reason, msg = httptools.validStatus(cherrypy.response.status) 
     220         
     221        since = cherrypy.request.headers.get('If-Unmodified-Since') 
     222        if since and since != lastmod: 
     223            if (status >= 200 and status < 299) or status == 412: 
     224                raise cherrypy.HTTPError(412) 
     225         
     226        since = cherrypy.request.headers.get('If-Modified-Since') 
     227        if since and since == lastmod: 
     228            if (status >= 200 and status < 299) or status == 304: 
     229                if cherrypy.request.method in ("GET", "HEAD"): 
     230                    raise cherrypy.HTTPRedirect([], 304) 
     231                else: 
     232                    raise cherrypy.HTTPError(412) 
     233 
     234 
     235#                                Tool code                                # 
    181236 
    182237def base_url(base=None, use_x_forwarded_host=True): 
  • trunk/cherrypy/lib/static.py

    r1096 r1117  
    1111 
    1212import cherrypy 
    13 from cherrypy.lib import httptools 
    14  
    15  
    16 def modified_since(path, stat=None): 
    17     """Check whether a file has been modified since the date 
    18     provided in 'If-Modified-Since' 
    19     It doesn't check if the file exists or not 
    20     Return True if has been modified, False otherwise 
    21     """ 
    22     # serve_file already creates a stat object so let's not 
    23     # waste our energy to do it again 
    24     if not stat: 
    25         try: 
    26             stat = os.stat(path) 
    27         except OSError: 
    28             if cherrypy.config.get('log_file_not_found', False): 
    29                 cherrypy.log("    NOT FOUND file: %s" % path, "DEBUG") 
    30             raise cherrypy.NotFound() 
    31      
    32     response = cherrypy.response 
    33     strModifTime = httptools.HTTPDate(time.gmtime(stat.st_mtime)) 
    34     if cherrypy.request.headers.has_key('If-Modified-Since'): 
    35         if cherrypy.request.headers['If-Modified-Since'] == strModifTime: 
    36             return False 
    37     response.headers['Last-Modified'] = strModifTime 
    38     return True 
     13from cherrypy.lib import cptools, httptools 
    3914 
    4015 
     
    8156    response.headers['Content-Type'] = contentType 
    8257     
    83     if not modified_since(path, stat): 
    84         response.status = "304 Not Modified" 
    85         response.body = [] 
    86         if getattr(cherrypy, "debug", None): 
    87             cherrypy.log("    Found file (304 Not Modified): %s" % path, "DEBUG") 
    88         return [] 
     58    # Set the Last-Modified response header, so that 
     59    # modified-since validation code can work. 
     60    response.headers['Last-Modified'] = httptools.HTTPDate(time.gmtime(stat.st_mtime)) 
     61    cptools.validate_since() 
    8962     
    9063    if disposition is not None: 
  • trunk/cherrypy/test/test.py

    r1114 r1117  
    8787        self.protocol = "HTTP/1.1" 
    8888         
    89         longopts = ['cover', 'profile', '1.1', 'help', 'basedir=', 'port=', 
     89        longopts = ['cover', 'profile', '1.0', 'help', 'basedir=', 'port=', 
    9090                    'server='] 
    9191        longopts.extend(self.available_servers) 
     
    295295        'test_tools', 
    296296        'test_decodingencoding', 
     297        'test_etags', 
    297298        'test_gzip', 
    298299        'test_objectmapping', 
  • trunk/cherrypy/test/test_static.py

    r1114 r1117  
    128128        ims = ("If-Modified-Since", lastmod) 
    129129        self.getPage("/static/dirback.jpg", headers=[ims]) 
    130         self.assertStatus("304 Not Modified") 
     130        self.assertStatus("304 Not modified") 
    131131##         
    132132##        # Test lots of requests for the same file (no If-Mod). 
  • trunk/cherrypy/tools.py

    r1115 r1117  
    228228# because it's failsafe and the redirect would be swallowed. 
    229229virtual_host = Tool('before_request_body', cptools.virtual_host) 
    230 log_tracebacks = Tool('before_error_response', cptools.log_traceback
    231 log_headers = Tool('before_error_response', cptools.log_request_headers
     230log_tracebacks = Tool('before_error_response', cptools.log_traceback, 'log_tracebacks'
     231log_headers = Tool('before_error_response', cptools.log_request_headers, 'log_headers'
    232232err_redirect = ErrorTool(cptools.redirect, 'err_redirect') 
     233etags = Tool('before_finalize', cptools.validate_etags, 'etags') 
    233234del cptools 
    234235 

Hosted by WebFaction

Log in as guest/cpguest to create tickets