1 import datetime
2 import threading
3 import time
4
5 import cherrypy
6 from cherrypy.lib import cptools, http
7
8
10
12 self.clear()
13 t = threading.Thread(target=self.expire_cache, name='expire_cache')
14 self.expiration_thread = t
15 t.setDaemon(True)
16 t.start()
17
19 """Reset the cache to its initial, empty state."""
20 self.cache = {}
21 self.expirations = {}
22 self.tot_puts = 0
23 self.tot_gets = 0
24 self.tot_hist = 0
25 self.tot_expires = 0
26 self.tot_non_modified = 0
27 self.cursize = 0
28
32 key = property(_key)
33
35
36
37
38
39 while time:
40 now = time.time()
41 for expiration_time, objects in self.expirations.items():
42 if expiration_time <= now:
43 for obj_size, obj_key in objects:
44 try:
45 del self.cache[obj_key]
46 self.tot_expires += 1
47 self.cursize -= obj_size
48 except KeyError:
49
50 pass
51 del self.expirations[expiration_time]
52 time.sleep(0.1)
53
55 """Return the object if in the cache, else None."""
56 self.tot_gets += 1
57 cache_item = self.cache.get(self.key, None)
58 if cache_item:
59 self.tot_hist += 1
60 return cache_item
61 else:
62 return None
63
65 conf = cherrypy.request.config.get
66
67 if len(self.cache) < conf("tools.caching.maxobjects", 1000):
68
69 obj_size = len(obj[2])
70 maxobj_size = conf("tools.caching.maxobj_size", 100000)
71
72 total_size = self.cursize + obj_size
73 maxsize = conf("tools.caching.maxsize", 10000000)
74
75
76 if (obj_size < maxobj_size and total_size < maxsize):
77
78 expiration_time = cherrypy.response.time + conf("tools.caching.delay", 600)
79 obj_key = self.key
80 bucket = self.expirations.setdefault(expiration_time, [])
81 bucket.append((obj_size, obj_key))
82 self.cache[obj_key] = obj
83 self.tot_puts += 1
84 self.cursize = total_size
85
88
89
90 -def get(invalid_methods=("POST", "PUT", "DELETE"), cache_class=MemoryCache, **kwargs):
91 """Try to obtain cached output. If fresh enough, raise HTTPError(304).
92
93 If POST, PUT, or DELETE:
94 * invalidates (deletes) any cached response for this resource
95 * sets request.cached = False
96 * sets request.cacheable = False
97
98 else if a cached copy exists:
99 * sets request.cached = True
100 * sets request.cacheable = False
101 * sets response.headers to the cached values
102 * checks the cached Last-Modified response header against the
103 current If-(Un)Modified-Since request headers; raises 304
104 if necessary.
105 * sets response.status and response.body to the cached values
106 * returns True
107
108 otherwise:
109 * sets request.cached = False
110 * sets request.cacheable = True
111 * returns False
112 """
113 if not hasattr(cherrypy, "_cache"):
114 cherrypy._cache = cache_class()
115
116 request = cherrypy.request
117
118
119
120 if request.method in invalid_methods:
121 cherrypy._cache.delete()
122 request.cached = False
123 request.cacheable = False
124 return False
125
126 cache_data = cherrypy._cache.get()
127 request.cached = c = bool(cache_data)
128 request.cacheable = not c
129 if c:
130 response = cherrypy.response
131 s, response.headers, b, create_time = cache_data
132
133
134 response.headers["Age"] = str(int(response.time - create_time))
135
136 try:
137
138
139
140 cptools.validate_since()
141 except cherrypy.HTTPError, x:
142 if x.status == 304:
143 cherrypy._cache.tot_non_modified += 1
144 raise
145
146
147 response.status = s
148 response.body = b
149 return c
150
151
166 response.body = tee(response.body)
167
168
170 """Tool for influencing cache mechanisms using the 'Expires' header.
171
172 'secs' must be either an int or a datetime.timedelta, and indicates the
173 number of seconds between response.time and when the response should
174 expire. The 'Expires' header will be set to (response.time + secs).
175
176 If 'secs' is zero, the following "cache prevention" headers are also set:
177 'Pragma': 'no-cache'
178 'Cache-Control': 'no-cache, must-revalidate'
179
180 If 'force' is False (the default), the following headers are checked:
181 'Etag', 'Last-Modified', 'Age', 'Expires'. If any are already present,
182 none of the above response headers are set.
183 """
184
185 response = cherrypy.response
186 headers = response.headers
187
188 cacheable = False
189 if not force:
190
191 for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'):
192 if indicator in headers:
193 cacheable = True
194 break
195
196 if not cacheable:
197 if isinstance(secs, datetime.timedelta):
198 secs = (86400 * secs.days) + secs.seconds
199
200 if secs == 0:
201 if force or "Pragma" not in headers:
202 headers["Pragma"] = "no-cache"
203 if cherrypy.request.protocol >= (1, 1):
204 if force or "Cache-Control" not in headers:
205 headers["Cache-Control"] = "no-cache, must-revalidate"
206
207 expiry = http.HTTPDate(response.time + secs)
208 if force or "Expires" not in headers:
209 headers["Expires"] = expiry
210