Friday, 15 May 2009

CherryPy Caching


I just tried turning on CherryPy web caching, this is one of the few things which receives only very cursory treatment in Sylvain Hellegouarch's  excellent book, 'CherryPy Essentials'. I managed by incorporating the 
conf = {'/':{'tools.caching.on':True}}
line in my code, however I was dismayed to discover that once on, I couldn't form a request would not get the cached result. Neither 'Cache-Control:max-age=0' nor 'Pragma: no-cache' would do it. Looking into the code (I'm using v. 3.1.1), I found the caching.py tool and indeed saw it pays pretty much no attention to the http request headers except (bizarrely, I think) the 'Vary' header. I've inserted a few lines into caching.py to fix this and submitted a trac bug, so we'll see whether this changes. The code lines are reproduced here:
#some people still use Pragma : no-cache to demand a fresh resource
        pragma_no_cache=False
        pragma_header=request.headers.get('Pragma')
        if pragma_header:
            pragma_values=[header.strip() for header in pragma_header.split(',')]
            for this_value in pragma_values:
                if 'no-cache' in this_value:
                    pragma_no_cache=True
                    break
        #added by shaun, look at cache-control
        max_acceptable_age=MemoryCache.delay
        age_seconds=int(response.time - create_time)
        cache_control_header=request.headers.get('Cache-Control')
        if cache_control_header:
            #split string on commas to get the multiple words
            cache_control_values=[header.strip() for header in cache_control_header.split(',')]
            #look for max-age
            for this_value in cache_control_values:
                if ('max-age' in this_value) and ('=' in this_value):
                    age_pair=[age.strip() for age in this_value.split('=')]
                    if age_pair[1].isdigit():
                      max_acceptable_age=int(age_pair[1])
                    break
                  
        #return if the cache is older than the acceptable age
        if (age_seconds > max_acceptable_age) or pragma_no_cache:
            request.cached = False
            request.cacheable = True
            return False
            
        # Add the required Age header
        response.headers["Age"] = str(age_seconds)

No comments: