From 9e423b51e325c9226e2f744bfa52336a626bf63a Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Thu, 14 Aug 2008 19:43:08 +0000 Subject: [PATCH] Fixed #8314 -- Fixed an infinite loop caused when submitting a session key (via a cookie) with no corresponding entry in the database. This only affected the database backend, but I've applied the same fix to all three backends for robustness. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8351 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/sessions/backends/base.py | 9 ++++++--- django/contrib/sessions/backends/cache.py | 3 ++- django/contrib/sessions/backends/db.py | 2 +- django/contrib/sessions/backends/file.py | 2 +- django/contrib/sessions/tests.py | 13 +++++++++++++ 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py index 9f4bf6f487..f64ef852cf 100644 --- a/django/contrib/sessions/backends/base.py +++ b/django/contrib/sessions/backends/base.py @@ -153,13 +153,16 @@ class SessionBase(object): session_key = property(_get_session_key, _set_session_key) - def _get_session(self): - # Lazily loads session from storage. + 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: + if self._session_key is None or no_load: self._session_cache = {} else: self._session_cache = self.load() diff --git a/django/contrib/sessions/backends/cache.py b/django/contrib/sessions/backends/cache.py index 2988d3ee09..157d18a586 100644 --- a/django/contrib/sessions/backends/cache.py +++ b/django/contrib/sessions/backends/cache.py @@ -30,7 +30,8 @@ class SessionStore(SessionBase): func = self._cache.add else: func = self._cache.set - result = func(self.session_key, self._session, self.get_expiry_age()) + result = func(self.session_key, self._get_session(no_load=must_create), + self.get_expiry_age()) if must_create and not result: raise CreateError diff --git a/django/contrib/sessions/backends/db.py b/django/contrib/sessions/backends/db.py index df9d64e7c4..e697bc56b1 100644 --- a/django/contrib/sessions/backends/db.py +++ b/django/contrib/sessions/backends/db.py @@ -49,7 +49,7 @@ class SessionStore(SessionBase): """ obj = Session( session_key = self.session_key, - session_data = self.encode(self._session), + session_data = self.encode(self._get_session(no_load=must_create)), expire_date = self.get_expiry_date() ) sid = transaction.savepoint() diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py index 7fb608df90..3438b097c4 100644 --- a/django/contrib/sessions/backends/file.py +++ b/django/contrib/sessions/backends/file.py @@ -73,7 +73,7 @@ class SessionStore(SessionBase): flags |= os.O_EXCL # Because this may trigger a load from storage, we must do it before # truncating the file to save. - session_data = self._session + session_data = self._get_session(no_load=must_create) try: fd = os.open(self._key_to_file(self.session_key), flags) try: diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py index ec4da2d543..9b88bed8d8 100644 --- a/django/contrib/sessions/tests.py +++ b/django/contrib/sessions/tests.py @@ -5,6 +5,7 @@ r""" >>> from django.contrib.sessions.backends.cache import SessionStore as CacheSession >>> from django.contrib.sessions.backends.file import SessionStore as FileSession >>> from django.contrib.sessions.backends.base import SessionBase +>>> from django.contrib.sessions.models import Session >>> db_session = DatabaseSession() >>> db_session.modified @@ -36,6 +37,12 @@ False >>> db_session.modified, db_session.accessed (True, True) +# Submitting an invalid session key (either by guessing, or if the db has +# removed the key) results in a new key being generated. +>>> Session.objects.filter(pk=db_session.session_key).delete() +>>> db_session = DatabaseSession(db_session.session_key) +>>> db_session.save() + >>> file_session = FileSession() >>> file_session.modified False @@ -65,6 +72,9 @@ False False >>> file_session.modified, file_session.accessed (True, True) +>>> Session.objects.filter(pk=file_session.session_key).delete() +>>> file_session = FileSession(file_session.session_key) +>>> file_session.save() # Make sure the file backend checks for a good storage dir >>> settings.SESSION_FILE_PATH = "/if/this/directory/exists/you/have/a/weird/computer" @@ -99,6 +109,9 @@ False False >>> cache_session.modified, cache_session.accessed (True, True) +>>> Session.objects.filter(pk=cache_session.session_key).delete() +>>> cache_session = CacheSession(cache_session.session_key) +>>> cache_session.save() >>> s = SessionBase() >>> s._session['some key'] = 'exists' # Pre-populate the session with some data