mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #23730 -- Moved support for SimpleCookie HIGHEST_PROTOCOL pickling to http.cookie.
This fix is necessary for Python 3.5 compatibility (refs #23763). Thanks Berker Peksag for review.
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| from __future__ import unicode_literals | ||||
| import sys | ||||
|  | ||||
| from django.utils.encoding import force_str | ||||
| from django.utils import six | ||||
| @@ -15,12 +16,29 @@ try: | ||||
| except http_cookies.CookieError: | ||||
|     _cookie_allows_colon_in_names = False | ||||
|  | ||||
| if _cookie_encodes_correctly and _cookie_allows_colon_in_names: | ||||
| # Cookie pickling bug is fixed in Python 2.7.9 and Python 3.4.3+ | ||||
| # http://bugs.python.org/issue22775 | ||||
| cookie_pickles_properly = ( | ||||
|     (sys.version_info[:2] == (2, 7) and sys.version_info >= (2, 7, 9)) or | ||||
|     sys.version_info >= (3, 4, 3) | ||||
| ) | ||||
|  | ||||
| if _cookie_encodes_correctly and _cookie_allows_colon_in_names and cookie_pickles_properly: | ||||
|     SimpleCookie = http_cookies.SimpleCookie | ||||
| else: | ||||
|     Morsel = http_cookies.Morsel | ||||
|  | ||||
|     class SimpleCookie(http_cookies.SimpleCookie): | ||||
|         if not cookie_pickles_properly: | ||||
|             def __setitem__(self, key, value): | ||||
|                 # Apply the fix from http://bugs.python.org/issue22775 where | ||||
|                 # it's not fixed in Python itself | ||||
|                 if isinstance(value, Morsel): | ||||
|                     # allow assignment of constructed Morsels (e.g. for pickling) | ||||
|                     dict.__setitem__(self, key, value) | ||||
|                 else: | ||||
|                     super(SimpleCookie, self).__setitem__(key, value) | ||||
|  | ||||
|         if not _cookie_encodes_correctly: | ||||
|             def value_encode(self, val): | ||||
|                 # Some browsers do not support quoted-string from RFC 2109, | ||||
|   | ||||
| @@ -206,17 +206,6 @@ class HttpResponseBase(six.Iterator): | ||||
|     def __getitem__(self, header): | ||||
|         return self._headers[header.lower()][1] | ||||
|  | ||||
|     def __getstate__(self): | ||||
|         # SimpleCookie is not pickleable with pickle.HIGHEST_PROTOCOL, so we | ||||
|         # serialize 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 | ||||
|   | ||||
| @@ -39,7 +39,7 @@ class SimpleTemplateResponse(HttpResponse): | ||||
|         rendered, and that the pickled state only includes rendered | ||||
|         data, not the data used to construct the response. | ||||
|         """ | ||||
|         obj_dict = super(SimpleTemplateResponse, self).__getstate__() | ||||
|         obj_dict = self.__dict__.copy() | ||||
|         if not self._is_rendered: | ||||
|             raise ContentNotRenderedError('The response content must be ' | ||||
|                                           'rendered before it can be pickled.') | ||||
|   | ||||
| @@ -631,7 +631,7 @@ class CookieTests(unittest.TestCase): | ||||
|         c = SimpleCookie() | ||||
|         c['test'] = "An,awkward;value" | ||||
|         c2 = SimpleCookie() | ||||
|         c2.load(c.output()) | ||||
|         c2.load(c.output()[12:]) | ||||
|         self.assertEqual(c['test'].value, c2['test'].value) | ||||
|  | ||||
|     def test_decode_2(self): | ||||
| @@ -641,7 +641,7 @@ class CookieTests(unittest.TestCase): | ||||
|         c = SimpleCookie() | ||||
|         c['test'] = b"\xf0" | ||||
|         c2 = SimpleCookie() | ||||
|         c2.load(c.output()) | ||||
|         c2.load(c.output()[12:]) | ||||
|         self.assertEqual(c['test'].value, c2['test'].value) | ||||
|  | ||||
|     def test_nonstandard_keys(self): | ||||
| @@ -678,3 +678,15 @@ class CookieTests(unittest.TestCase): | ||||
|         r = HttpResponse() | ||||
|         r.set_cookie("a:.b/", 1) | ||||
|         self.assertEqual(len(r.cookies.bad_cookies), 1) | ||||
|  | ||||
|     def test_pickle(self): | ||||
|         rawdata = 'Customer="WILE_E_COYOTE"; Path=/acme; Version=1' | ||||
|         expected_output = 'Set-Cookie: %s' % rawdata | ||||
|  | ||||
|         C = SimpleCookie() | ||||
|         C.load(rawdata) | ||||
|         self.assertEqual(C.output(), expected_output) | ||||
|  | ||||
|         for proto in range(pickle.HIGHEST_PROTOCOL + 1): | ||||
|             C1 = pickle.loads(pickle.dumps(C, protocol=proto)) | ||||
|             self.assertEqual(C1.output(), expected_output) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user