Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

New session module (tx Devi).

  • Loading branch information...
commit d2d62c10ce53b4678ebe6b4b9f023d0a5f21b6b7 1 parent 51b438f
Anand Chitipothu anandology authored
4 test/alltests.py
View
@@ -1,8 +1,8 @@
import webtest
def suite():
- modules = ["doctests", "db", "application"]
+ modules = ["doctests", "db", "application", "session"]
return webtest.suite(modules)
if __name__ == "__main__":
- webtest.main()
+ webtest.main()
2  test/db.py
View
@@ -7,7 +7,6 @@ class DBTest(webtest.TestCase):
def setUp(self):
self.db = webtest.setup_database(self.dbname)
- self.db.printing = True
self.db.query("CREATE TABLE person (name text, email text)")
def tearDown(self):
@@ -80,7 +79,6 @@ class MySQLTest(DBTest):
def setUp(self):
self.db = webtest.setup_database(self.dbname)
- self.db.printing = True
# In mysql, transactions are supported only with INNODB engine.
self.db.query("CREATE TABLE person (name text, email text) ENGINE=INNODB")
2  test/doctests.py
View
@@ -3,7 +3,7 @@
import webtest
def suite():
- modules = ["web.utils", "web.db", "web.net", "web.wsgi", "web.http", "web.webapi", "web.request"]
+ modules = ["web.utils", "web.db", "web.net", "web.wsgi", "web.http", "web.webapi", "web.request", "web.session"]
return webtest.doctest_suite(modules)
if __name__ == "__main__":
102 test/session.py
View
@@ -0,0 +1,102 @@
+import webtest
+import web
+import tempfile
+
+class Browser:
+ """Browser simulation.
+ Stores cookies across requests.
+ """
+ def __init__(self, app):
+ self.app = app
+ self.cookies = {}
+ self.response = None
+
+ def open(self, path):
+ headers = {}
+ if self.cookies:
+ headers['HTTP_COOKIE'] = self.cookie_header()
+ self.response = self.app.request(path, headers=headers)
+ if 'Set-Cookie' in self.response.headers:
+ self.read_cookie(self.response.headers['Set-Cookie'])
+
+ return self.response.data
+
+ def cookie_header(self):
+ return "; ".join(["%s=%s" % (k, v) for k, v in self.cookies.items()])
+
+ def read_cookie(self, header):
+ tokens = header.split('; ')
+ d = {}
+ name, value = tokens[0].split("=")
+ for t in tokens[1:]:
+ k, v = t.split("=")
+ d[k.lower()] = v
+
+ #@@ fix this
+ if 'expires' in d:
+ d.pop('name', None)
+ return
+
+ self.cookies[name] = value
+
+class SessionTest(webtest.TestCase):
+ def setUp(self):
+ app = web.auto_application()
+ session = self.make_session(app)
+ class count(app.page):
+ def GET(self):
+ session.count += 1
+ return str(session.count)
+
+ class reset(app.page):
+ def GET(self):
+ session.kill()
+ return ""
+
+ self.app = app
+ self.session = session
+
+ def make_session(self, app):
+ dir = tempfile.mkdtemp()
+ store = web.session.DiskStore(tempfile.mkdtemp())
+ return web.session.Session(app, store, {'count': 0})
+
+ def testSession(self):
+ b = Browser(self.app)
+ self.assertEquals(b.open('/count'), '1')
+ self.assertEquals(b.open('/count'), '2')
+ self.assertEquals(b.open('/count'), '3')
+ b.open('/reset')
+ self.assertEquals(b.open('/count'), '1')
+
+ def testParallelSessions(self):
+ b1 = Browser(self.app)
+ b2 = Browser(self.app)
+
+ b1.open('/count')
+
+ for i in range(1, 10):
+ self.assertEquals(b1.open('/count'), str(i+1))
+ self.assertEquals(b2.open('/count'), str(i))
+
+class DBSessionTest(SessionTest):
+ """Session test with db store."""
+ def make_session(self, app):
+ db = webtest.setup_database("postgres")
+ #db.printing = True
+ db.query(""
+ + "CREATE TABLE session ("
+ + " session_id char(128) unique not null,"
+ + " atime timestamp default (current_timestamp at time zone 'utc'),"
+ + " data text)"
+ )
+ store = web.session.DBStore(db, 'session')
+ return web.session.Session(app, store, {'count': 0})
+
+ def tearDown(self):
+ # there might be some error with the current connection, delete from a new connection
+ self.db = webtest.setup_database("postgres")
+ self.db.query('DROP TABLE session')
+
+if __name__ == "__main__":
+ webtest.main()
8 test/webtest.py
View
@@ -119,6 +119,10 @@ def suite(module_names):
def setup_database(dbname):
if dbname == 'sqlite':
- return web.database(dbn=dbname, db='webpy.db')
+ db = web.database(dbn=dbname, db='webpy.db')
else:
- return web.database(dbn=dbname, db='webpy', user='scott', pw='tiger')
+ db = web.database(dbn=dbname, db='webpy', user='scott', pw='tiger')
+
+ if '-v' in sys.argv:
+ db.printing = True
+ return db
2  web/__init__.py
View
@@ -14,7 +14,7 @@
import utils, db, net, wsgi, http, webapi, request, httpserver, debugerror
import template, form
-#import session
+import session
from utils import *
from db import *
6 web/application.py
View
@@ -84,7 +84,7 @@ def add_processor(self, processor):
"""
self.processors.append(processor)
- def request(self, path='/', method='GET', data=None, host="0.0.0.0:8080", https=False):
+ def request(self, path='/', method='GET', data=None, host="0.0.0.0:8080", headers=None,https=False):
"""Makes request to this application for the specified path and method.
Response will be a storage object with data, status and headers.
@@ -119,6 +119,10 @@ def request(self, path='/', method='GET', data=None, host="0.0.0.0:8080", https=
"""
query = urllib.splitquery(path)[1] or ""
env = dict(HTTP_HOST=host, REQUEST_METHOD=method, PATH_INFO=path, QUERY_STRING=query, HTTPS=https)
+ headers = headers or {}
+ for k, v in headers.items():
+ env[k.upper()] = v
+
if data:
import StringIO
q = urllib.urlencode(data)
703 web/session.py
View
@@ -1,512 +1,269 @@
-'''
-Session module
-(part of web.py)
-'''
-
+"""
+Session Management
+(from web.py)
+"""
+import os
import time
+import datetime
import random
-
-import errno
-import os
-import re
-import glob
-
-try: # Python 2.5
- from hashlib import sha512 as sha
-except ImportError:
- import sha
-
-try: # faster C-implementation
+import md5
+import base64
+try:
import cPickle as pickle
except ImportError:
import pickle
-import web
+import utils
+import webapi as web
+__all__ = [
+ 'Session', 'SessionExpired',
+ 'Store', 'DiskStore', 'DBStore',
+]
-session_parameters = web.utils.Storage({
- 'cookie_name': 'webpy',
- # name of the cookie which will transfer the session id
+web.config.session_parameters = utils.storage({
+ 'cookie_name': 'webpy_session_id',
'cookie_domain': None,
- # cookie domain for the setcookie() when setting session id cookie
-
- 'timeout': 600,
- 'max_age': 24 * 60 * 60,
-
- 'id_seed': 'web.py',
- 'regenerate_id': True, # on every request regenerate id and set again cookie
- 'generator': False, # if False, use default generator
-
- 'ignore_expiration': False,
- 'ignore_old_age': True,
+ 'timeout': 86400, #24 * 60 * 60, # 24 hours in seconds
+ 'ignore_expiry': True,
'ignore_change_ip': True,
- # if the pair ( id, ip ) doesn't match the db, then fail/raise exception/...
-
- 'handler': 'db'
+ 'secret_key': 'fLjUfxqXtfNoIldA0A0J',
+ 'expired_message': 'Session expired',
})
-handler_parameters = web.utils.Storage({
- 'file_dir': '/tmp', # storage dir
- 'file_prefix': 'sess', # session file prefix
- 'db_table': 'session_data' # table name
-})
+class SessionExpired(web.HTTPError):
+ def __init__(self, message):
+ web.HTTPError.__init__(self, '200 OK', {}, data=message)
+class Session(utils.ThreadedDict):
+ """Session management for web.py
+ """
-def sha_hash(seed):
- '''return SHA hash of seed; wrapper around different modules'''
- try: # >= Python 2.5
- return sha(seed).hexdigest()
- except TypeError:
- return sha.new(seed).hexdigest()
+ def __init__(self, app, store, initializer=None):
+ self.__dict__['store'] = store
+ self.__dict__['_initializer'] = initializer
+ self.__dict__['_last_cleanup_time'] = 0
+ self.__dict__['_config'] = utils.storage(web.config.session_parameters)
+ if app:
+ app.add_processor(self._processor)
-class Session(web.utils.Storage):
- '''main session object
- main instance variables
- _handler
- _id
- _data - internal Storage object'''
-
- def __init__(self):
- web.utils.Storage.__init__(self)
- self._id = False
- self._old_id = False
- self._data = {}
- self._handler = None
-
- def __getattr__(self, key):
- if key in ('_id', '_old_id', '_data', '_handler'):
- return object.__getattribute__(self, key)
+ def _processor(self, handler):
+ """Application processor to setup session for every request"""
+ self._cleanup()
+ self._load()
try:
- return self._data[key]
- except KeyError, k:
- raise AttributeError, k
+ return handler()
+ finally:
+ self._save()
+
+ def _load(self):
+ """Load the session from the store, by the id from cookie"""
+ cookie_name = self._config.cookie_name
+ cookie_domain = self._config.cookie_domain
+ self.session_id = web.cookies().get(cookie_name)
+
+ self._check_expiry()
+ if self.session_id:
+ d = self.store[self.session_id]
+ self.update(d)
+ self._validate_ip()
+
+ if not self.session_id:
+ self.session_id = self._generate_session_id()
+
+ if self._initializer:
+ if isinstance(self._initializer, dict):
+ self.update(self._initializer)
+ elif hasattr(self._initializer, '__call__'):
+ self._initializer()
+
+ self.ip = web.ctx.ip
+
+ def _check_expiry(self):
+ # check for expiry
+ if self.session_id and self.session_id not in self.store:
+ if self._config.ignore_expiry:
+ self.session_id = None
+ else:
+ return self.expired()
- def __setattr__(self, key, value):
- if key in ('_id', '_old_id', '_data', '_handler'):
- object.__setattr__(self, key, value)
+ def _validate_ip(self):
+ # check for change of IP
+ if self.session_id and self.get('ip', None) != web.ctx.ip:
+ if self._config.ignore_change_ip:
+ self.session_id = None
+ else:
+ return self.expired()
+
+ def _save(self):
+ cookie_name = self._config.cookie_name
+ cookie_domain = self._config.cookie_domain
+ if not self.get('_killed'):
+ web.setcookie(cookie_name, self.session_id, domain=cookie_domain)
+ self.store[self.session_id] = dict(self)
else:
- self._data[key] = value
-
- def __delattr__(self, key):
- if key in ('_id', '_old_id', '_data', '_handler'):
- #object.__delattr__(self, key, value)
- return
+ web.setcookie(cookie_name, self.session_id, expires=-1, domain=cookie_domain)
+
+ def _generate_session_id(self):
+ """Generate a random id for session"""
- try:
- del self._data[key]
- except KeyError, k:
- raise AttributeError, k
+ while True:
+ rand = random.random()
+ now = time.time()
+ secret_key = self._config.secret_key
+ session_id = md5.new("%s%s%s%s" %(rand, now, web.ctx.ip, secret_key))
+ session_id = session_id.hexdigest()
+ if session_id not in self.store:
+ break
+ return session_id
+
+ def _cleanup(self):
+ """Cleanup the stored sessions"""
+ current_time = time.time()
+ timeout = self._config.timeout
+ if self._last_cleanup_time + timeout > current_time:
+ self.store.cleanup(timeout)
+ self._last_cleanup_time = current_time
+
+ def expired(self):
+ """Called when an expired session is atime"""
+ raise SessionExpired(self._config.expired_message)
+
+ def kill(self):
+ """Kill the session, make it no longer available"""
+ del self.store[self.session_id]
+ self._killed = True
+
+class Store:
+ """Base class for session stores"""
+
+ def __contains__(self, key):
+ raise NotImplemented
def __getitem__(self, key):
- return self._data[key]
+ raise NotImplemented
def __setitem__(self, key, value):
- self._data[key] = value
+ raise NotImplemented
+
+ def cleanup(self, timeout):
+ """removes all the expired sessions"""
+ raise NotImplemented
+
+ def encode(self, session_dict):
+ """encodes session dict as a string"""
+ pickled = pickle.dumps(session_dict)
+ return base64.encodestring(pickled)
+
+ def decode(self, session_data):
+ """decodes the data to get back the session dict """
+ pickled = base64.decodestring(session_data)
+ return pickle.loads(pickled)
+
+class DiskStore(Store):
+ """Store for saving a session on disk
+
+ >>> import tempfile
+ >>> root = tempfile.mkdtemp()
+ >>> s = DiskStore(root)
+ >>> s['a'] = 'foo'
+ >>> s['a']
+ 'foo'
+ >>> time.sleep(0.01)
+ >>> s.cleanup(0.01)
+ >>> s['a']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'a'
+ """
+ def __init__(self, root):
+ # if the storage root doesn't exists, create it.
+ if not os.path.exists(root):
+ os.mkdir(root)
+ self.root = root
+
+ def __contains__(self, key):
+ path = os.path.join(self.root, key)
+ return os.path.exists(path)
- def __delitem__(self, key):
- del self._data[key]
-
- def __repr__(self):
- return '<Session {\'id\': ' + str(self._id) + ', \'data\': ' + str(self._data) + '}>'
-
- # public methods
- def start(self):
- '''starts the session: creates handler object, sets generator,
- regenerates id, sets cookies, calls _identity, _verify, _generate_id'''
- handler = {'db': DBHandler, 'file': FileHandler}
- self._handler = handler[web.config.session_parameters.handler]()
-
- self._identify()
-
- if self._id:
- item = self._retreive()
- if self._verify(item):
- self._data = item.data
-
- if web.config.session_parameters.regenerate_id:
- self._old_id = self._id
- self._id = self._generate_id()
-
- if not self._id:
- self._id = self._generate_id()
-
- def get_id(self):
- '''returns current session id'''
- return self._id
-
- def cleanup(self):
- '''cleans expired sessions'''
- self._handler.clean(web.config.session_parameters.timeout)
-
- def save(self):
- '''save session data'''
- self._store()
-
- web.setcookie(web.config.session_parameters.cookie_name,
- self._id,
- web.config.session_parameters.timeout,
- web.config.session_parameters.cookie_domain)
-
- def destroy(self):
- '''removes session (including cookies)'''
- self._remove()
- self._id = False
- self._old_id = False
- web.setcookie(web.config.session_parameters.cookie_name,
- '',
- (-1) * web.config.session_parameters.timeout,
- web.config.session_parameters.cookie_domain)
-
- # private methods
- def _generate_id(self):
- '''generates session id
- using implicit session id generator or user supplied generator'''
- if web.config.session_parameters.generator:
- return web.config.session_parameters.generator()
-
- seed = '%s %s %s %s' % (random.random(),
- time.time(),
- web.ctx.ip,
- web.config.session_parameters.id_seed)
- return sha_hash(seed)
-
- def _identify(self):
- '''identifies session id (through cookies)'''
- try:
- self._id = web.cookies().__getattr__(web.config.session_parameters.cookie_name)
- except (AttributeError, KeyError):
- self._id = False
+ def __getitem__(self, key):
+ path = os.path.join(self.root, key)
+ if os.path.exists(path):
+ pickled = open(path).read()
+ return self.decode(pickled)
+ else:
+ raise KeyError, key
- def _verify(self, item):
- '''verifies with retreived data from handler object'''
+ def __setitem__(self, key, value):
+ pickled = self.encode(value)
+ path = os.path.join(self.root, key)
try:
- self._id = item.id
- except AttributeError:
- self._id = False
- return False
+ f = open(path, 'w')
+ try:
+ f.write(pickled)
+ finally:
+ f.close()
+ except IOError:
+ pass
+ def __delitem__(self, key):
+ path = os.path.join(self.root, key)
+ if os.path.exists(path):
+ os.remove(path)
+
+ def cleanup(self, timeout):
now = time.time()
-
- if not web.config.session_parameters.ignore_expiration \
- and now - item.touched >= web.config.session_parameters.timeout:
- self._remove()
- self._id = False
- return False
-
- if not web.config.session_parameters.ignore_change_ip \
- and web.ctx.ip != item.ip.strip():
- self._remove()
- self._id = False
- return False
-
- if not web.config.session_parameters.ignore_old_age \
- and now - item.created >= web.config.session_parameters.max_age:
- self._remove()
- self._id = False
- return False
-
- return True
-
- def _store(self):
- '''stores session data (wrapper around handler object)'''
- self._handler.store(self._id, web.ctx.ip, self._data, self._old_id)
-
- def _retreive(self):
- '''retreive session data (wrapper around handler object)'''
- return self._handler.retreive(self._id)
-
- def _remove(self):
- '''removes session data (wrapper around handler object)'''
- self._handler.remove(self._id)
-
- if self._old_id:
- self._handler.remove(self._old_id)
-
-
-class Handler:
- '''abstract handler class'''
- def __init__(self):
- pass
-
- def store(self, id_, client_ip, data, old_id=False):
- '''takes
- client_ip - client ip
- id_ - string
- data - Storage
- old_id - if the id regenerates after every request'''
- pass
-
- def retreive(self, id_):
- '''returns Storage'''
- pass
-
- def remove(self, id_):
- '''removes session'''
- pass
-
- def clean(self, timeout):
- '''removes all expired sessions'''
- pass
-
-
-class DBHandler(Handler):
- '''needs an table:
- CREATE TABLE session_data (
- id CHAR(129) UNIQUE NOT NULL,
- ip CHAR(16) NOT NULL,
- created int NOT NULL,
- touched int NOT NULL,
+ for f in os.listdir(self.root):
+ path = os.path.join(self.root, f)
+ atime = os.stat(path).st_atime
+ if now - atime > timeout :
+ os.remove(path)
+
+class DBStore(Store):
+ """Store for saving a session in database
+ Needs a table with the following columns:
+
+ session_id CHAR(128) UNIQUE NOT NULL,
+ atime DATETIME NOT NULL default current_timestamp,
data TEXT
- );'''
-
- def store(self, id_, client_ip, data, old_id=False):
- '''takes
- client_ip - client ip
- id_ - string
- data - Storage
- old_id - if the id regenerates after every request'''
- do_insert = True
-
- if not old_id:
- old_id = id_
-
- if len(list(web.select(web.config.handler_parameters.db_table,
- vars={'id': old_id},
- what='id',
- where='id = $id'))) == 1:
- do_insert = False
-
- web.transact()
-
- now = int(time.time())
- try:
- if do_insert:
- web.db.insert(web.config.handler_parameters.db_table,
- seqname=False, id=id_, ip=client_ip, touched=now,
- created=now, data=pickle.dumps(data, 0))
- else:
- web.update(web.config.handler_parameters.db_table,
- where='id = $old_id',
- vars={'old_id': old_id},
- id=id_, ip=client_ip, touched=now,
- data=pickle.dumps(data, 0))
- web.commit()
-
- except Exception, inst:
- web.rollback()
- raise inst
-
- def remove(self, id_):
- '''removes session'''
- web.transact()
- try:
- web.delete(web.config.handler_parameters.db_table,
- where='id = $id', vars={'id': id_})
- web.commit()
-
- except Exception, inst:
- web.rollback()
- raise inst
-
- def retreive(self, id_):
- '''returns Storage'''
- try:
- tmp = web.select(web.config.handler_parameters.db_table,
- what='*',
- vars={
- 'id': id_,
- 'timeout': web.config.session_parameters.timeout
- },
- where='id = $id')
-
- except Exception, inst:
- raise inst
+ """
+ def __init__(self, db, table_name):
+ self.db = db
+ self.table = table_name
+
+ def __contains__(self, key):
+ data = self.db.select(self.table, where="session_id=$key", vars=locals())
+ return bool(list(data))
+ def __getitem__(self, key):
+ now = datetime.datetime.now()
try:
- result = tmp[0]
- result.data = pickle.loads(result.data.encode('ascii'))
- return result
-
+ s = self.db.select(self.table, where="session_id=$key", vars=locals())[0]
+ self.db.update(self.table, where="session_id=$key", atime=now, vars=locals())
except IndexError:
- return web.Storage()
-
- def clean(self, timeout):
- '''removes all expired sessions'''
- web.transact()
-
- try:
- web.delete(web.config.handler_parameters.db_table,
- where='($now - touched) >= $timeout',
- vars={'timeout': timeout, 'now': int(time.time())})
- web.commit()
-
- except Exception, inst:
- web.rollback()
- raise inst
-
-
-class FileHandler(Handler):
- '''needs dir with rw permission to create session files'''
- def __init__(self):
- '''normalizes file_dir path'''
- Handler.__init__(self)
- self._path = os.path.abspath(web.config.handler_parameters.file_dir)
-
- def store(self, id_, client_ip, data, old_id=False):
- '''takes
- client_ip - client ip
- id_ - string
- data - Storage
- old_id - if the id regenerates after every request'''
- created = False
- self._acquire_lock(id_)
-
- if old_id:
- self._acquire_lock(old_id)
-
- try:
- file_desc = file(self._session_file(old_id), 'rb')
- except (IOError, OSError), inst:
- if inst.errno != errno.ENOENT:
- self._release_lock(old_id)
- self._release_lock(id_)
- raise inst
- else:
- result = pickle.load(file_desc)
- created = result.created
- file_desc.close()
- os.unlink(self._session_file(old_id))
-
- self._release_lock(old_id)
-
- if not created:
- created = int(time.time())
-
- file_desc = file(self._session_file(id_), 'wb')
- box = web.Storage({
- 'id': id_,
- 'ip': client_ip,
- 'data': data,
- 'created': created
- })
-
- pickle.dump(box, file_desc, 0)
- file_desc.close()
-
- self._release_lock(id_)
-
- def retreive(self, id_):
- '''returns Storage'''
- self._acquire_lock(id_)
-
- try:
- file_desc = file(self._session_file(id_), 'rb')
- except (IOError, OSError), inst:
- if inst.errno != errno.ENOENT:
- raise inst
-
- result = web.Storage()
+ raise KeyError
else:
- result = pickle.load(file_desc)
- result.touched = os.fstat(file_desc.fileno()).st_mtime
- file_desc.close()
-
- self._release_lock(id_)
- return result
-
- def remove(self, id_):
- '''removes session'''
- self._acquire_lock(id_)
-
- try:
- os.unlink(self._session_file(id_))
- except (IOError, OSError), inst:
- if inst.errno != errno.ENOENT:
- raise inst
-
- self._release_lock(id_)
-
- def clean(self, timeout):
- '''removes all expired sessions'''
- files = glob.glob('%s/%s*' % (self._path,
- web.config.handler_parameters.file_prefix))
- patern = '%s/%s(?P<id>[0-9a-f]{40,128})(?!.lock)' % (self._path,
- web.config.handler_parameters.file_prefix)
-
- compiled = re.compile(patern)
- now = time.time()
-
- for file_name in files:
- try:
- id_ = compiled.match(file_name).group('id')
- except AttributeError:
- continue
-
- if self._acquire_lock(id_, False):
- if now - os.path.getmtime(file_name) > timeout:
- os.unlink(file_name)
-
- self._release_lock(id_)
-
- # private methods
- def _session_file(self, id_):
- '''returns session file name'''
- return '%s/%s%s' % (self._path, web.config.handler_parameters.file_prefix, id_)
-
- def _lock_file(self, id_):
- '''returns session lock file name'''
- return '%s.lock' % self._session_file(id_)
-
- def _acquire_lock(self, id_, blocking=True):
- '''create lock file
- if blocking is False, don't loop'''
- file_name = self._lock_file(id_)
-
- while True:
- try:
- file_desc = os.open(file_name, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
- except (IOError, OSError), inst:
- if inst.errno != errno.EEXIST:
- raise inst
- else:
- os.close(file_desc)
- break
-
- try:
- now = time.time()
- if now - os.path.getmtime(file_name) > 60:
- os.unlink(file_name)
-
- except (IOError, OSError), inst:
- if inst.errno != errno.ENOENT:
- raise inst
-
- if not blocking:
- return False
-
- time.sleep(0.1)
-
- return True
-
- def _release_lock(self, id_):
- '''unlink lock file'''
- try:
- os.unlink(self._lock_file(id_))
- except (IOError, OSError), inst:
- if inst.errno != errno.ENOENT:
- raise inst
-
-
-def _load_session():
- '''loadhook function
- create session object, sets parameters'''
- web.webapi.config.session_parameters = session_parameters
- web.webapi.config.handler_parameters = handler_parameters
- web.webapi.ctx.session = Session()
+ return self.decode(s.data)
+ def __setitem__(self, key, value):
+ pickled = self.encode(value)
+ now = datetime.datetime.now()
+ if key in self:
+ self.db.update(self.table, where="session_id=$key", data=pickled, vars=locals())
+ else:
+ self.db.insert(self.table, False, session_id=key, data=pickled )
+
+ def __delitem__(self, key):
+ self.db.delete(self.table, where="session_id=$key", vars=locals())
-web.webapi.loadhooks['session'] = _load_session
+ def cleanup(self, timeout):
+ timeout = datetime.timedelta(timeout/(24.0*60*60)) #timedelta takes numdays as arg
+ last_allowed_time = datetime.datetime.now() - timeout
+ self.db.delete(self.table, where="$last_allowed_time > atime", vars=locals())
+if __name__ == '__main__' :
+ import doctest
+ doctest.testmod()
12 web/webapi.py
View
@@ -31,15 +31,9 @@
: Set to `True` if you would like SQL queries and timings to be
printed to the debug output.
`session_parameters`
- : dictionary/storage containing main session parameters
- cookie_name, cookie_domain, timeout, max_age,
- id_seed, regenerate_id, generator,
- ignore_change_ip, ignore_expiration, ignore_old_age,
- handler
-`handler_parameters`
- : session handler parameters
- file_dir, file_prefix,
- db_table
+ : A dictionary containing session parameters
+ cookie_name, cookie_domain, timeout,
+ ignore_change_ip, ignore_expiry, expired_message
"""
class HTTPError(Exception):
Please sign in to comment.
Something went wrong with that request. Please try again.