fix spurious http cache bug: sometimes last-modified headers is generated using non-english local, which ends up in a date that twisted can't parse and make it feels the page may be cached while it may not stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 02 Feb 2010 10:59:44 +0100
branchstable
changeset 4424 5a5cd7591706
parent 4423 c1850ef961fc
child 4425 b9913205d91e
fix spurious http cache bug: sometimes last-modified headers is generated using non-english local, which ends up in a date that twisted can't parse and make it feels the page may be cached while it may not
web/httpcache.py
--- a/web/httpcache.py	Tue Feb 02 10:47:47 2010 +0100
+++ b/web/httpcache.py	Tue Feb 02 10:59:44 2010 +0100
@@ -8,6 +8,7 @@
 """
 __docformat__ = "restructuredtext en"
 
+from time import mktime
 from datetime import datetime
 
 # time delta usable to convert localized time to GMT time
@@ -23,6 +24,7 @@
     def set_headers(self):
         self.req.set_header('Cache-control', 'no-cache')
 
+
 class MaxAgeHTTPCacheManager(NoHTTPCacheManager):
     """max-age cache manager: set max-age cache control policy, with max-age
     specified with the `cache_max_age` attribute of the view
@@ -31,6 +33,7 @@
         self.req.set_header('Cache-control',
                             'max-age=%s' % self.view.cache_max_age)
 
+
 class EtagHTTPCacheManager(NoHTTPCacheManager):
     """etag based cache manager for startup views
 
@@ -38,8 +41,6 @@
     * set policy to 'must-revalidate' and expires to the current time to force
       revalidation on each request
     """
-    # GMT time required
-    date_format = "%a, %d %b %Y %H:%M:%S GMT"
 
     def etag(self):
         return self.view.id + '/' + ','.join(sorted(self.req.user.groups))
@@ -49,6 +50,7 @@
         return 0
 
     def last_modified(self):
+        """return view's last modified GMT time"""
         return self.view.last_modified()
 
     def set_headers(self):
@@ -61,7 +63,12 @@
         req.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))
+        # use a timestamp, not a formatted raw header, and let
+        # the front-end correctly generate it
+        # ("%a, %d %b %Y %H:%M:%S GMT" return localized date that
+        # twisted don't parse correctly)
+        req.set_header('Last-modified', mktime(mdate.timetuple()), raw=False)
+
 
 class EntityHTTPCacheManager(EtagHTTPCacheManager):
     """etag based cache manager for view displaying a single entity
@@ -99,6 +106,7 @@
     self.http_cache_manager(self).set_headers()
 viewmod.View.set_http_cache_headers = set_http_cache_headers
 
+
 def last_modified(self):
     """return the date/time where this view should be considered as
     modified. Take care of possible related objects modifications.
@@ -117,6 +125,7 @@
     return ctime
 viewmod.View.last_modified = last_modified
 
+
 # configure default caching
 viewmod.View.http_cache_manager = NoHTTPCacheManager
 # max-age=0 to actually force revalidation when needed