"""HTTP cache managers:organization: Logilab:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr"""__docformat__="restructuredtext en"frommx.DateTimeimportDateTimeFromTicks,now,gmtime# time delta usable to convert localized time to GMT timeGMTOFFSET=-(now()-gmtime())classNoHTTPCacheManager(object):"""default cache manager: set no-cache cache control policy"""def__init__(self,view):self.view=viewself.req=view.reqself.rset=view.rsetdefset_headers(self):self.req.set_header('Cache-control','no-cache')classMaxAgeHTTPCacheManager(NoHTTPCacheManager):"""max-age cache manager: set max-age cache control policy, with max-age specified with the `cache_max_age` attribute of the view """defset_headers(self):self.req.set_header('Cache-control','max-age=%s'%self.view.cache_max_age)classEtagHTTPCacheManager(NoHTTPCacheManager):"""etag based cache manager for startup views * etag is generated using the view name and the user's groups * set policy to 'must-revalidate' and expires to the current time to force revalidation on each request """# GMT time requireddate_format="%a, %d %b %Y %H:%M:%S GMT"defetag(self):returnself.view.id+'/'+','.join(sorted(self.req.user.groups))defmax_age(self):# 0 to actually force revalidationreturn0deflast_modified(self):returnself.view.last_modified()defset_headers(self):req=self.reqtry:req.set_header('Etag','"%s"'%self.etag())exceptNoEtag:self.req.set_header('Cache-control','no-cache')returnreq.set_header('Cache-control','must-revalidate;max-age=%s'%self.max_age())mdate=self.last_modified()req.set_header('Last-modified',mdate.strftime(self.date_format))classEntityHTTPCacheManager(EtagHTTPCacheManager):"""etag based cache manager for view displaying a single entity * etag is generated using entity's eid, the view name and the user's groups * get last modified time from the entity definition (this may not be the entity's modification time since a view may include some related entities with a modification time to consider) using the `last_modified` method """defetag(self):ifself.rsetisNoneorlen(self.rset)==0:# entity startup view for instancereturnsuper(EntityHTTPCacheManager,self).etag()iflen(self.rset)>1:raiseNoEtag()etag=super(EntityHTTPCacheManager,self).etag()eid=self.rset[0][0]ifself.req.user.owns(eid):etag+=',owners'returnstr(eid)+'/'+etagclassNoEtag(Exception):"""an etag can't be generated"""__all__=('GMTOFFSET','NoHTTPCacheManager','MaxAgeHTTPCacheManager','EtagHTTPCacheManager','EntityHTTPCacheManager')# monkey patching, so view doesn't depends on this module and we have all# http cache related logic herefromcubicweb.commonimportviewdefset_http_cache_headers(self):self.http_cache_manager(self).set_headers()view.View.set_http_cache_headers=set_http_cache_headersdeflast_modified(self):"""return the date/time where this view should be considered as modified. Take care of possible related objects modifications. /!\ must return GMT time /!\ """# XXX check view module's file modification time in dev mod ?ctime=gmtime()ifself.cache_max_age:mtime=self.req.header_if_modified_since()ifmtime:if(ctime-mtime).seconds>self.cache_max_age:mtime=ctimeelse:mtime=ctimeelse:mtime=ctime# mtime = ctime will force page rerenderingreturnmtimeview.View.last_modified=last_modified# configure default cachingview.View.http_cache_manager=NoHTTPCacheManager# max-age=0 to actually force revalidation when neededview.View.cache_max_age=0view.EntityView.http_cache_manager=EntityHTTPCacheManagerview.StartupView.http_cache_manager=MaxAgeHTTPCacheManagerview.StartupView.cache_max_age=60*60*2# stay in http cache for 2 hours by default