Index: django/contrib/newsessions/middleware.py
===================================================================
--- django/contrib/newsessions/middleware.py    (revision 0)
+++ django/contrib/newsessions/middleware.py    (revision 0)
@@ -0,0 +1,95 @@
+from django.conf import settings
+from django.contrib.newsessions.models import Session
+from django.core.exceptions import SuspiciousOperation
+from django.utils.cache import patch_vary_headers
+import datetime
+
+TEST_COOKIE_NAME = 'testcookie'
+TEST_COOKIE_VALUE = 'worked'
+
+class SessionWrapper(object):
+    def __init__(self, session_key, remote_addr):
+        self.session_key = session_key
+        self._pk = None
+        self.modified = False
+        self.remote_addr = remote_addr
+
+    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 set_test_cookie(self):
+        self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE
+
+    def test_cookie_worked(self):
+        return self.get(TEST_COOKIE_NAME) == TEST_COOKIE_VALUE
+
+    def delete_test_cookie(self):
+        del self[TEST_COOKIE_NAME]
+
+    def _get_session(self):
+        # Lazily loads session from storage.
+        try:
+            return self._session_cache
+        except AttributeError:
+            if self.session_key is None:
+                s = Session.objects.get_new_session(self.remote_addr)
+            else:
+                try:
+                    s = Session.objects.get(session_key=self.session_key, expire_date__gt=datetime.datetime.now(), remote_addr=self.remote_addr)
+                except (Session.DoesNotExist, SuspiciousOperation):
+                    s = Session.objects.get_new_session(self.remote_addr)
+            self.session_key = s.session_key
+            self._session_cache = s.get_decoded()
+            self._pk = s.id
+            return self._session_cache
+
+    _session = property(_get_session)
+
+class SessionMiddleware(object):
+    def process_request(self, request):
+        request.session = SessionWrapper(request.COOKIES.get(settings.SESSION_COOKIE_NAME, None), request.META['REMOTE_ADDR'])
+
+    def process_response(self, request, response):
+        # If request.session was modified, or if response.session was set, save
+        # those changes and set a session cookie.
+        patch_vary_headers(response, ('Cookie',))
+        try:
+            modified = request.session.modified
+        except AttributeError:
+            pass
+        else:
+            if modified or settings.SESSION_SAVE_EVERY_REQUEST:
+                if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
+                    max_age = None
+                    expires = None
+                else:
+                    max_age = settings.SESSION_COOKIE_AGE
+                    expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
+                if not request.session._pk:
+                    request.session._session
+                new_session = Session.objects.save(request.session._pk, request.session.session_key, request.session._session,
+                    datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), request.META['REMOTE_ADDR'])
+                response.set_cookie(settings.SESSION_COOKIE_NAME, request.session.session_key,
+                    max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
+                    secure=settings.SESSION_COOKIE_SECURE or None)
+        return response
Index: django/contrib/newsessions/__init__.py
===================================================================
Index: django/contrib/newsessions/models.py
===================================================================
--- django/contrib/newsessions/models.py        (revision 0)
+++ django/contrib/newsessions/models.py        (revision 0)
@@ -0,0 +1,72 @@
+import base64, md5, random, sys
+import cPickle as pickle
+from django.db import models
+from django.utils.translation import gettext_lazy as _
+from django.conf import settings
+import datetime
+
+class SessionManager(models.Manager):
+    def encode(self, session_dict):
+        "Returns the given session dictionary pickled and encoded as a string."
+        pickled = pickle.dumps(session_dict)
+        pickled_md5 = md5.new(pickled + settings.SECRET_KEY).hexdigest()
+        return base64.encodestring(pickled + pickled_md5)
+
+    def get_new_session(self, remote_addr):
+        "Returns session key that isn't being used."
+        # The random module is seeded when this Apache child is created.
+        # Use person_id and SECRET_KEY as added salt.
+        while 1:
+            session_key = md5.new(str(random.randint(0, sys.maxint - 1)) + str(random.randint(0, sys.maxint - 1)) + settings.SECRET_KEY).hexdigest()
+            try:
+                return self.save(None, session_key, {}, datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), remote_addr)
+            except:
+                pass
+
+    def save(self, id, session_key, session_dict, expire_date, remote_addr):
+        s = self.model(id, session_key, self.encode(session_dict), expire_date, remote_addr)
+        if session_dict or not id:
+            s.save()
+        else:
+            s.delete() # Clear sessions with no data.
+        return s
+
+class Session(models.Model):
+    """
+    Django provides full support for anonymous sessions. The session
+    framework lets you store and retrieve arbitrary data on a
+    per-site-visitor basis. It stores data on the server side and
+    abstracts the sending and receiving of cookies. Cookies contain a
+    session ID -- not the data itself.
+
+    The Django sessions framework is entirely cookie-based. It does
+    not fall back to putting session IDs in URLs. This is an intentional
+    design decision. Not only does that behavior make URLs ugly, it makes
+    your site vulnerable to session-ID theft via the "Referer" header.
+
+    For complete documentation on using Sessions in your code, consult
+    the sessions documentation that is shipped with Django (also available
+    on the Django website).
+    """
+    session_key = models.CharField(_('session key'), maxlength=40, unique=True)
+    session_data = models.TextField(_('session data'))
+    expire_date = models.DateTimeField(_('expire date'))
+    remote_addr = models.IPAddressField(_('ip address'))
+    objects = SessionManager()
+    class Meta:
+        db_table = 'django_newsession'
+        verbose_name = _('session')
+        verbose_name_plural = _('sessions')
+
+    def get_decoded(self):
+        encoded_data = base64.decodestring(self.session_data)
+        pickled, tamper_check = encoded_data[:-32], encoded_data[-32:]
+        if md5.new(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
+            from django.core.exceptions import SuspiciousOperation
+            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 {}
