Commits

mtre...@bcc190cf-cafb-0310-a4f2-bffc1f526a37  committed 0ab7259

Reduced the chances of session object collision. The window of opportunity is
now about five Python instructions in get_or_create(). This doesn't guarantee
no collisions, but should fix many occurrences. Refs #1180.

  • Participants
  • Parent commits 69d7bed

Comments (0)

Files changed (2)

File django/contrib/sessions/middleware.py

             if accessed:
                 patch_vary_headers(response, ('Cookie',))
             if modified or settings.SESSION_SAVE_EVERY_REQUEST:
-                session_key = request.session.session_key or Session.objects.get_new_session_key()
+                if request.session.session_key:
+                    session_key = request.session.session_key
+                else:
+                    obj = Session.objects.get_new_session_object()
+                    session_key = obj.session_key
+
                 if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
                     max_age = None
                     expires = None

File django/contrib/sessions/models.py

-import base64, md5, random, sys
+import base64, md5, random, sys, datetime
 import cPickle as pickle
 from django.db import models
 from django.utils.translation import gettext_lazy as _
                 break
         return session_key
 
+    def get_new_session_object(self):
+        """
+        Returns a new session object.
+        """
+        # FIXME: There is a *small* chance of collision here, meaning we will
+        # return an existing object. That can be fixed when we add a way to
+        # validate (and guarantee) that non-auto primary keys are unique. For
+        # now, we save immediately in order to reduce the "window of
+        # misfortune" as much as possible.
+        created = False
+        while not created:
+            obj, created = self.get_or_create(session_key=self.get_new_session_key(),
+                    expire_date = datetime.datetime.now())
+            # Collision in key generation, so re-seed the generator
+            random.seed()
+        return obj
+
     def save(self, session_key, session_dict, expire_date):
         s = self.model(session_key, self.encode(session_dict), expire_date)
         if session_dict: