summaryrefslogtreecommitdiffstats
path: root/webapp/django/contrib/sessions/backends/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/contrib/sessions/backends/base.py')
-rw-r--r--webapp/django/contrib/sessions/backends/base.py287
1 files changed, 287 insertions, 0 deletions
diff --git a/webapp/django/contrib/sessions/backends/base.py b/webapp/django/contrib/sessions/backends/base.py
new file mode 100644
index 0000000000..b4cdeadd81
--- /dev/null
+++ b/webapp/django/contrib/sessions/backends/base.py
@@ -0,0 +1,287 @@
+import base64
+import os
+import random
+import sys
+import time
+from datetime import datetime, timedelta
+try:
+ import cPickle as pickle
+except ImportError:
+ import pickle
+
+from django.conf import settings
+from django.core.exceptions import SuspiciousOperation
+from django.utils.hashcompat import md5_constructor
+
+# Use the system (hardware-based) random number generator if it exists.
+if hasattr(random, 'SystemRandom'):
+ randrange = random.SystemRandom().randrange
+else:
+ randrange = random.randrange
+MAX_SESSION_KEY = 18446744073709551616L # 2 << 63
+
+class CreateError(Exception):
+ """
+ Used internally as a consistent exception type to catch from save (see the
+ docstring for SessionBase.save() for details).
+ """
+ pass
+
+class SessionBase(object):
+ """
+ Base class for all Session classes.
+ """
+ TEST_COOKIE_NAME = 'testcookie'
+ TEST_COOKIE_VALUE = 'worked'
+
+ def __init__(self, session_key=None):
+ self._session_key = session_key
+ self.accessed = False
+ self.modified = False
+
+ def __contains__(self, key):
+ return key in self._session
+
+ def __getitem__(self, key):
+ return self._session[key]
+
+ def __setitem__(self, key, value):
+ self._session[key] = value
+ self.modified = True
+
+ def __delitem__(self, key):
+ del self._session[key]
+ self.modified = True
+
+ def keys(self):
+ return self._session.keys()
+
+ def items(self):
+ return self._session.items()
+
+ def get(self, key, default=None):
+ return self._session.get(key, default)
+
+ def pop(self, key, *args):
+ self.modified = self.modified or key in self._session
+ return self._session.pop(key, *args)
+
+ def setdefault(self, key, value):
+ if key in self._session:
+ return self._session[key]
+ else:
+ self.modified = True
+ self._session[key] = value
+ return value
+
+ def set_test_cookie(self):
+ self[self.TEST_COOKIE_NAME] = self.TEST_COOKIE_VALUE
+
+ def test_cookie_worked(self):
+ return self.get(self.TEST_COOKIE_NAME) == self.TEST_COOKIE_VALUE
+
+ def delete_test_cookie(self):
+ del self[self.TEST_COOKIE_NAME]
+
+ def encode(self, session_dict):
+ "Returns the given session dictionary pickled and encoded as a string."
+ pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
+ pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
+ return base64.encodestring(pickled + pickled_md5)
+
+ def decode(self, session_data):
+ encoded_data = base64.decodestring(session_data)
+ pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
+ if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+ raise SuspiciousOperation("User tampered with session cookie.")
+ try:
+ return pickle.loads(pickled)
+ # Unpickling can cause a variety of exceptions. If something happens,
+ # just return an empty dictionary (an empty session).
+ except:
+ return {}
+
+ def update(self, dict_):
+ self._session.update(dict_)
+ self.modified = True
+
+ def has_key(self, key):
+ return self._session.has_key(key)
+
+ def values(self):
+ return self._session.values()
+
+ def iterkeys(self):
+ return self._session.iterkeys()
+
+ def itervalues(self):
+ return self._session.itervalues()
+
+ def iteritems(self):
+ return self._session.iteritems()
+
+ def clear(self):
+ # To avoid unnecessary persistent storage accesses, we set up the
+ # internals directly (loading data wastes time, since we are going to
+ # set it to an empty dict anyway).
+ self._session_cache = {}
+ self.accessed = True
+ self.modified = True
+
+ def _get_new_session_key(self):
+ "Returns session key that isn't being used."
+ # The random module is seeded when this Apache child is created.
+ # Use settings.SECRET_KEY as added salt.
+ try:
+ pid = os.getpid()
+ except AttributeError:
+ # No getpid() in Jython, for example
+ pid = 1
+ while 1:
+ session_key = md5_constructor("%s%s%s%s"
+ % (randrange(0, MAX_SESSION_KEY), pid, time.time(),
+ settings.SECRET_KEY)).hexdigest()
+ if not self.exists(session_key):
+ break
+ return session_key
+
+ def _get_session_key(self):
+ if self._session_key:
+ return self._session_key
+ else:
+ self._session_key = self._get_new_session_key()
+ return self._session_key
+
+ def _set_session_key(self, session_key):
+ self._session_key = session_key
+
+ session_key = property(_get_session_key, _set_session_key)
+
+ def _get_session(self, no_load=False):
+ """
+ Lazily loads session from storage (unless "no_load" is True, when only
+ an empty dict is stored) and stores it in the current instance.
+ """
+ self.accessed = True
+ try:
+ return self._session_cache
+ except AttributeError:
+ if self._session_key is None or no_load:
+ self._session_cache = {}
+ else:
+ self._session_cache = self.load()
+ return self._session_cache
+
+ _session = property(_get_session)
+
+ def get_expiry_age(self):
+ """Get the number of seconds until the session expires."""
+ expiry = self.get('_session_expiry')
+ if not expiry: # Checks both None and 0 cases
+ return settings.SESSION_COOKIE_AGE
+ if not isinstance(expiry, datetime):
+ return expiry
+ delta = expiry - datetime.now()
+ return delta.days * 86400 + delta.seconds
+
+ def get_expiry_date(self):
+ """Get session the expiry date (as a datetime object)."""
+ expiry = self.get('_session_expiry')
+ if isinstance(expiry, datetime):
+ return expiry
+ if not expiry: # Checks both None and 0 cases
+ expiry = settings.SESSION_COOKIE_AGE
+ return datetime.now() + timedelta(seconds=expiry)
+
+ def set_expiry(self, value):
+ """
+ Sets a custom expiration for the session. ``value`` can be an integer,
+ a Python ``datetime`` or ``timedelta`` object or ``None``.
+
+ If ``value`` is an integer, the session will expire after that many
+ seconds of inactivity. If set to ``0`` then the session will expire on
+ browser close.
+
+ If ``value`` is a ``datetime`` or ``timedelta`` object, the session
+ will expire at that specific future time.
+
+ If ``value`` is ``None``, the session uses the global session expiry
+ policy.
+ """
+ if value is None:
+ # Remove any custom expiration for this session.
+ try:
+ del self['_session_expiry']
+ except KeyError:
+ pass
+ return
+ if isinstance(value, timedelta):
+ value = datetime.now() + value
+ self['_session_expiry'] = value
+
+ def get_expire_at_browser_close(self):
+ """
+ Returns ``True`` if the session is set to expire when the browser
+ closes, and ``False`` if there's an expiry date. Use
+ ``get_expiry_date()`` or ``get_expiry_age()`` to find the actual expiry
+ date/age, if there is one.
+ """
+ if self.get('_session_expiry') is None:
+ return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
+ return self.get('_session_expiry') == 0
+
+ def flush(self):
+ """
+ Removes the current session data from the database and regenerates the
+ key.
+ """
+ self.clear()
+ self.delete()
+ self.create()
+
+ def cycle_key(self):
+ """
+ Creates a new session key, whilst retaining the current session data.
+ """
+ data = self._session_cache
+ key = self.session_key
+ self.create()
+ self._session_cache = data
+ self.delete(key)
+
+ # Methods that child classes must implement.
+
+ def exists(self, session_key):
+ """
+ Returns True if the given session_key already exists.
+ """
+ raise NotImplementedError
+
+ def create(self):
+ """
+ Creates a new session instance. Guaranteed to create a new object with
+ a unique key and will have saved the result once (with empty data)
+ before the method returns.
+ """
+ raise NotImplementedError
+
+ def save(self, must_create=False):
+ """
+ Saves the session data. If 'must_create' is True, a new session object
+ is created (otherwise a CreateError exception is raised). Otherwise,
+ save() can update an existing object with the same key.
+ """
+ raise NotImplementedError
+
+ def delete(self, session_key=None):
+ """
+ Deletes the session data under this key. If the key is None, the
+ current session key value is used.
+ """
+ raise NotImplementedError
+
+ def load(self):
+ """
+ Loads the session data and returns a dictionary.
+ """
+ raise NotImplementedError