Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 2062

Show
Ignore:
Timestamp:
11/01/08 14:49:57
Author:
fumanchu
Message:

Fix for #870 (Support "session cookies" which flush on browser close).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/lib/sessions.py

    r2045 r2062  
    582582 
    583583def init(storage_type='ram', path=None, path_header=None, name='session_id', 
    584          timeout=60, domain=None, secure=False, clean_freq=5, **kwargs): 
     584         timeout=60, domain=None, secure=False, clean_freq=5, 
     585         persistent=True, **kwargs): 
    585586    """Initialize session object (using cookies). 
    586587     
     
    592593        cookie 'path' will be pulled from request.headers[path_header]. 
    593594    name: the name of the cookie. 
    594     timeout: the expiration timeout (in minutes) for both the cookie and 
    595         stored session data. 
     595    timeout: the expiration timeout (in minutes) for the stored session data. 
     596        If 'persistent' is True (the default), this is also the timeout 
     597        for the cookie. 
    596598    domain: the cookie domain. 
    597599    secure: if False (the default) the cookie 'secure' value will not 
    598600        be set. If True, the cookie 'secure' value will be set (to 1). 
    599601    clean_freq (minutes): the poll rate for expired session cleanup. 
     602    persistent: if True (the default), the 'timeout' argument will be used 
     603        to expire the cookie. If False, the cookie will not have an expiry, 
     604        and the cookie will be a "session cookie" which expires when the 
     605        browser is closed. 
    600606     
    601607    Any additional kwargs will be bound to the new Session instance, 
     
    638644        cherrypy.session = cherrypy._ThreadLocalProxy('session') 
    639645     
     646    if persistent: 
     647        cookie_timeout = timeout 
     648    else: 
     649        # See http://support.microsoft.com/kb/223799/EN-US/ 
     650        # and http://support.mozilla.com/en-US/kb/Cookies 
     651        cookie_timeout = None 
    640652    set_response_cookie(path=path, path_header=path_header, name=name, 
    641                         timeout=timeout, domain=domain, secure=secure) 
     653                        timeout=cookie_timeout, domain=domain, secure=secure) 
    642654 
    643655 
     
    650662        cookie 'path' will be pulled from request.headers[path_header]. 
    651663    name: the name of the cookie. 
    652     timeout: the expiration timeout for the cookie. 
     664    timeout: the expiration timeout for the cookie. If 0 or other boolean 
     665        False, no 'expires' param will be set, and the cookie will be a 
     666        "session cookie" which expires when the browser is closed. 
    653667    domain: the cookie domain. 
    654668    secure: if False (the default) the cookie 'secure' value will not 
  • trunk/cherrypy/test/test_session.py

    r1922 r2062  
    100100            return str(len(cherrypy.session)) 
    101101        length.exposed = True 
     102         
     103        def session_cookie(self): 
     104            cherrypy.session.load() 
     105            return cherrypy.session.id 
     106        session_cookie.exposed = True 
     107        session_cookie._cp_config = { 
     108            'tools.sessions.path': '/session_cookie', 
     109            'tools.sessions.name': 'temp', 
     110            'tools.sessions.persistent': False} 
    102111     
    103112    cherrypy.tree.mount(Root()) 
     
    121130        self.getPage('/testStr') 
    122131        self.assertBody('1') 
     132        cookie_parts = dict([p.strip().split('=') 
     133                             for p in self.cookies[0][1].split(";")]) 
     134        # Assert there is an 'expires' param 
     135        self.assertEqual(set(cookie_parts.keys()), 
     136                         set(['session_id', 'expires', 'Path'])) 
    123137        self.getPage('/testGen', self.cookies) 
    124138        self.assertBody('2') 
     
    276290        self.assertNotEqual(id1, id2) 
    277291        self.assertNotEqual(id2, 'maliciousid') 
     292     
     293    def test_7_session_cookies(self): 
     294        self.getPage('/setsessiontype/ram') 
     295        self.getPage('/session_cookie') 
     296        # grab the cookie ID 
     297        cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")]) 
     298        # Assert there is no 'expires' param 
     299        self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path'])) 
     300        id1 = cookie_parts['temp'] 
     301        self.assertEqual(sessions.RamSession.cache.keys(), [id1]) 
     302         
     303        # Send another request in the same "browser session". 
     304        self.getPage('/session_cookie', self.cookies) 
     305        cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")]) 
     306        # Assert there is no 'expires' param 
     307        self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path'])) 
     308        self.assertBody(id1) 
     309        self.assertEqual(sessions.RamSession.cache.keys(), [id1]) 
     310         
     311        # Wait 0.5 seconds to separate the two sessions 
     312        time.sleep(0.5) 
     313         
     314        # Simulate a browser close by just not sending the cookies 
     315        self.getPage('/session_cookie') 
     316        # grab the cookie ID 
     317        cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")]) 
     318        # Assert there is no 'expires' param 
     319        self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path'])) 
     320        # Assert a new id has been generated... 
     321        id2 = cookie_parts['temp'] 
     322        self.assertNotEqual(id1, id2) 
     323        self.assertEqual(set(sessions.RamSession.cache.keys()), set([id1, id2])) 
     324        # Wait for the session.timeout on the first session (1 second) 
     325        time.sleep(1) 
     326        cache = sessions.RamSession.cache.keys() 
     327        if cache != [id2]: 
     328            if set(cache) == set([id1, id2]): 
     329                self.fail("The first session did not time out.") 
     330            elif not cache: 
     331                self.fail("The second session may have been cleaned up " 
     332                          "prematurely, but it may just be thread timing.") 
     333            else: 
     334                self.fail("Unknown session id in cache: %r", cache) 
     335        # Wait for the session.timeout on the second session (1 second) 
     336        time.sleep(1) 
     337        cache = sessions.RamSession.cache.keys() 
     338        if cache: 
     339            if cache == [id2]: 
     340                self.fail("The second session did not time out.") 
     341            else: 
     342                self.fail("Unknown session id in cache: %r", cache) 
    278343 
    279344 

Hosted by WebFaction

Log in as guest/cpguest to create tickets