6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
7 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
7 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
8 """ |
8 """ |
9 __docformat__ = "restructuredtext en" |
9 __docformat__ = "restructuredtext en" |
10 |
10 |
|
11 from time import mktime |
11 from datetime import datetime |
12 from datetime import datetime |
12 |
13 |
13 # time delta usable to convert localized time to GMT time |
14 # time delta usable to convert localized time to GMT time |
14 GMTOFFSET = - (datetime.now() - datetime.utcnow()) |
15 GMTOFFSET = - (datetime.now() - datetime.utcnow()) |
15 |
16 |
21 self.cw_rset = view.cw_rset |
22 self.cw_rset = view.cw_rset |
22 |
23 |
23 def set_headers(self): |
24 def set_headers(self): |
24 self.req.set_header('Cache-control', 'no-cache') |
25 self.req.set_header('Cache-control', 'no-cache') |
25 |
26 |
|
27 |
26 class MaxAgeHTTPCacheManager(NoHTTPCacheManager): |
28 class MaxAgeHTTPCacheManager(NoHTTPCacheManager): |
27 """max-age cache manager: set max-age cache control policy, with max-age |
29 """max-age cache manager: set max-age cache control policy, with max-age |
28 specified with the `cache_max_age` attribute of the view |
30 specified with the `cache_max_age` attribute of the view |
29 """ |
31 """ |
30 def set_headers(self): |
32 def set_headers(self): |
31 self.req.set_header('Cache-control', |
33 self.req.set_header('Cache-control', |
32 'max-age=%s' % self.view.cache_max_age) |
34 'max-age=%s' % self.view.cache_max_age) |
33 |
35 |
|
36 |
34 class EtagHTTPCacheManager(NoHTTPCacheManager): |
37 class EtagHTTPCacheManager(NoHTTPCacheManager): |
35 """etag based cache manager for startup views |
38 """etag based cache manager for startup views |
36 |
39 |
37 * etag is generated using the view name and the user's groups |
40 * etag is generated using the view name and the user's groups |
38 * set policy to 'must-revalidate' and expires to the current time to force |
41 * set policy to 'must-revalidate' and expires to the current time to force |
39 revalidation on each request |
42 revalidation on each request |
40 """ |
43 """ |
41 # GMT time required |
|
42 date_format = "%a, %d %b %Y %H:%M:%S GMT" |
|
43 |
44 |
44 def etag(self): |
45 def etag(self): |
45 return self.view.__regid__ + '/' + ','.join(sorted(self.req.user.groups)) |
46 return self.view.__regid__ + '/' + ','.join(sorted(self.req.user.groups)) |
46 |
47 |
47 def max_age(self): |
48 def max_age(self): |
48 # 0 to actually force revalidation |
49 # 0 to actually force revalidation |
49 return 0 |
50 return 0 |
50 |
51 |
51 def last_modified(self): |
52 def last_modified(self): |
|
53 """return view's last modified GMT time""" |
52 return self.view.last_modified() |
54 return self.view.last_modified() |
53 |
55 |
54 def set_headers(self): |
56 def set_headers(self): |
55 req = self.req |
57 req = self.req |
56 try: |
58 try: |
59 self.req.set_header('Cache-control', 'no-cache') |
61 self.req.set_header('Cache-control', 'no-cache') |
60 return |
62 return |
61 req.set_header('Cache-control', |
63 req.set_header('Cache-control', |
62 'must-revalidate;max-age=%s' % self.max_age()) |
64 'must-revalidate;max-age=%s' % self.max_age()) |
63 mdate = self.last_modified() |
65 mdate = self.last_modified() |
64 req.set_header('Last-modified', mdate.strftime(self.date_format)) |
66 # use a timestamp, not a formatted raw header, and let |
|
67 # the front-end correctly generate it |
|
68 # ("%a, %d %b %Y %H:%M:%S GMT" return localized date that |
|
69 # twisted don't parse correctly) |
|
70 req.set_header('Last-modified', mktime(mdate.timetuple()), raw=False) |
|
71 |
65 |
72 |
66 class EntityHTTPCacheManager(EtagHTTPCacheManager): |
73 class EntityHTTPCacheManager(EtagHTTPCacheManager): |
67 """etag based cache manager for view displaying a single entity |
74 """etag based cache manager for view displaying a single entity |
68 |
75 |
69 * etag is generated using entity's eid, the view name and the user's groups |
76 * etag is generated using entity's eid, the view name and the user's groups |
97 |
104 |
98 def set_http_cache_headers(self): |
105 def set_http_cache_headers(self): |
99 self.http_cache_manager(self).set_headers() |
106 self.http_cache_manager(self).set_headers() |
100 viewmod.View.set_http_cache_headers = set_http_cache_headers |
107 viewmod.View.set_http_cache_headers = set_http_cache_headers |
101 |
108 |
|
109 |
102 def last_modified(self): |
110 def last_modified(self): |
103 """return the date/time where this view should be considered as |
111 """return the date/time where this view should be considered as |
104 modified. Take care of possible related objects modifications. |
112 modified. Take care of possible related objects modifications. |
105 |
113 |
106 /!\ must return GMT time /!\ |
114 /!\ must return GMT time /!\ |
109 ctime = datetime.utcnow() |
117 ctime = datetime.utcnow() |
110 if self.cache_max_age: |
118 if self.cache_max_age: |
111 mtime = self._cw.header_if_modified_since() |
119 mtime = self._cw.header_if_modified_since() |
112 if mtime: |
120 if mtime: |
113 tdelta = (ctime - mtime) |
121 tdelta = (ctime - mtime) |
114 if tdelta.days * 24*60*60 + tdelta.seconds > self.cache_max_age: |
122 if tdelta.days * 24*60*60 + tdelta.seconds <= self.cache_max_age: |
115 mtime = ctime |
123 return mtime |
116 else: |
|
117 mtime = ctime |
|
118 else: |
|
119 mtime = ctime |
|
120 # mtime = ctime will force page rerendering |
124 # mtime = ctime will force page rerendering |
121 return mtime |
125 return ctime |
122 viewmod.View.last_modified = last_modified |
126 viewmod.View.last_modified = last_modified |
|
127 |
123 |
128 |
124 # configure default caching |
129 # configure default caching |
125 viewmod.View.http_cache_manager = NoHTTPCacheManager |
130 viewmod.View.http_cache_manager = NoHTTPCacheManager |
126 # max-age=0 to actually force revalidation when needed |
131 # max-age=0 to actually force revalidation when needed |
127 viewmod.View.cache_max_age = 0 |
132 viewmod.View.cache_max_age = 0 |