Commit 82b3e6ff authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Fixed #13222 -- Made HttpResponse iterable once

response.content can be accessed many times as desired, and always
returns the same result.

iter(response) works only once and consumes the iterator.
parent 495a8b81
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ class HttpResponse(HttpResponseBase):
                'deprecated. Use `StreamingHttpResponse` instead '
                'if you need the streaming behavior.',
                PendingDeprecationWarning, stacklevel=2)
        if not hasattr(self, '_iterator'):
            self._iterator = iter(self._container)
        return self

@@ -303,7 +304,7 @@ class HttpResponse(HttpResponseBase):

    def tell(self):
        self._consume_content()
        return sum(len(chunk) for chunk in self)
        return len(self.content)


class StreamingHttpResponse(HttpResponseBase):
+5 −1
Original line number Diff line number Diff line
@@ -596,7 +596,11 @@ class TransactionTestCase(SimpleTestCase):
            msg_prefix + "Couldn't retrieve content: Response code was %d"
            " (expected %d)" % (response.status_code, status_code))
        text = force_text(text, encoding=response._charset)
        content = b''.join(response).decode(response._charset)
        if response.streaming:
            content = b''.join(response.streaming_content)
        else:
            content = response.content
        content = content.decode(response._charset)
        # Avoid ResourceWarning about unclosed files.
        response.close()
        if html:
+22 −1
Original line number Diff line number Diff line
@@ -337,15 +337,36 @@ class HttpResponseTests(unittest.TestCase):
        self.assertRaises(UnicodeEncodeError,
                          getattr, r, 'content')

        # content can safely be accessed multiple times.
        # .content can safely be accessed multiple times.
        r = HttpResponse(iter(['hello', 'world']))
        self.assertEqual(r.content, r.content)
        self.assertEqual(r.content, b'helloworld')
        # accessing the iterator works (once) after accessing .content
        self.assertEqual(b''.join(r), b'helloworld')
        self.assertEqual(b''.join(r), b'')
        # accessing .content still works
        self.assertEqual(r.content, b'helloworld')

        # XXX accessing .content doesn't work if the response was iterated first
        # XXX change this when the deprecation completes in HttpResponse
        r = HttpResponse(iter(['hello', 'world']))
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", PendingDeprecationWarning)
            self.assertEqual(b''.join(r), b'helloworld')
        self.assertEqual(r.content, b'')                # not the expected result!

        # additional content can be written to the response.
        r = HttpResponse(iter(['hello', 'world']))
        self.assertEqual(r.content, b'helloworld')
        r.write('!')
        self.assertEqual(r.content, b'helloworld!')

    def test_iterator_isnt_rewound(self):
        # Regression test for #13222
        r = HttpResponse('abc')
        i = iter(r)
        self.assertEqual(list(i), [b'abc'])
        self.assertEqual(list(i), [])

    def test_file_interface(self):
        r = HttpResponse()