Commits

Anonymous committed 603af28

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.

  • Participants
  • Parent commits ed8b270

Comments (0)

Files changed (5)

File django/contrib/sessions/backends/base.py

 
     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()

File django/contrib/sessions/backends/cache.py

             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
 

File django/contrib/sessions/backends/db.py

         """
         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()

File django/contrib/sessions/backends/file.py

             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:

File django/contrib/sessions/tests.py

 >>> 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
 >>> 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
 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"
 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