Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit beec61a

Browse files
committed
Issue #15633: httplib.HTTPResponse is now mark closed when the server sends less than the advertised Content-Length.
1 parent 6375257 commit beec61a

3 files changed

Lines changed: 27 additions & 4 deletions

File tree

Lib/http/client.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,11 @@ def read(self, amt=None):
493493
if self.length is None:
494494
s = self.fp.read()
495495
else:
496-
s = self._safe_read(self.length)
496+
try:
497+
s = self._safe_read(self.length)
498+
except IncompleteRead:
499+
self.close()
500+
raise
497501
self.length = 0
498502
self.close() # we read everything
499503
return s
@@ -507,6 +511,10 @@ def read(self, amt=None):
507511
# connection, and the user is reading more bytes than will be provided
508512
# (for example, reading in 1k chunks)
509513
s = self.fp.read(amt)
514+
if not s:
515+
# Ideally, we would raise IncompleteRead if the content-length
516+
# wasn't satisfied, but it might break compatibility.
517+
self.close()
510518
if self.length is not None:
511519
self.length -= len(s)
512520
if not self.length:

Lib/test/test_httplib.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,19 @@ def test_partial_reads_no_content_length(self):
199199
self.assertEqual(resp.read(1), b'')
200200
self.assertTrue(resp.isclosed())
201201

202+
def test_partial_reads_incomplete_body(self):
203+
# if the server shuts down the connection before the whole
204+
# content-length is delivered, the socket is gracefully closed
205+
body = "HTTP/1.1 200 Ok\r\nContent-Length: 10\r\n\r\nText"
206+
sock = FakeSocket(body)
207+
resp = client.HTTPResponse(sock)
208+
resp.begin()
209+
self.assertEqual(resp.read(2), b'Te')
210+
self.assertFalse(resp.isclosed())
211+
self.assertEqual(resp.read(2), b'xt')
212+
self.assertEqual(resp.read(1), b'')
213+
self.assertTrue(resp.isclosed())
214+
202215
def test_host_port(self):
203216
# Check invalid host_port
204217

@@ -349,7 +362,7 @@ def test_negative_content_length(self):
349362
resp = client.HTTPResponse(sock, method="GET")
350363
resp.begin()
351364
self.assertEqual(resp.read(), b'Hello\r\n')
352-
resp.close()
365+
self.assertTrue(resp.isclosed())
353366

354367
def test_incomplete_read(self):
355368
sock = FakeSocket('HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\nHello\r\n')
@@ -363,10 +376,9 @@ def test_incomplete_read(self):
363376
"IncompleteRead(7 bytes read, 3 more expected)")
364377
self.assertEqual(str(i),
365378
"IncompleteRead(7 bytes read, 3 more expected)")
379+
self.assertTrue(resp.isclosed())
366380
else:
367381
self.fail('IncompleteRead expected')
368-
finally:
369-
resp.close()
370382

371383
def test_epipe(self):
372384
sock = EPipeSocket(

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ Core and Builtins
212212
Library
213213
-------
214214

215+
- Issue #15633: httplib.HTTPResponse is now mark closed when the server
216+
sends less than the advertised Content-Length.
217+
215218
- Issue #6972: The zipfile module no longer overwrites files outside of
216219
its destination path when extracting malicious zip files.
217220

0 commit comments

Comments
 (0)