diff --git a/requests/models.py b/requests/models.py index ce4e284e64..48ac38b270 100644 --- a/requests/models.py +++ b/requests/models.py @@ -785,6 +785,7 @@ def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter= """ pending = None + carriage_return = u'\r' if decode_unicode else b'\r' for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): @@ -798,6 +799,8 @@ def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter= if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]: pending = lines.pop() + elif not delimiter and lines and chunk.endswith(carriage_return): + pending = lines.pop() + carriage_return else: pending = None @@ -805,6 +808,8 @@ def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=None, delimiter= yield line if pending is not None: + if not delimiter: + pending = pending.rstrip(carriage_return) yield pending @property diff --git a/tests/test_requests.py b/tests/test_requests.py index b374747427..595a1a042d 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -3,6 +3,7 @@ """Tests for Requests.""" from __future__ import division +import base64 import json import os import pickle @@ -1738,6 +1739,15 @@ def test_response_iter_lines(self, httpbin): next(it) assert len(list(it)) == 3 + @pytest.mark.parametrize('chunk', (3, 4)) + @pytest.mark.parametrize('decode', (True, False)) + def test_response_iter_lines_crlf_across_chunks(self, httpbin, chunk, decode): + b64_body = base64.b64encode(b'one\r\ntwo\r\rthree\r').decode('ascii') + r = requests.get(httpbin('base64/' + b64_body), stream=True) + + it = r.iter_lines(chunk_size=chunk, decode_unicode=decode) + assert [len(line) for line in it] == [3, 3, 0, 5] + def test_response_context_manager(self, httpbin): with requests.get(httpbin('stream/4'), stream=True) as response: assert isinstance(response, requests.Response)