Changeset 1736
- Timestamp:
- 10/04/07 03:10:31
- Files:
-
- trunk/cherrypy/lib/sessions.py (modified) (5 diffs)
- trunk/cherrypy/test/test_session.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/lib/sessions.py
r1721 r1736 243 243 LOCK_SUFFIX = '.lock' 244 244 245 def setup( self):245 def setup(cls, **kwargs): 246 246 """Set up the storage system for file-based sessions. 247 247 … … 249 249 automatically when using sessions.init (as the built-in Tool does). 250 250 """ 251 for k, v in kwargs.iteritems(): 252 setattr(cls, k, v) 253 251 254 # Warn if any lock files exist at startup. 252 lockfiles = [fname for fname in os.listdir( self.storage_path)253 if (fname.startswith( self.SESSION_PREFIX)254 and fname.endswith( self.LOCK_SUFFIX))]255 lockfiles = [fname for fname in os.listdir(cls.storage_path) 256 if (fname.startswith(cls.SESSION_PREFIX) 257 and fname.endswith(cls.LOCK_SUFFIX))] 255 258 if lockfiles: 256 259 plural = ('', 's')[len(lockfiles) > 1] … … 259 262 "manually delete the lockfiles found at %r." 260 263 % (len(lockfiles), plural, 261 os.path.abspath(self.storage_path))) 264 os.path.abspath(cls.storage_path))) 265 setup = classmethod(setup) 262 266 263 267 def _get_file_path(self): … … 397 401 398 402 403 class MemcachedSession(Session): 404 405 locks = {} 406 servers = ['127.0.0.1:11211'] 407 408 def setup(cls, **kwargs): 409 """Set up the storage system for memcached-based sessions. 410 411 This should only be called once per process; this will be done 412 automatically when using sessions.init (as the built-in Tool does). 413 """ 414 for k, v in kwargs.iteritems(): 415 setattr(cls, k, v) 416 417 import memcache 418 cls.cache = memcache.Client(cls.servers) 419 setup = classmethod(setup) 420 421 def _load(self): 422 return self.cache.get(self.id) 423 424 def _save(self, expiration_time): 425 # Send the expiration time as "Unix time" (seconds since 1/1/1970) 426 zeroday = datetime.datetime(1970, 1, 1, tzinfo=expiration_time.tzinfo) 427 td = expiration_time - zeroday 428 td = (td.days * 86400) + td.seconds 429 if not self.cache.set(self.id, (self._data, expiration_time), td): 430 raise AssertionError("Session data for id %r not set." % self.id) 431 432 def _delete(self): 433 self.cache.delete(self.id) 434 435 def acquire_lock(self): 436 """Acquire an exclusive lock on the currently-loaded session data.""" 437 self.locked = True 438 self.locks.setdefault(self.id, threading.RLock()).acquire() 439 440 def release_lock(self): 441 """Release the lock on the currently-loaded session data.""" 442 self.locks[self.id].release() 443 self.locked = False 444 445 399 446 # Hook functions (for CherryPy tools) 400 447 … … 466 513 id = request.cookie[name].value 467 514 515 # Find the storage class and call setup (first time only). 516 storage_class = storage_type.title() + 'Session' 517 storage_class = globals()[storage_class] 518 if not hasattr(cherrypy, "session"): 519 if hasattr(storage_class, "setup"): 520 storage_class.setup(**kwargs) 521 468 522 # Create and attach a new Session instance to cherrypy.serving. 469 523 # It will possess a reference to (and lock, and lazily load) 470 524 # the requested session data. 471 storage_class = storage_type.title() + 'Session'472 525 kwargs['timeout'] = timeout 473 526 kwargs['clean_freq'] = clean_freq 474 cherrypy.serving.session = sess = globals()[storage_class](id, **kwargs)527 cherrypy.serving.session = sess = storage_class(id, **kwargs) 475 528 476 529 # Create cherrypy.session which will proxy to cherrypy.serving.session 477 530 if not hasattr(cherrypy, "session"): 478 531 cherrypy.session = cherrypy._ThreadLocalProxy('session') 479 if hasattr(sess, "setup"):480 sess.setup()481 532 482 533 # Set response cookie trunk/cherrypy/test/test_session.py
r1708 r1736 44 44 def setsessiontype(self, newtype): 45 45 self.__class__._cp_config.update({'tools.sessions.storage_type': newtype}) 46 if hasattr(cherrypy, "session"): 47 del cherrypy.session 46 48 setsessiontype.exposed = True 49 setsessiontype._cp_config = {'tools.sessions.on': False} 47 50 48 51 def index(self): … … 202 205 203 206 207 try: 208 import memcache 209 except ImportError: 210 pass 211 else: 212 class MemcachedSessionTest(helper.CPWebCase): 213 214 def test_0_Session(self): 215 self.getPage('/setsessiontype/memcached') 216 217 self.getPage('/testStr') 218 self.assertBody('1') 219 self.getPage('/testGen', self.cookies) 220 self.assertBody('2') 221 self.getPage('/testStr', self.cookies) 222 self.assertBody('3') 223 self.getPage('/delkey?key=counter', self.cookies) 224 self.assertStatus(200) 225 226 # Wait for the session.timeout (1.02 secs) 227 time.sleep(1.25) 228 self.getPage('/') 229 self.assertBody('1') 230 231 # Test session __contains__ 232 self.getPage('/keyin?key=counter', self.cookies) 233 self.assertBody("True") 234 235 # Test session delete 236 self.getPage('/delete', self.cookies) 237 self.assertBody("done") 238 239 def test_1_Concurrency(self): 240 client_thread_count = 5 241 request_count = 30 242 243 # Get initial cookie 244 self.getPage("/") 245 self.assertBody("1") 246 cookies = self.cookies 247 248 data_dict = {} 249 250 def request(index): 251 for i in xrange(request_count): 252 self.getPage("/", cookies) 253 # Uncomment the following line to prove threads overlap. 254 ## print index, 255 if not self.body.isdigit(): 256 self.fail(self.body) 257 data_dict[index] = v = int(self.body) 258 259 # Start <request_count> concurrent requests from 260 # each of <client_thread_count> clients 261 ts = [] 262 for c in xrange(client_thread_count): 263 data_dict[c] = 0 264 t = threading.Thread(target=request, args=(c,)) 265 ts.append(t) 266 t.start() 267 268 for t in ts: 269 t.join() 270 271 hitcount = max(data_dict.values()) 272 expected = 1 + (client_thread_count * request_count) 273 self.assertEqual(hitcount, expected) 274 275 def test_3_Redirect(self): 276 # Start a new session 277 self.getPage('/testStr') 278 self.getPage('/iredir', self.cookies) 279 self.assertBody("memcached") 280 281 def test_5_Error_paths(self): 282 self.getPage('/unknown/page') 283 self.assertErrorPage(404, "The path '/unknown/page' was not found.") 284 285 # Note: this path is *not* the same as above. The above 286 # takes a normal route through the session code; this one 287 # skips the session code's before_handler and only calls 288 # before_finalize (save) and on_end (close). So the session 289 # code has to survive calling save/close without init. 290 self.getPage('/restricted', self.cookies, method='POST') 291 self.assertErrorPage(405, "Specified method is invalid for this server.") 292 293 294 295 204 296 if __name__ == "__main__": 205 297 setup_server()

