Browse Source

Refs #27795 -- Removed force_bytes() usage from django/utils/http.py.

django.utils.http.urlsafe_base64_encode() now returns a string, not a
bytestring. Since URLs are represented as strings,
urlsafe_base64_encode() should return a string. All uses immediately
decoded the bytestring to a string anyway.

As the inverse operation, urlsafe_base64_decode() accepts a string.
Jon Dufresne 6 years ago
parent
commit
c82893cb8c

+ 1 - 1
django/contrib/auth/forms.py

@@ -284,7 +284,7 @@ class PasswordResetForm(forms.Form):
                 'email': email,
                 'domain': domain,
                 'site_name': site_name,
-                'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
+                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                 'user': user,
                 'token': token_generator.make_token(user),
                 'protocol': 'https' if use_https else 'http',

+ 4 - 5
django/utils/http.py

@@ -15,7 +15,6 @@ from urllib.parse import (
 from django.core.exceptions import TooManyFieldsSent
 from django.utils.datastructures import MultiValueDict
 from django.utils.deprecation import RemovedInDjango30Warning
-from django.utils.encoding import force_bytes
 from django.utils.functional import keep_lazy_text
 
 # based on RFC 7232, Appendix C
@@ -220,10 +219,10 @@ def int_to_base36(i):
 
 def urlsafe_base64_encode(s):
     """
-    Encode a bytestring in base64 for use in URLs. Strip any trailing equal
-    signs.
+    Encode a bytestring to a base64 string for use in URLs. Strip any trailing
+    equal signs.
     """
-    return base64.urlsafe_b64encode(s).rstrip(b'\n=')
+    return base64.urlsafe_b64encode(s).rstrip(b'\n=').decode('ascii')
 
 
 def urlsafe_base64_decode(s):
@@ -231,7 +230,7 @@ def urlsafe_base64_decode(s):
     Decode a base64 encoded string. Add back any trailing equal signs that
     might have been stripped.
     """
-    s = force_bytes(s)
+    s = s.encode()
     try:
         return base64.urlsafe_b64decode(s.ljust(len(s) + len(s) % 4, b'='))
     except (LookupError, BinasciiError) as e:

+ 10 - 2
docs/ref/utils.txt

@@ -726,14 +726,22 @@ escaping HTML.
 
 .. function:: urlsafe_base64_encode(s)
 
-    Encodes a bytestring in base64 for use in URLs, stripping any trailing
-    equal signs.
+    Encodes a bytestring to a base64 string for use in URLs, stripping any
+    trailing equal signs.
+
+    .. versionchanged:: 2.2
+
+        In older versions, it returns a bytestring instead of a string.
 
 .. function::  urlsafe_base64_decode(s)
 
     Decodes a base64 encoded string, adding back any trailing equal signs that
     might have been stripped.
 
+    .. versionchanged:: 2.2
+
+        In older versions, ``s`` may be a bytestring.
+
 ``django.utils.module_loading``
 ===============================
 

+ 4 - 0
docs/releases/2.2.txt

@@ -298,6 +298,10 @@ Miscellaneous
 
 * Support for bytestring paths in the template filesystem loader is removed.
 
+* :func:`django.utils.http.urlsafe_base64_encode` now returns a string instead
+  of a bytestring, and :func:`django.utils.http.urlsafe_base64_decode` may no
+  longer be passed a bytestring.
+
 .. _deprecated-features-2.2:
 
 Features deprecated in 2.2

+ 1 - 1
tests/auth_tests/test_templates.py

@@ -47,7 +47,7 @@ class AuthTemplateTests(TestCase):
         client = PasswordResetConfirmClient()
         default_token_generator = PasswordResetTokenGenerator()
         token = default_token_generator.make_token(self.user)
-        uidb64 = urlsafe_base64_encode(str(self.user.pk).encode()).decode()
+        uidb64 = urlsafe_base64_encode(str(self.user.pk).encode())
         url = reverse('password_reset_confirm', kwargs={'uidb64': uidb64, 'token': token})
         response = client.get(url)
         self.assertContains(response, '<title>Enter new password</title>')

+ 1 - 1
tests/auth_tests/test_views.py

@@ -424,7 +424,7 @@ class UUIDUserPasswordResetTest(CustomUserPasswordResetTest):
     def test_confirm_invalid_uuid(self):
         """A uidb64 that decodes to a non-UUID doesn't crash."""
         _, path = self._test_confirm_start()
-        invalid_uidb64 = urlsafe_base64_encode('INVALID_UUID'.encode()).decode()
+        invalid_uidb64 = urlsafe_base64_encode('INVALID_UUID'.encode())
         first, _uuidb64_, second = path.strip('/').split('/')
         response = self.client.get('/' + '/'.join((first, invalid_uidb64, second)) + '/')
         self.assertContains(response, 'The password reset link was invalid')