Commits

Luke Plant committed 2152548

Fixed #15863 - SimpleCookies are not correctly serialized with the file or database cache backends

Thanks to rakuco for the report and for the tests.

Comments (0)

Files changed (2)

django/http/__init__.py

     def __getitem__(self, header):
         return self._headers[header.lower()][1]
 
+    def __getstate__(self):
+        # SimpleCookie is not pickeable with pickle.HIGHEST_PROTOCOL, so we
+        # serialise to a string instead
+        state = self.__dict__.copy()
+        state['cookies'] = str(state['cookies'])
+        return state
+
+    def __setstate__(self, state):
+        self.__dict__.update(state)
+        self.cookies = SimpleCookie(self.cookies)
+
     def has_header(self, header):
         """Case-insensitive check for a header."""
         return header.lower() in self._headers

tests/regressiontests/cache/tests.py

 class BaseCacheTests(object):
     # A common set of tests to apply to all cache backends
 
+    def _get_request_cache(self, path):
+        request = HttpRequest()
+        request.META = {
+            'SERVER_NAME': 'testserver',
+            'SERVER_PORT': 80,
+        }
+        request.path = request.path_info = path
+        request._cache_update_cache = True
+        request.method = 'GET'
+        return request
+
     def test_simple(self):
         # Simple cache set/get works
         self.cache.set("key", "value")
         self.assertEqual(self.custom_key_cache2.get('answer2'), 42)
 
 
+    def test_cache_write_unpickable_object(self):
+        update_middleware = UpdateCacheMiddleware()
+        update_middleware.cache = self.cache
+
+        fetch_middleware = FetchFromCacheMiddleware()
+        fetch_middleware.cache = self.cache
+
+        request = self._get_request_cache('/cache/test')
+        get_cache_data = FetchFromCacheMiddleware().process_request(request)
+        self.assertEqual(get_cache_data, None)
+
+        response = HttpResponse()
+        content = 'Testing cookie serialization.'
+        response.content = content
+        response.set_cookie('foo', 'bar')
+
+        update_middleware.process_response(request, response)
+
+        get_cache_data = fetch_middleware.process_request(request)
+        self.assertNotEqual(get_cache_data, None)
+        self.assertEqual(get_cache_data.content, content)
+        self.assertEqual(get_cache_data.cookies, response.cookies)
+
+        update_middleware.process_response(request, get_cache_data)
+        get_cache_data = fetch_middleware.process_request(request)
+        self.assertNotEqual(get_cache_data, None)
+        self.assertEqual(get_cache_data.content, content)
+        self.assertEqual(get_cache_data.cookies, response.cookies)
+
 def custom_key_func(key, key_prefix, version):
     "A customized cache key function"
     return 'CUSTOM-' + '-'.join([key_prefix, str(version), key])