diff --git a/django/utils/http.py b/django/utils/http.py index 27d445d46f..67414d93f6 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -10,7 +10,7 @@ from binascii import Error as BinasciiError from email.utils import formatdate from django.utils.datastructures import MultiValueDict -from django.utils.encoding import force_str, force_text +from django.utils.encoding import force_bytes, force_str, force_text from django.utils.functional import allow_lazy from django.utils import six from django.utils.six.moves.urllib.parse import ( @@ -224,7 +224,7 @@ def urlsafe_base64_decode(s): Decodes a base64 encoded string, adding back any trailing equal signs that might have been stripped. """ - s = s.encode('utf-8') # base64encode should only return ASCII. + s = force_bytes(s) try: return base64.urlsafe_b64decode(s.ljust(len(s) + len(s) % 4, b'=')) except (LookupError, BinasciiError) as e: diff --git a/docs/releases/1.7.1.txt b/docs/releases/1.7.1.txt index 6511074542..01edc4c8f5 100644 --- a/docs/releases/1.7.1.txt +++ b/docs/releases/1.7.1.txt @@ -103,3 +103,6 @@ Bugfixes * Fixed missing ``get_or_create`` and ``update_or_create`` on related managers causing ``IntegrityError`` (:ticket:`23611`). + +* Made :func:`~django.utils.http.urlsafe_base64_decode` return the proper + type (byte string) on Python 3 (:ticket:`23333`). diff --git a/tests/utils_tests/test_http.py b/tests/utils_tests/test_http.py index 3f512ad80b..db24d1c9f2 100644 --- a/tests/utils_tests/test_http.py +++ b/tests/utils_tests/test_http.py @@ -119,6 +119,12 @@ class TestUtilsHttp(unittest.TestCase): '/url%20with%20spaces/'): self.assertTrue(http.is_safe_url(good_url, host='testserver'), "%s should be allowed" % good_url) + def test_urlsafe_base64_roundtrip(self): + bytestring = b'foo' + encoded = http.urlsafe_base64_encode(bytestring) + decoded = http.urlsafe_base64_decode(encoded) + self.assertEqual(bytestring, decoded) + class ETagProcessingTests(unittest.TestCase): def test_parsing(self):