diff -r 45cf82f424ce Lib/http/client.py --- a/Lib/http/client.py Sun Feb 21 22:00:29 2016 +0200 +++ b/Lib/http/client.py Sat Mar 12 16:35:19 2016 +0100 @@ -640,6 +640,8 @@ return b"" if self.chunked: return self._read1_chunked(n) + if self.length is not None and (n < 0 or n > self.length): + n = self.length try: result = self.fp.read1(n) except ValueError: @@ -650,6 +652,8 @@ result = self.fp.read1(16*1024) if not result and n: self._close_conn() + elif self.length is not None: + self.length -= len(result) return result def peek(self, n=-1): @@ -667,9 +671,13 @@ if self.chunked: # Fallback to IOBase readline which uses peek() and read() return super().readline(limit) + if self.length is not None and (limit < 0 or limit > self.length): + limit = self.length result = self.fp.readline(limit) if not result and limit: self._close_conn() + elif self.length is not None: + self.length -= len(result) return result def _read1_chunked(self, n): diff -r 45cf82f424ce Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py Sun Feb 21 22:00:29 2016 +0200 +++ b/Lib/test/test_httplib.py Sat Mar 12 16:35:19 2016 +0100 @@ -355,6 +355,21 @@ resp.close() self.assertTrue(resp.closed) + def test_mixed_reads(self): + # if we have a length, the system knows when to close itself + # same behaviour than when we read the whole thing with read() + body = "HTTP/1.1 200 Ok\r\nContent-Length: 13\r\n\r\nText\r\nAnother" + sock = FakeSocket(body) + resp = client.HTTPResponse(sock) + resp.begin() + self.assertEqual(resp.readline(), b'Text\r\n') + self.assertFalse(resp.isclosed()) + self.assertEqual(resp.read(), b'Another') + self.assertTrue(resp.isclosed()) + self.assertFalse(resp.closed) + resp.close() + self.assertTrue(resp.closed) + def test_partial_readintos(self): # if we have a length, the system knows when to close itself # same behaviour than when we read the whole thing with read() @@ -854,6 +869,52 @@ self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end resp.close() + def test_readlines_content_length(self): + extradata = "extradata" + expected = b"Hello123\r\n" + sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 1000\r\n\r\n'+'Hello123\r\n'*100 + extradata) + resp = client.HTTPResponse(sock, method="GET") + resp.begin() + self.assertEqual(b''.join(resp.readlines()), expected*100) + # the file should now have our extradata ready to be read + self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end + resp.close() + + def test_read1_content_length(self): + extradata = "extradata" + expected = b"Hello123\r\n" + sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 1000\r\n\r\n'+'Hello123\r\n'*100 + extradata) + resp = client.HTTPResponse(sock, method="GET") + resp.begin() + self.assertEqual(resp.read1(), expected*100) + # the file should now have our extradata ready to be read + self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end + resp.close() + + def test_readline_bound_content_length(self): + extradata = "extradata" + expected = b"Hello123\r\n" + sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 1000\r\n\r\n'+'Hello123\r\n'*100 + extradata) + resp = client.HTTPResponse(sock, method="GET") + resp.begin() + self.assertEqual(b''.join(resp.readline(10) for _ in range(10)), expected*10) + self.assertEqual(resp.read(), expected*90) + # the file should now have our extradata ready to be read + self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end + resp.close() + + def test_read1_bound_content_length(self): + extradata = "extradata" + expected = b"Hello123\r\n" + sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 1000\r\n\r\n'+'Hello123\r\n'*100 + extradata) + resp = client.HTTPResponse(sock, method="GET") + resp.begin() + self.assertEqual(resp.read1(20), expected*2) + self.assertEqual(resp.read(), expected*98) + # the file should now have our extradata ready to be read + self.assertEqual(sock.file.read(100), extradata.encode("ascii")) #we read to the end + resp.close() + class ExtendedReadTest(TestCase): """ Test peek(), read1(), readline()