From 51f896fe25d0593abad2b3c55fd510c46ef57f05 Mon Sep 17 00:00:00 2001
From: Keryn Knight <keryn@kerynknight.com>
Date: Wed, 9 Feb 2022 16:01:03 +0000
Subject: [PATCH] Refs #33546 -- Optimized
 ResponseHeaders._convert_to_charset() by reducing the type-checking
 duplication.

In the common case, where keys and values are be encoded into
ascii/latin-1, defer the checking for newlines until it's been
successfully coerced to a string.

Co-authored-by: Nick Pope <nick@nickpope.me.uk>
---
 django/http/response.py | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/django/http/response.py b/django/http/response.py
index fb379f98a7..fae91b3f05 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -43,22 +43,32 @@ class ResponseHeaders(CaseInsensitiveMapping):
         `charset` must be 'ascii' or 'latin-1'. If `mime_encode` is True and
         `value` can't be represented in the given charset, apply MIME-encoding.
         """
-        if not isinstance(value, (bytes, str)):
-            value = str(value)
-        if (isinstance(value, bytes) and (b"\n" in value or b"\r" in value)) or (
-            isinstance(value, str) and ("\n" in value or "\r" in value)
-        ):
-            raise BadHeaderError(
-                "Header values can't contain newlines (got %r)" % value
-            )
         try:
             if isinstance(value, str):
                 # Ensure string is valid in given charset
                 value.encode(charset)
-            else:
+            elif isinstance(value, bytes):
                 # Convert bytestring using given charset
                 value = value.decode(charset)
+            else:
+                value = str(value)
+                # Ensure string is valid in given charset.
+                value.encode(charset)
+            if "\n" in value or "\r" in value:
+                raise BadHeaderError(
+                    f"Header values can't contain newlines (got {value!r})"
+                )
         except UnicodeError as e:
+            # Encoding to a string of the specified charset failed, but we
+            # don't know what type that value was, or if it contains newlines,
+            # which we may need to check for before sending it to be
+            # encoded for multiple character sets.
+            if (isinstance(value, bytes) and (b"\n" in value or b"\r" in value)) or (
+                isinstance(value, str) and ("\n" in value or "\r" in value)
+            ):
+                raise BadHeaderError(
+                    f"Header values can't contain newlines (got {value!r})"
+                ) from e
             if mime_encode:
                 value = Header(value, "utf-8", maxlinelen=sys.maxsize).encode()
             else: