Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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.
  • Loading branch information...
commit 82b3e6ffcb9d810cc0e3ec27d25f89ce1fd525e0 1 parent 495a8b8
Aymeric Augustin authored October 24, 2012
5  django/http/response.py
@@ -283,7 +283,8 @@ def __iter__(self):
283 283
                 'deprecated. Use `StreamingHttpResponse` instead '
284 284
                 'if you need the streaming behavior.',
285 285
                 PendingDeprecationWarning, stacklevel=2)
286  
-        self._iterator = iter(self._container)
  286
+        if not hasattr(self, '_iterator'):
  287
+            self._iterator = iter(self._container)
287 288
         return self
288 289
 
289 290
     def __next__(self):
@@ -303,7 +304,7 @@ def write(self, content):
303 304
 
304 305
     def tell(self):
305 306
         self._consume_content()
306  
-        return sum(len(chunk) for chunk in self)
  307
+        return len(self.content)
307 308
 
308 309
 
309 310
 class StreamingHttpResponse(HttpResponseBase):
6  django/test/testcases.py
@@ -596,7 +596,11 @@ def assertContains(self, response, text, count=None, status_code=200,
596 596
             msg_prefix + "Couldn't retrieve content: Response code was %d"
597 597
             " (expected %d)" % (response.status_code, status_code))
598 598
         text = force_text(text, encoding=response._charset)
599  
-        content = b''.join(response).decode(response._charset)
  599
+        if response.streaming:
  600
+            content = b''.join(response.streaming_content)
  601
+        else:
  602
+            content = response.content
  603
+        content = content.decode(response._charset)
600 604
         # Avoid ResourceWarning about unclosed files.
601 605
         response.close()
602 606
         if html:
23  tests/regressiontests/httpwrappers/tests.py
@@ -337,15 +337,36 @@ def test_iter_content(self):
337 337
         self.assertRaises(UnicodeEncodeError,
338 338
                           getattr, r, 'content')
339 339
 
340  
-        # content can safely be accessed multiple times.
  340
+        # .content can safely be accessed multiple times.
341 341
         r = HttpResponse(iter(['hello', 'world']))
342 342
         self.assertEqual(r.content, r.content)
343 343
         self.assertEqual(r.content, b'helloworld')
  344
+        # accessing the iterator works (once) after accessing .content
  345
+        self.assertEqual(b''.join(r), b'helloworld')
  346
+        self.assertEqual(b''.join(r), b'')
  347
+        # accessing .content still works
  348
+        self.assertEqual(r.content, b'helloworld')
  349
+
  350
+        # XXX accessing .content doesn't work if the response was iterated first
  351
+        # XXX change this when the deprecation completes in HttpResponse
  352
+        r = HttpResponse(iter(['hello', 'world']))
  353
+        with warnings.catch_warnings():
  354
+            warnings.simplefilter("ignore", PendingDeprecationWarning)
  355
+            self.assertEqual(b''.join(r), b'helloworld')
  356
+        self.assertEqual(r.content, b'')                # not the expected result!
344 357
 
345 358
         # additional content can be written to the response.
  359
+        r = HttpResponse(iter(['hello', 'world']))
  360
+        self.assertEqual(r.content, b'helloworld')
346 361
         r.write('!')
347 362
         self.assertEqual(r.content, b'helloworld!')
348 363
 
  364
+    def test_iterator_isnt_rewound(self):
  365
+        # Regression test for #13222
  366
+        r = HttpResponse('abc')
  367
+        i = iter(r)
  368
+        self.assertEqual(list(i), [b'abc'])
  369
+        self.assertEqual(list(i), [])
349 370
 
350 371
     def test_file_interface(self):
351 372
         r = HttpResponse()

0 notes on commit 82b3e6f

Please sign in to comment.
Something went wrong with that request. Please try again.