Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Lib/http/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,8 @@ def read1(self, n=-1):
result = self.fp.read1(n)
if not result and n:
self._close_conn()
if self.length:
raise IncompleteRead(result, self.length)
elif self.length is not None:
self.length -= len(result)
if not self.length:
Expand All @@ -689,6 +691,8 @@ def readline(self, limit=-1):
result = self.fp.readline(limit)
if not result and limit:
self._close_conn()
if self.length:
raise IncompleteRead(result, self.length)
elif self.length is not None:
self.length -= len(result)
if not self.length:
Expand Down
34 changes: 34 additions & 0 deletions Lib/test/test_httplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,40 @@ class ExtendedReadTestContentLengthKnown(ExtendedReadTest):
_header, _body = ExtendedReadTest.lines.split('\r\n\r\n', 1)
lines = _header + f'\r\nContent-Length: {len(_body)}\r\n\r\n' + _body

def _test_incomplete_read(self, read_meth):
resp = self.resp
# Reduce the size of content the response object will read to
# cause the incomplete read.
resp.fp.read(1)
with self.assertRaises(client.IncompleteRead) as cm:
while True:
data = read_meth()
if not data:
break
exception = cm.exception
# Unlike `read1` and `readline`, `read` tries to read the whole
# content during one call, so it's partial is not empty in this
# case.
# `read1` and `readline` raise `IncompleteRead` only when they
# read 0 bytes before all expected content has been read, so the
# partial is empty.
if read_meth == self.resp.read:
expected_partial = self._body[1:].encode()
else:
expected_partial = b""
self.assertEqual(exception.partial, expected_partial)
self.assertEqual(exception.expected, 1)
self.assertTrue(resp.isclosed())

def test_read_incomplete_read(self):
self._test_incomplete_read(self.resp.read)

def test_read1_incomplete_read(self):
self._test_incomplete_read(self.resp.read1)

def test_readline_incomplete_read(self):
self._test_incomplete_read(self.resp.readline)


class ExtendedReadTestChunked(ExtendedReadTest):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Make ``http.client.HTTPResponse.read1`` and
``http.client.HTTPResponse.readline`` raise :exc:`IncompleteRead` instead of
returning zero bytes if a connection is closed before an expected number of
bytes has been read. Patch by Illia Volochii.