1 import datetime
2 import threading
3 import time
4
5 import cherrypy
6 from cherrypy.lib import cptools, http
7
8
10
11 maxobjects = 1000
12 maxobj_size = 100000
13 maxsize = 10000000
14 delay = 600
15
17 self.clear()
18 t = threading.Thread(target=self.expire_cache, name='expire_cache')
19 self.expiration_thread = t
20 if hasattr(threading.Thread, "daemon"):
21
22 t.daemon = True
23 else:
24 t.setDaemon(True)
25 t.start()
26
28 """Reset the cache to its initial, empty state."""
29 self.cache = {}
30 self.expirations = {}
31 self.tot_puts = 0
32 self.tot_gets = 0
33 self.tot_hist = 0
34 self.tot_expires = 0
35 self.tot_non_modified = 0
36 self.cursize = 0
37
40
42
43
44
45
46 while time:
47 now = time.time()
48 for expiration_time, objects in self.expirations.items():
49 if expiration_time <= now:
50 for obj_size, obj_key in objects:
51 try:
52 del self.cache[obj_key]
53 self.tot_expires += 1
54 self.cursize -= obj_size
55 except KeyError:
56
57 pass
58 del self.expirations[expiration_time]
59 time.sleep(0.1)
60
62 """Return the object if in the cache, else None."""
63 self.tot_gets += 1
64 cache_item = self.cache.get(self.key(), None)
65 if cache_item:
66 self.tot_hist += 1
67 return cache_item
68 else:
69 return None
70
72 if len(self.cache) < self.maxobjects:
73
74 obj_size = len(obj[2])
75 total_size = self.cursize + obj_size
76
77
78 if (obj_size < self.maxobj_size and total_size < self.maxsize):
79
80 expiration_time = cherrypy.response.time + self.delay
81 obj_key = self.key()
82 bucket = self.expirations.setdefault(expiration_time, [])
83 bucket.append((obj_size, obj_key))
84 self.cache[obj_key] = obj
85 self.tot_puts += 1
86 self.cursize = total_size
87
90
91
92 -def get(invalid_methods=("POST", "PUT", "DELETE"), **kwargs):
93 """Try to obtain cached output. If fresh enough, raise HTTPError(304).
94
95 If POST, PUT, or DELETE:
96 * invalidates (deletes) any cached response for this resource
97 * sets request.cached = False
98 * sets request.cacheable = False
99
100 else if a cached copy exists:
101 * sets request.cached = True
102 * sets request.cacheable = False
103 * sets response.headers to the cached values
104 * checks the cached Last-Modified response header against the
105 current If-(Un)Modified-Since request headers; raises 304
106 if necessary.
107 * sets response.status and response.body to the cached values
108 * returns True
109
110 otherwise:
111 * sets request.cached = False
112 * sets request.cacheable = True
113 * returns False
114 """
115 request = cherrypy.request
116
117
118
119 if request.method in invalid_methods:
120 cherrypy._cache.delete()
121 request.cached = False
122 request.cacheable = False
123 return False
124
125 cache_data = cherrypy._cache.get()
126 request.cached = c = bool(cache_data)
127 request.cacheable = not c
128 if c:
129 response = cherrypy.response
130 s, h, b, create_time, original_req_headers = cache_data
131
132
133
134
135
136
137
138
139
140
141
142
143
144 for header_element in h.elements('Vary'):
145 key = header_element.value
146 if original_req_headers[key] != request.headers.get(key, 'missing'):
147 request.cached = False
148 request.cacheable = True
149 return False
150
151
152 response.headers = rh = http.HeaderMap()
153 for k in h:
154 dict.__setitem__(rh, k, dict.__getitem__(h, k))
155
156
157 response.headers["Age"] = str(int(response.time - create_time))
158
159 try:
160
161
162
163 cptools.validate_since()
164 except cherrypy.HTTPRedirect, x:
165 if x.status == 304:
166 cherrypy._cache.tot_non_modified += 1
167 raise
168
169
170 response.status = s
171 response.body = b
172 return c
173
174
197
198 response = cherrypy.response
199 response.body = tee(response.body)
200
201
203 """Tool for influencing cache mechanisms using the 'Expires' header.
204
205 'secs' must be either an int or a datetime.timedelta, and indicates the
206 number of seconds between response.time and when the response should
207 expire. The 'Expires' header will be set to (response.time + secs).
208
209 If 'secs' is zero, the 'Expires' header is set one year in the past, and
210 the following "cache prevention" headers are also set:
211 'Pragma': 'no-cache'
212 'Cache-Control': 'no-cache, must-revalidate'
213
214 If 'force' is False (the default), the following headers are checked:
215 'Etag', 'Last-Modified', 'Age', 'Expires'. If any are already present,
216 none of the above response headers are set.
217 """
218
219 response = cherrypy.response
220 headers = response.headers
221
222 cacheable = False
223 if not force:
224
225 for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'):
226 if indicator in headers:
227 cacheable = True
228 break
229
230 if not cacheable:
231 if isinstance(secs, datetime.timedelta):
232 secs = (86400 * secs.days) + secs.seconds
233
234 if secs == 0:
235 if force or "Pragma" not in headers:
236 headers["Pragma"] = "no-cache"
237 if cherrypy.request.protocol >= (1, 1):
238 if force or "Cache-Control" not in headers:
239 headers["Cache-Control"] = "no-cache, must-revalidate"
240
241 expiry = http.HTTPDate(1169942400.0)
242 else:
243 expiry = http.HTTPDate(response.time + secs)
244 if force or "Expires" not in headers:
245 headers["Expires"] = expiry
246