Commit a14f0872 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #21282 -- Made HttpResponse.serialize_headers accept latin-1

Thanks Raphaël Barrois for the report and the initial patch and
Aymeric Augustin for the review.
parent 50087063
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -123,8 +123,11 @@ class HttpResponseBase(six.Iterator):

    def serialize_headers(self):
        """HTTP headers as a bytestring."""
        def to_bytes(val, encoding):
            return val if isinstance(val, bytes) else val.encode(encoding)

        headers = [
            ('%s: %s' % (key, value)).encode('us-ascii')
            (b': '.join([to_bytes(key, 'ascii'), to_bytes(value, 'latin-1')]))
            for key, value in self._headers.values()
        ]
        return b'\r\n'.join(headers)
@@ -135,7 +138,7 @@ class HttpResponseBase(six.Iterator):
        __str__ = serialize_headers

    def _convert_to_charset(self, value, charset, mime_encode=False):
        """Converts headers key/value to ascii/latin1 native strings.
        """Converts headers key/value to ascii/latin-1 native strings.

        `charset` must be 'ascii' or 'latin-1'. If `mime_encode` is True and
        `value` value can't be represented in the given charset, MIME-encoding
@@ -171,7 +174,7 @@ class HttpResponseBase(six.Iterator):

    def __setitem__(self, header, value):
        header = self._convert_to_charset(header, 'ascii')
        value = self._convert_to_charset(value, 'latin1', mime_encode=True)
        value = self._convert_to_charset(value, 'latin-1', mime_encode=True)
        self._headers[header.lower()] = (header, value)

    def __delitem__(self, header):
+3 −0
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ class HttpResponseTests(unittest.TestCase):
        r['key'] = 'test'.encode('ascii')
        self.assertEqual(r['key'], str('test'))
        self.assertIsInstance(r['key'], str)
        self.assertIn(b'test', r.serialize_headers())

        # Latin-1 unicode or bytes values are also converted to native strings.
        r['key'] = 'café'
@@ -262,11 +263,13 @@ class HttpResponseTests(unittest.TestCase):
        r['key'] = 'café'.encode('latin-1')
        self.assertEqual(r['key'], smart_str('café', 'latin-1'))
        self.assertIsInstance(r['key'], str)
        self.assertIn('café'.encode('latin-1'), r.serialize_headers())

        # Other unicode values are MIME-encoded (there's no way to pass them as bytes).
        r['key'] = ''
        self.assertEqual(r['key'], str('=?utf-8?b?4oCg?='))
        self.assertIsInstance(r['key'], str)
        self.assertIn(b'=?utf-8?b?4oCg?=', r.serialize_headers())

        # The response also converts unicode or bytes keys to strings, but requires
        # them to contain ASCII