mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +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 | from __future__ import unicode_literals | ||||||
|  | import sys | ||||||
|  |  | ||||||
| from django.utils.encoding import force_str | from django.utils.encoding import force_str | ||||||
| from django.utils import six | from django.utils import six | ||||||
| @@ -15,12 +16,29 @@ try: | |||||||
| except http_cookies.CookieError: | except http_cookies.CookieError: | ||||||
|     _cookie_allows_colon_in_names = False |     _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 |     SimpleCookie = http_cookies.SimpleCookie | ||||||
| else: | else: | ||||||
|     Morsel = http_cookies.Morsel |     Morsel = http_cookies.Morsel | ||||||
|  |  | ||||||
|     class SimpleCookie(http_cookies.SimpleCookie): |     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: |         if not _cookie_encodes_correctly: | ||||||
|             def value_encode(self, val): |             def value_encode(self, val): | ||||||
|                 # Some browsers do not support quoted-string from RFC 2109, |                 # Some browsers do not support quoted-string from RFC 2109, | ||||||
|   | |||||||
| @@ -206,17 +206,6 @@ class HttpResponseBase(six.Iterator): | |||||||
|     def __getitem__(self, header): |     def __getitem__(self, header): | ||||||
|         return self._headers[header.lower()][1] |         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): |     def has_header(self, header): | ||||||
|         """Case-insensitive check for a header.""" |         """Case-insensitive check for a header.""" | ||||||
|         return header.lower() in self._headers |         return header.lower() in self._headers | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ class SimpleTemplateResponse(HttpResponse): | |||||||
|         rendered, and that the pickled state only includes rendered |         rendered, and that the pickled state only includes rendered | ||||||
|         data, not the data used to construct the response. |         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: |         if not self._is_rendered: | ||||||
|             raise ContentNotRenderedError('The response content must be ' |             raise ContentNotRenderedError('The response content must be ' | ||||||
|                                           'rendered before it can be pickled.') |                                           'rendered before it can be pickled.') | ||||||
|   | |||||||
| @@ -631,7 +631,7 @@ class CookieTests(unittest.TestCase): | |||||||
|         c = SimpleCookie() |         c = SimpleCookie() | ||||||
|         c['test'] = "An,awkward;value" |         c['test'] = "An,awkward;value" | ||||||
|         c2 = SimpleCookie() |         c2 = SimpleCookie() | ||||||
|         c2.load(c.output()) |         c2.load(c.output()[12:]) | ||||||
|         self.assertEqual(c['test'].value, c2['test'].value) |         self.assertEqual(c['test'].value, c2['test'].value) | ||||||
|  |  | ||||||
|     def test_decode_2(self): |     def test_decode_2(self): | ||||||
| @@ -641,7 +641,7 @@ class CookieTests(unittest.TestCase): | |||||||
|         c = SimpleCookie() |         c = SimpleCookie() | ||||||
|         c['test'] = b"\xf0" |         c['test'] = b"\xf0" | ||||||
|         c2 = SimpleCookie() |         c2 = SimpleCookie() | ||||||
|         c2.load(c.output()) |         c2.load(c.output()[12:]) | ||||||
|         self.assertEqual(c['test'].value, c2['test'].value) |         self.assertEqual(c['test'].value, c2['test'].value) | ||||||
|  |  | ||||||
|     def test_nonstandard_keys(self): |     def test_nonstandard_keys(self): | ||||||
| @@ -678,3 +678,15 @@ class CookieTests(unittest.TestCase): | |||||||
|         r = HttpResponse() |         r = HttpResponse() | ||||||
|         r.set_cookie("a:.b/", 1) |         r.set_cookie("a:.b/", 1) | ||||||
|         self.assertEqual(len(r.cookies.bad_cookies), 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