mirror of
				https://github.com/django/django.git
				synced 2025-10-26 07:06:08 +00:00 
			
		
		
		
	Fixed #20557 -- Properly decoded non-ASCII cookies on Python 3.
Thanks mitsuhiko for the report. Non-ASCII values are supported. Non-ASCII keys still aren't, because the current parser mangles them. That's another bug.
This commit is contained in:
		| @@ -136,7 +136,8 @@ class WSGIRequest(http.HttpRequest): | |||||||
|     def _get_get(self): |     def _get_get(self): | ||||||
|         if not hasattr(self, '_get'): |         if not hasattr(self, '_get'): | ||||||
|             # The WSGI spec says 'QUERY_STRING' may be absent. |             # The WSGI spec says 'QUERY_STRING' may be absent. | ||||||
|             self._get = http.QueryDict(self.environ.get('QUERY_STRING', ''), encoding=self._encoding) |             raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '') | ||||||
|  |             self._get = http.QueryDict(raw_query_string, encoding=self._encoding) | ||||||
|         return self._get |         return self._get | ||||||
|  |  | ||||||
|     def _set_get(self, get): |     def _set_get(self, get): | ||||||
| @@ -152,7 +153,8 @@ class WSGIRequest(http.HttpRequest): | |||||||
|  |  | ||||||
|     def _get_cookies(self): |     def _get_cookies(self): | ||||||
|         if not hasattr(self, '_cookies'): |         if not hasattr(self, '_cookies'): | ||||||
|             self._cookies = http.parse_cookie(self.environ.get('HTTP_COOKIE', '')) |             raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '') | ||||||
|  |             self._cookies = http.parse_cookie(raw_cookie) | ||||||
|         return self._cookies |         return self._cookies | ||||||
|  |  | ||||||
|     def _set_cookies(self, cookies): |     def _set_cookies(self, cookies): | ||||||
| @@ -265,3 +267,15 @@ def get_bytes_from_wsgi(environ, key, default): | |||||||
|     # decoded with ISO-8859-1. This is wrong for Django websites where UTF-8 |     # decoded with ISO-8859-1. This is wrong for Django websites where UTF-8 | ||||||
|     # is the default. Re-encode to recover the original bytestring. |     # is the default. Re-encode to recover the original bytestring. | ||||||
|     return value if six.PY2 else value.encode(ISO_8859_1) |     return value if six.PY2 else value.encode(ISO_8859_1) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_str_from_wsgi(environ, key, default): | ||||||
|  |     """ | ||||||
|  |     Get a value from the WSGI environ dictionary as bytes. | ||||||
|  |  | ||||||
|  |     key and default should be str objects. Under Python 2 they may also be | ||||||
|  |     unicode objects provided they only contain ASCII characters. | ||||||
|  |     """ | ||||||
|  |     value = environ.get(str(key), str(default)) | ||||||
|  |     # Same comment as above | ||||||
|  |     return value if six.PY2 else value.encode(ISO_8859_1).decode(UTF_8) | ||||||
|   | |||||||
| @@ -1,8 +1,11 @@ | |||||||
| from django.core.handlers.wsgi import WSGIHandler | from __future__ import unicode_literals | ||||||
|  |  | ||||||
|  | from django.core.handlers.wsgi import WSGIHandler, WSGIRequest | ||||||
| from django.core.signals import request_started, request_finished | from django.core.signals import request_started, request_finished | ||||||
| from django.db import close_old_connections, connection | from django.db import close_old_connections, connection | ||||||
| from django.test import RequestFactory, TestCase, TransactionTestCase | from django.test import RequestFactory, TestCase, TransactionTestCase | ||||||
| from django.test.utils import override_settings | from django.test.utils import override_settings | ||||||
|  | from django.utils import six | ||||||
|  |  | ||||||
|  |  | ||||||
| class HandlerTests(TestCase): | class HandlerTests(TestCase): | ||||||
| @@ -30,11 +33,19 @@ class HandlerTests(TestCase): | |||||||
|     def test_bad_path_info(self): |     def test_bad_path_info(self): | ||||||
|         """Tests for bug #15672 ('request' referenced before assignment)""" |         """Tests for bug #15672 ('request' referenced before assignment)""" | ||||||
|         environ = RequestFactory().get('/').environ |         environ = RequestFactory().get('/').environ | ||||||
|         environ['PATH_INFO'] = '\xed' |         environ['PATH_INFO'] = b'\xed' if six.PY2 else '\xed' | ||||||
|         handler = WSGIHandler() |         handler = WSGIHandler() | ||||||
|         response = handler(environ, lambda *a, **k: None) |         response = handler(environ, lambda *a, **k: None) | ||||||
|         self.assertEqual(response.status_code, 400) |         self.assertEqual(response.status_code, 400) | ||||||
|  |  | ||||||
|  |     def test_non_ascii_cookie(self): | ||||||
|  |         """Test that non-ASCII cookies set in JavaScript are properly decoded (#20557).""" | ||||||
|  |         environ = RequestFactory().get('/').environ | ||||||
|  |         raw_cookie = 'want="café"'.encode('utf-8') | ||||||
|  |         environ['HTTP_COOKIE'] = raw_cookie if six.PY2 else raw_cookie.decode('iso-8859-1') | ||||||
|  |         request = WSGIRequest(environ) | ||||||
|  |         self.assertEqual(request.COOKIES['want'], "café") | ||||||
|  |  | ||||||
|  |  | ||||||
| class TransactionsPerRequestTests(TransactionTestCase): | class TransactionsPerRequestTests(TransactionTestCase): | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user