1 import os
2 localDir = os.path.dirname(__file__)
3 import sys
4 import threading
5 import time
6
7 import cherrypy
8 from cherrypy._cpcompat import copykeys, HTTPConnection, HTTPSConnection
9 from cherrypy.lib import sessions
10 from cherrypy.lib.httputil import response_codes
11
17
18 cherrypy.tools.allow = cherrypy.Tool('on_start_resource', http_methods_allowed)
19
20
22
23 class Root:
24
25 _cp_config = {'tools.sessions.on': True,
26 'tools.sessions.storage_type' : 'ram',
27 'tools.sessions.storage_path' : localDir,
28 'tools.sessions.timeout': (1.0 / 60),
29 'tools.sessions.clean_freq': (1.0 / 60),
30 }
31
32 def clear(self):
33 cherrypy.session.cache.clear()
34 clear.exposed = True
35
36 def data(self):
37 cherrypy.session['aha'] = 'foo'
38 return repr(cherrypy.session._data)
39 data.exposed = True
40
41 def testGen(self):
42 counter = cherrypy.session.get('counter', 0) + 1
43 cherrypy.session['counter'] = counter
44 yield str(counter)
45 testGen.exposed = True
46
47 def testStr(self):
48 counter = cherrypy.session.get('counter', 0) + 1
49 cherrypy.session['counter'] = counter
50 return str(counter)
51 testStr.exposed = True
52
53 def setsessiontype(self, newtype):
54 self.__class__._cp_config.update({'tools.sessions.storage_type': newtype})
55 if hasattr(cherrypy, "session"):
56 del cherrypy.session
57 cls = getattr(sessions, newtype.title() + 'Session')
58 if cls.clean_thread:
59 cls.clean_thread.stop()
60 cls.clean_thread.unsubscribe()
61 del cls.clean_thread
62 setsessiontype.exposed = True
63 setsessiontype._cp_config = {'tools.sessions.on': False}
64
65 def index(self):
66 sess = cherrypy.session
67 c = sess.get('counter', 0) + 1
68 time.sleep(0.01)
69 sess['counter'] = c
70 return str(c)
71 index.exposed = True
72
73 def keyin(self, key):
74 return str(key in cherrypy.session)
75 keyin.exposed = True
76
77 def delete(self):
78 cherrypy.session.delete()
79 sessions.expire()
80 return "done"
81 delete.exposed = True
82
83 def delkey(self, key):
84 del cherrypy.session[key]
85 return "OK"
86 delkey.exposed = True
87
88 def blah(self):
89 return self._cp_config['tools.sessions.storage_type']
90 blah.exposed = True
91
92 def iredir(self):
93 raise cherrypy.InternalRedirect('/blah')
94 iredir.exposed = True
95
96 def restricted(self):
97 return cherrypy.request.method
98 restricted.exposed = True
99 restricted._cp_config = {'tools.allow.on': True,
100 'tools.allow.methods': ['GET']}
101
102 def regen(self):
103 cherrypy.tools.sessions.regenerate()
104 return "logged in"
105 regen.exposed = True
106
107 def length(self):
108 return str(len(cherrypy.session))
109 length.exposed = True
110
111 def session_cookie(self):
112
113 cherrypy.session.load()
114 return cherrypy.session.id
115 session_cookie.exposed = True
116 session_cookie._cp_config = {
117 'tools.sessions.path': '/session_cookie',
118 'tools.sessions.name': 'temp',
119 'tools.sessions.persistent': False}
120
121 cherrypy.tree.mount(Root())
122
123
124 from cherrypy.test import helper
125
127 setup_server = staticmethod(setup_server)
128
134
136 self.getPage('/setsessiontype/ram')
137 self.getPage('/clear')
138
139
140
141 self.getPage('/data')
142 self.assertBody("{'aha': 'foo'}")
143 c = self.cookies[0]
144 self.getPage('/data', self.cookies)
145 self.assertEqual(self.cookies[0], c)
146
147 self.getPage('/testStr')
148 self.assertBody('1')
149 cookie_parts = dict([p.strip().split('=')
150 for p in self.cookies[0][1].split(";")])
151
152 self.assertEqual(set(cookie_parts.keys()),
153 set(['session_id', 'expires', 'Path']))
154 self.getPage('/testGen', self.cookies)
155 self.assertBody('2')
156 self.getPage('/testStr', self.cookies)
157 self.assertBody('3')
158 self.getPage('/data', self.cookies)
159 self.assertBody("{'aha': 'foo', 'counter': 3}")
160 self.getPage('/length', self.cookies)
161 self.assertBody('2')
162 self.getPage('/delkey?key=counter', self.cookies)
163 self.assertStatus(200)
164
165 self.getPage('/setsessiontype/file')
166 self.getPage('/testStr')
167 self.assertBody('1')
168 self.getPage('/testGen', self.cookies)
169 self.assertBody('2')
170 self.getPage('/testStr', self.cookies)
171 self.assertBody('3')
172 self.getPage('/delkey?key=counter', self.cookies)
173 self.assertStatus(200)
174
175
176 time.sleep(2)
177 self.getPage('/')
178 self.assertBody('1')
179 self.getPage('/length', self.cookies)
180 self.assertBody('1')
181
182
183 self.getPage('/keyin?key=counter', self.cookies)
184 self.assertBody("True")
185 cookieset1 = self.cookies
186
187
188 self.getPage('/')
189 self.getPage('/length', self.cookies)
190 self.assertBody('2')
191
192
193 self.getPage('/delete', self.cookies)
194 self.assertBody("done")
195 self.getPage('/delete', cookieset1)
196 self.assertBody("done")
197 f = lambda: [x for x in os.listdir(localDir) if x.startswith('session-')]
198 self.assertEqual(f(), [])
199
200
201 self.getPage('/')
202 f = lambda: [x for x in os.listdir(localDir) if x.startswith('session-')]
203 self.assertNotEqual(f(), [])
204 time.sleep(2)
205 self.assertEqual(f(), [])
206
210
214
243
244
245
246
247
248 ts = []
249 for c in range(client_thread_count):
250 data_dict[c] = 0
251 t = threading.Thread(target=request, args=(c,))
252 ts.append(t)
253 t.start()
254
255 for t in ts:
256 t.join()
257
258 hitcount = max(data_dict.values())
259 expected = 1 + (client_thread_count * request_count)
260
261 for e in errors:
262 print(e)
263 self.assertEqual(hitcount, expected)
264
270
272
273 self.getPage('/testStr')
274
275 id = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
276 path = os.path.join(localDir, "session-" + id)
277 os.unlink(path)
278 self.getPage('/testStr', self.cookies)
279
291
293 self.getPage('/testStr')
294
295 id1 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
296 self.getPage('/regen')
297 self.assertBody('logged in')
298 id2 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
299 self.assertNotEqual(id1, id2)
300
301 self.getPage('/testStr')
302
303 id1 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
304 self.getPage('/testStr',
305 headers=[('Cookie',
306 'session_id=maliciousid; '
307 'expires=Sat, 27 Oct 2017 04:18:28 GMT; Path=/;')])
308 id2 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
309 self.assertNotEqual(id1, id2)
310 self.assertNotEqual(id2, 'maliciousid')
311
313 self.getPage('/setsessiontype/ram')
314 self.getPage('/clear')
315 self.getPage('/session_cookie')
316
317 cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")])
318
319 self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
320 id1 = cookie_parts['temp']
321 self.assertEqual(copykeys(sessions.RamSession.cache), [id1])
322
323
324 self.getPage('/session_cookie', self.cookies)
325 cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")])
326
327 self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
328 self.assertBody(id1)
329 self.assertEqual(copykeys(sessions.RamSession.cache), [id1])
330
331
332 self.getPage('/session_cookie')
333
334 cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")])
335
336 self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
337
338 id2 = cookie_parts['temp']
339 self.assertNotEqual(id1, id2)
340 self.assertEqual(set(sessions.RamSession.cache.keys()), set([id1, id2]))
341
342
343 time.sleep(2.5)
344 cache = copykeys(sessions.RamSession.cache)
345 if cache:
346 if cache == [id2]:
347 self.fail("The second session did not time out.")
348 else:
349 self.fail("Unknown session id in cache: %r", cache)
350
351
352 import socket
353 try:
354 import memcache
355
356 host, port = '127.0.0.1', 11211
357 for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
358 socket.SOCK_STREAM):
359 af, socktype, proto, canonname, sa = res
360 s = None
361 try:
362 s = socket.socket(af, socktype, proto)
363
364
365 s.settimeout(1.0)
366 s.connect((host, port))
367 s.close()
368 except socket.error:
369 if s:
370 s.close()
371 raise
372 break
373 except (ImportError, socket.error):
379 else:
381 setup_server = staticmethod(setup_server)
382
410
412 client_thread_count = 5
413 request_count = 30
414
415
416 self.getPage("/")
417 self.assertBody("1")
418 cookies = self.cookies
419
420 data_dict = {}
421
422 def request(index):
423 for i in range(request_count):
424 self.getPage("/", cookies)
425
426
427 if not self.body.isdigit():
428 self.fail(self.body)
429 data_dict[index] = v = int(self.body)
430
431
432
433 ts = []
434 for c in range(client_thread_count):
435 data_dict[c] = 0
436 t = threading.Thread(target=request, args=(c,))
437 ts.append(t)
438 t.start()
439
440 for t in ts:
441 t.join()
442
443 hitcount = max(data_dict.values())
444 expected = 1 + (client_thread_count * request_count)
445 self.assertEqual(hitcount, expected)
446
452
464