summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul McMillan <Paul@McMillan.ws>2012-03-23 05:31:11 +0000
committerPaul McMillan <Paul@McMillan.ws>2012-03-23 05:31:11 +0000
commit2ca980195653a754a1c4726f5bb253147c6cb329 (patch)
tree87a236a3caa99a6198ae1a91e7bf3c6212a9fe9e
parent38061221c341bde559a5935bed3b78468b28d657 (diff)
downloaddjango-2ca980195653a754a1c4726f5bb253147c6cb329.tar.gz
Fixed #17810. Catch session key errors.
Catches memcached session key errors related to overly long session keys. This is a long-standing bug, but severity was exacerbated by the addition of cookie-backed session storage, which generates long session values. If an installation switched from cookie-backed session store to memcached, users would not be able to log in because of the server error from overly long memcached keys. git-svn-id: http://code.djangoproject.com/svn/django/trunk@17795 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/contrib/sessions/backends/cache.py8
-rw-r--r--django/contrib/sessions/backends/cached_db.py8
-rw-r--r--django/contrib/sessions/tests.py30
3 files changed, 39 insertions, 7 deletions
diff --git a/django/contrib/sessions/backends/cache.py b/django/contrib/sessions/backends/cache.py
index ea9e926cfa..ac6647e110 100644
--- a/django/contrib/sessions/backends/cache.py
+++ b/django/contrib/sessions/backends/cache.py
@@ -16,7 +16,13 @@ class SessionStore(SessionBase):
return KEY_PREFIX + self._get_or_create_session_key()
def load(self):
- session_data = self._cache.get(self.cache_key)
+ try:
+ session_data = self._cache.get(self.cache_key, None)
+ except Exception as e:
+ e_type = str(type(e))
+ if e_type != "<class 'memcache.MemcachedKeyLengthError'>":
+ raise e
+ session_data = None
if session_data is not None:
return session_data
self.create()
diff --git a/django/contrib/sessions/backends/cached_db.py b/django/contrib/sessions/backends/cached_db.py
index 342aa600d3..20804c85f6 100644
--- a/django/contrib/sessions/backends/cached_db.py
+++ b/django/contrib/sessions/backends/cached_db.py
@@ -21,7 +21,13 @@ class SessionStore(DBStore):
return KEY_PREFIX + self._get_or_create_session_key()
def load(self):
- data = cache.get(self.cache_key, None)
+ try:
+ data = cache.get(self.cache_key, None)
+ except Exception as e:
+ e_type = str(type(e))
+ if e_type != "<class 'memcache.MemcachedKeyLengthError'>":
+ raise e
+ data = None
if data is None:
data = super(SessionStore, self).load()
cache.set(self.cache_key, data, settings.SESSION_COOKIE_AGE)
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index 3886c34512..7686bd254e 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -2,7 +2,9 @@ from __future__ import with_statement
from datetime import datetime, timedelta
import shutil
+import string
import tempfile
+import warnings
from django.conf import settings
from django.contrib.sessions.backends.db import SessionStore as DatabaseSession
@@ -12,10 +14,11 @@ from django.contrib.sessions.backends.file import SessionStore as FileSession
from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession
from django.contrib.sessions.models import Session
from django.contrib.sessions.middleware import SessionMiddleware
+from django.core.cache.backends.base import CacheKeyWarning
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.http import HttpResponse
from django.test import TestCase, RequestFactory
-from django.test.utils import override_settings
+from django.test.utils import override_settings, get_warnings_state, restore_warnings_state
from django.utils import timezone
from django.utils import unittest
@@ -25,7 +28,7 @@ class SessionTestsMixin(object):
# class, which wouldn't work, and to allow different TestCase subclasses to
# be used.
- backend = None # subclasses must specify
+ backend = None # subclasses must specify
def setUp(self):
self.session = self.backend()
@@ -119,13 +122,13 @@ class SessionTestsMixin(object):
self.assertTrue(hasattr(i, '__iter__'))
self.assertTrue(self.session.accessed)
self.assertFalse(self.session.modified)
- self.assertEqual(list(i), [('x',1)])
+ self.assertEqual(list(i), [('x', 1)])
def test_clear(self):
self.session['x'] = 1
self.session.modified = False
self.session.accessed = False
- self.assertEqual(self.session.items(), [('x',1)])
+ self.assertEqual(self.session.items(), [('x', 1)])
self.session.clear()
self.assertEqual(self.session.items(), [])
self.assertTrue(self.session.accessed)
@@ -280,7 +283,7 @@ class DatabaseSessionTests(SessionTestsMixin, TestCase):
s = Session.objects.get(session_key=self.session.session_key)
# Change it
- Session.objects.save(s.session_key, {'y':2}, s.expire_date)
+ Session.objects.save(s.session_key, {'y': 2}, s.expire_date)
# Clear cache, so that it will be retrieved from DB
del self.session._session_cache
self.assertEqual(self.session['y'], 2)
@@ -298,6 +301,14 @@ class CacheDBSessionTests(SessionTestsMixin, TestCase):
with self.assertNumQueries(0):
self.assertTrue(self.session.exists(self.session.session_key))
+ def test_load_overlong_key(self):
+ warnings_state = get_warnings_state()
+ warnings.filterwarnings('ignore',
+ category=CacheKeyWarning)
+ self.session._session_key = (string.ascii_letters + string.digits) * 20
+ self.assertEqual(self.session.load(), {})
+ restore_warnings_state(warnings_state)
+
CacheDBSessionWithTimeZoneTests = override_settings(USE_TZ=True)(CacheDBSessionTests)
@@ -339,6 +350,14 @@ class CacheSessionTests(SessionTestsMixin, unittest.TestCase):
backend = CacheSession
+ def test_load_overlong_key(self):
+ warnings_state = get_warnings_state()
+ warnings.filterwarnings('ignore',
+ category=CacheKeyWarning)
+ self.session._session_key = (string.ascii_letters + string.digits) * 20
+ self.assertEqual(self.session.load(), {})
+ restore_warnings_state(warnings_state)
+
class SessionMiddlewareTests(unittest.TestCase):
@@ -394,6 +413,7 @@ class SessionMiddlewareTests(unittest.TestCase):
self.assertNotIn('httponly',
str(response.cookies[settings.SESSION_COOKIE_NAME]))
+
class CookieSessionTests(SessionTestsMixin, TestCase):
backend = CookieSession