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

Changeset 1067

Show
Ignore:
Timestamp:
04/24/06 19:08:29
Author:
fumanchu
Message:

Fixed session module for the new tool API.

Files:

Legend:

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

    r1047 r1067  
    5959thread_data = local() 
    6060 
    61 ### Create variables needed for session (see lib/sessionfilter.py for more info) 
    62 ##from filters import sessionfilter 
    63 ##session = sessionfilter.SessionWrapper() 
    64 ##_session_data_holder = {} # Needed for RAM sessions only 
    65 ##_session_lock_dict = {} # Needed for RAM sessions only 
    66 ##_session_last_clean_up_time = datetime.datetime.now() 
    67  
    6861def expose(func=None, alias=None): 
    6962    """Expose the function, optionally providing an alias or set of aliases.""" 
  • trunk/cherrypy/lib/sessions.py

    r1049 r1067  
    77 
    88Global variables (RAM backend only): 
    9     - cherrypy._session_lock_dict: dictionary containing the locks for all session_id 
    10     - cherrypy._session_data_holder: dictionary containing the data for all sessions 
     9    - _session_lock_dict: dictionary containing the locks for all session_id 
     10    - _session_data_holder: dictionary containing the data for all sessions 
    1111 
    1212""" 
     
    2727import cherrypy 
    2828 
     29_session_last_clean_up_time = datetime.datetime.now() 
     30_session_data_holder = {} # Needed for RAM sessions only 
     31_session_lock_dict = {} # Needed for RAM sessions only 
     32 
    2933 
    3034def generate_id(): 
     
    3236    return sha.new('%s' % random.random()).hexdigest() 
    3337 
     38 
     39def noop(data): pass 
    3440 
    3541class Session: 
     
    4450    """ 
    4551     
     52    timeout = 60 
     53    locking = 'explicit' 
     54    deadlock_timeout = 30 
     55    clean_up_delay = 5 
     56    storage_type = 'Ram' 
     57    storage_class = None 
     58    cookie_name = 'session_id' 
     59    cookie_domain = None 
     60    cookie_secure = False 
     61    cookie_path = None 
     62    cookie_path_from_header = None 
     63     
    4664    def __init__(self): 
    47         conf = cherrypy.config.get 
    48          
    4965        self.storage = None 
    5066        self.locked = False 
    51         self.loaded = True 
    52          
    53         self.timeout = conf('session_filter.timeout', 60) 
    54         self.locking = conf('session_filter.locking', 'explicit') 
    55         self.on_create = conf('session_filter.on_create', lambda data: None) 
    56         self.on_renew = conf('session_filter.on_renew', lambda data: None) 
    57         self.on_delete = conf('session_filter.on_delete', lambda data: None) 
    58         gen_id = conf('session_filter.generate_id', generate_id) 
    59         self.deadlock_timeout = conf('session_filter.deadlock_timeout', 30) 
    60          
    61         clean_up_delay = conf('session_filter.clean_up_delay', 5) 
    62         clean_up_delay = datetime.timedelta(seconds = clean_up_delay * 60) 
    63          
    64         storage = conf('session_filter.storage_type', 'Ram').title() 
     67        self.loaded = False 
     68        self.saved = False 
     69         
     70        self.generate_id = generate_id 
     71        self.on_create = noop 
     72        self.on_renew = noop 
     73        self.on_delete = noop 
     74     
     75    def load(self): 
     76        clean_up_delay = datetime.timedelta(seconds = self.clean_up_delay * 60) 
    6577         
    6678        # People can set their own custom class 
    67         #   through session_filter.storage_class 
    68         cls = conf('session_filter.storage_class', None) 
    69         if cls is None: 
    70             cls = globals()[storage + 'Storage'] 
    71         self.storage = cls() 
     79        #   through tools.sessions.storage_class 
     80        if self.storage_class is None: 
     81            self.storage_class = globals()[self.storage_type.title() + 'Storage'] 
     82        self.storage = self.storage_class() 
    7283         
    7384        now = datetime.datetime.now() 
    7485        # Check if we need to clean up old sessions 
    75         if cherrypy._session_last_clean_up_time + clean_up_delay < now: 
    76             cherrypy._session_last_clean_up_time = now 
     86        global _session_last_clean_up_time 
     87        if _session_last_clean_up_time + clean_up_delay < now: 
     88            _session_last_clean_up_time = now 
    7789            # Run clean_up in other thread to avoid blocking this request 
    7890            thread.start_new_thread(self.storage.clean_up, (self,)) 
     
    8092        self.data = {} 
    8193         
     94        if self.cookie_path is None: 
     95            if self.cookie_path_from_header is not None: 
     96                geth = cherrypy.request.headers.get 
     97                self.cookie_path = geth(self.cookie_path_from_header, None) 
     98            if self.cookie_path is None: 
     99                self.cookie_path = '/' 
     100         
    82101        # Check if request came with a session ID 
    83         cookie_name = conf('session_filter.cookie_name', 'session_id') 
    84         cookie_domain = conf('session_filter.cookie_domain', None) 
    85         cookie_secure = conf('session_filter.cookie_secure', False) 
    86         cookie_path = conf('session_filter.cookie_path', None) 
    87         if cookie_path is None: 
    88             cookie_path_header = conf('session_filter.cookie_path_from_header', None) 
    89             if cookie_path_header is not None: 
    90                 cookie_path = cherrypy.request.headers.get(cookie_path_header, None) 
    91             if cookie_path is None: 
    92                 cookie_path = '/' 
    93         if cookie_name in cherrypy.request.simple_cookie: 
     102        if self.cookie_name in cherrypy.request.simple_cookie: 
    94103            # It did: we mark the data as needing to be loaded 
    95             self.id = cherrypy.request.simple_cookie[cookie_name].value 
     104            self.id = cherrypy.request.simple_cookie[self.cookie_name].value 
    96105             
    97106            # If using implicit locking, acquire lock 
     
    101110        else: 
    102111            # No id yet 
    103             self.id = gen_id() 
     112            self.id = self.generate_id() 
    104113            self.data['_id'] =  self.id 
    105114            self.on_create(self.data) 
     
    107116        # Set response cookie 
    108117        cookie = cherrypy.response.simple_cookie 
    109         cookie[cookie_name] = self.id 
    110         cookie[cookie_name]['path'] = cookie_path 
     118        cookie[self.cookie_name] = self.id 
     119        cookie[self.cookie_name]['path'] = self.cookie_path 
    111120        # We'd like to use the "max-age" param as 
    112121        #   http://www.faqs.org/rfcs/rfc2109.html indicates but IE doesn't 
     
    116125        #cookie[cookie_name]['max-age'] = self.timeout * 60 
    117126        gmt_expiration_time = time.gmtime(time.time() + (self.timeout * 60)) 
    118         cookie[cookie_name]['expires'] = time.strftime( 
     127        cookie[self.cookie_name]['expires'] = time.strftime( 
    119128                "%a, %d-%b-%Y %H:%M:%S GMT", gmt_expiration_time) 
    120         if cookie_domain is not None: 
    121             cookie[cookie_name]['domain'] = cookie_domain 
    122         if cookie_secure is True: 
    123             cookie[cookie_name]['secure'] = 1 
     129        if self.cookie_domain is not None: 
     130            cookie[self.cookie_name]['domain'] = self.cookie_domain 
     131        if self.cookie_secure is True: 
     132            cookie[self.cookie_name]['secure'] = 1 
    124133     
    125134    def save(self): 
     
    135144            # Always release the lock if the user didn't release it 
    136145            self.storage.release_lock() 
     146         
     147        self.saved = True 
    137148 
    138149 
     
    143154 
    144155class SessionNotEnabledError(Exception): 
    145     """User forgot to set session_filter.on to True""" 
     156    """User forgot to set tools.sessions.on to True""" 
    146157    pass 
    147158 
    148 class SessionStoragePathNotConfiguredError(Exception): 
     159class SessionStoragePathError(Exception): 
    149160    """User set storage_type to file but forgot to set the storage_path""" 
    150161    pass 
    151162 
    152163 
    153 class SessionFilter(basefilter.BaseFilter): 
    154      
    155     def before_request_body(self): 
    156         if cherrypy.config.get('session_filter.on', False): 
    157             cherrypy.request._session = Session() 
    158      
    159     def before_finalize(self): 
    160         sess = getattr(cherrypy.request, "_session", None) 
    161         if sess: 
    162             # Make a wrapper around the body in order to save the session 
    163             #   either before or after the body is returned 
    164             def save_session_data(body, sess): 
    165                 if isinstance(body, types.GeneratorType): 
    166                     for line in body: 
    167                         yield line 
    168                     sess.save() 
    169                 else: 
    170                     sess.save() 
    171                     for line in body: 
    172                         yield line 
    173             cherrypy.response.body = save_session_data(cherrypy.response.body, sess) 
    174      
    175     def on_end_request(self): 
    176         sess = getattr(cherrypy.request, "_session", None) 
    177         if sess: 
    178             if sess.locked: 
    179                 # If the session is still locked we release the lock 
    180                 sess.storage.release_lock() 
    181             if sess.storage: 
    182                 sess.storage = None 
    183  
    184  
    185164class RamStorage: 
    186165    """ Implementation of the RAM backend for sessions """ 
    187166     
    188167    def load(self, id): 
    189         return cherrypy._session_data_holder.get(id) 
     168        return _session_data_holder.get(id) 
    190169     
    191170    def save(self, id, data, expiration_time): 
    192         cherrypy._session_data_holder[id] = (data, expiration_time) 
     171        _session_data_holder[id] = (data, expiration_time) 
    193172     
    194173    def acquire_lock(self): 
    195174        sess = cherrypy.request._session 
    196175        id = cherrypy.session.id 
    197         lock = cherrypy._session_lock_dict.get(id) 
     176        lock = _session_lock_dict.get(id) 
    198177        if lock is None: 
    199178            lock = threading.Lock() 
    200             cherrypy._session_lock_dict[id] = lock 
     179            _session_lock_dict[id] = lock 
    201180        startTime = time.time() 
    202181        while True: 
     
    209188     
    210189    def release_lock(self): 
    211         sess = cherrypy.request._session 
    212         id = cherrypy.session['_id'] 
    213         cherrypy._session_lock_dict[id].release() 
    214         sess.locked = False 
     190        _session_lock_dict[cherrypy.session['_id']].release() 
     191        cherrypy.request._session.locked = False 
    215192     
    216193    def clean_up(self, sess): 
    217194        to_be_deleted = [] 
    218195        now = datetime.datetime.now() 
    219         for id, (data, expiration_time) in cherrypy._session_data_holder.iteritems(): 
     196        for id, (data, expiration_time) in _session_data_holder.iteritems(): 
    220197            if expiration_time < now: 
    221198                to_be_deleted.append(id) 
    222199        for id in to_be_deleted: 
    223200            try: 
    224                 deleted_session = cherrypy._session_data_holder[id] 
    225                 del cherrypy._session_data_holder[id] 
     201                deleted_session = _session_data_holder[id] 
     202                del _session_data_holder[id] 
    226203                sess.on_delete(deleted_session) 
    227204            except KeyError: 
     
    254231     
    255232    def acquire_lock(self): 
    256         sess = cherrypy.request._session 
    257233        file_path = self._get_file_path(cherrypy.session.id) 
    258         lock_file_path = file_path + self.LOCK_SUFFIX 
    259         self._lock_file(lock_file_path) 
    260         sess.locked = True 
     234        self._lock_file(file_path + self.LOCK_SUFFIX) 
     235        cherrypy.request._session.locked = True 
    261236     
    262237    def release_lock(self): 
    263         sess = cherrypy.request._session 
    264238        file_path = self._get_file_path(cherrypy.session.id) 
    265         lock_file_path = file_path + self.LOCK_SUFFIX 
    266         self._unlock_file(lock_file_path) 
    267         sess.locked = False 
     239        self._unlock_file(file_path + self.LOCK_SUFFIX) 
     240        cherrypy.request._session.locked = False 
    268241     
    269242    def clean_up(self, sess): 
    270         storage_path = cherrypy.config.get('session_filter.storage_path'
     243        storage_path = getattr(sess, "storage_path"
    271244        if storage_path is None: 
    272245            return 
     
    294267     
    295268    def _get_file_path(self, id): 
    296         storage_path = cherrypy.config.get('session_filter.storage_path'
     269        storage_path = getattr(cherrypy.request._session, "storage_path"
    297270        if storage_path is None: 
    298             raise SessionStoragePathNotConfiguredError() 
     271            raise SessionStoragePathError() 
    299272        fileName = self.SESSION_PREFIX + id 
    300273        file_path = os.path.join(storage_path, fileName) 
     
    302275     
    303276    def _lock_file(self, path): 
    304         sess = cherrypy.request._session 
     277        timeout = cherrypy.request._session.deadlock_timeout 
    305278        startTime = time.time() 
    306279        while True: 
     
    308281                lockfd = os.open(path, os.O_CREAT|os.O_WRONLY|os.O_EXCL) 
    309282            except OSError: 
    310                 if time.time() - startTime > sess.deadlock_timeout: 
     283                if time.time() - startTime > timeout: 
    311284                    raise SessionDeadlockError() 
    312285                time.sleep(0.5) 
     
    331304     
    332305    def __init__(self): 
    333         self.db = cherrypy.config.get('session_filter.get_db')() 
     306        self.db = cherrypy.request._session.get_db() 
    334307        self.cursor = self.db.cursor() 
    335308     
     
    407380        elif name == 'id': 
    408381            return sess.id 
    409  
     382         
    410383        if not sess.loaded: 
    411384            data = sess.storage.load(sess.id) 
     
    423396        return getattr(sess.data, name) 
    424397 
     398 
     399# The actual hook functions 
     400 
     401def save(): 
     402    # Save the session either before or after the body is returned 
     403    if not isinstance(cherrypy.response.body, types.GeneratorType): 
     404        cherrypy.request._session.save() 
     405 
     406def cleanup(): 
     407    sess = cherrypy.request._session 
     408    if not sess.saved: 
     409        sess.save() 
     410     
     411    if sess.locked: 
     412        # If the session is still locked we release the lock 
     413        sess.storage.release_lock() 
     414    if sess.storage: 
     415        sess.storage = None 
     416 
     417def wrap(*args, **kwargs): 
     418    """Make a decorator for this tool.""" 
     419    def deco(f): 
     420        def wrapper(*a, **kw): 
     421            return f(*a, **kw) 
     422            save(*args, **kwargs) 
     423            cherrypy.request.hooks.attach('on_end_request', cleanup) 
     424        return wrapper 
     425    return deco 
     426 
     427def setup(conf): 
     428    """Hook this tool into cherrypy.request using the given conf. 
     429     
     430    The standard CherryPy request object will automatically call this 
     431    method when the tool is "turned on" in config. 
     432    """ 
     433    def wrapper(): 
     434        s = cherrypy.request._session = Session() 
     435        for k, v in conf.iteritems(): 
     436            setattr(s, str(k), v) 
     437        s.load() 
     438         
     439        if not hasattr(cherrypy, "session"): 
     440            cherrypy.session = SessionWrapper() 
     441     
     442    cherrypy.request.hooks.attach('before_request_body', wrapper) 
     443    cherrypy.request.hooks.attach('before_finalize', save) 
     444    cherrypy.request.hooks.attach('on_end_request', cleanup) 
  • trunk/cherrypy/test/test_session_filter.py

    r1017 r1067  
    2020         
    2121        def setsessiontype(self, newtype): 
    22             cherrypy.config.update({'session_filter.storage_type': newtype}) 
     22            cherrypy.config.update({'tools.sessions.storage_type': newtype}) 
    2323        setsessiontype.exposed = True 
    2424         
     
    2727            'server.log_to_screen': False, 
    2828            'server.environment': 'production', 
    29             'session_filter.on': True, 
    30             'session_filter.storage_type' : 'file', 
    31             'session_filter.storage_path' : '.', 
     29            'tools.sessions.on': True, 
     30            'tools.sessions.storage_type' : 'file', 
     31            'tools.sessions.storage_path' : '.', 
    3232    }) 
    3333 
  • trunk/cherrypy/tools.py

    r1060 r1067  
    126126 
    127127from cherrypy.lib import cptools 
     128session_auth = MainTool(cptools.session_auth) 
    128129base_url = Tool('before_request_body', cptools.base_url) 
    129130response_headers = Tool('before_finalize', cptools.response_headers) 
     
    153154 
    154155# These modules are themselves Tools 
    155 from cherrypy.lib import caching, xmlrpc 
     156from cherrypy.lib import caching, sessions, xmlrpc 

Hosted by WebFaction

Log in as guest/cpguest to create tickets