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

Skip to content

Commit b5b9c8c

Browse files
Issue #16723: httplib.HTTPResponse no longer marked closed when the connection
is automatically closed.
1 parent f581b37 commit b5b9c8c

3 files changed

Lines changed: 39 additions & 15 deletions

File tree

Lib/http/client.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ def _read_status(self):
324324
# empty version will cause next test to fail.
325325
version = ""
326326
if not version.startswith("HTTP/"):
327-
self.close()
327+
self._close_conn()
328328
raise BadStatusLine(line)
329329

330330
# The status code is a three-digit number
@@ -446,29 +446,33 @@ def _check_close(self):
446446
# otherwise, assume it will close
447447
return True
448448

449+
def _close_conn(self):
450+
fp = self.fp
451+
self.fp = None
452+
fp.close()
453+
449454
def close(self):
455+
super().close() # set "closed" flag
450456
if self.fp:
451-
self.fp.close()
452-
self.fp = None
457+
self._close_conn()
453458

454459
# These implementations are for the benefit of io.BufferedReader.
455460

456461
# XXX This class should probably be revised to act more like
457462
# the "raw stream" that BufferedReader expects.
458463

459-
@property
460-
def closed(self):
461-
return self.isclosed()
462-
463464
def flush(self):
464-
self.fp.flush()
465+
super().flush()
466+
if self.fp:
467+
self.fp.flush()
465468

466469
def readable(self):
467470
return True
468471

469472
# End of "raw stream" methods
470473

471474
def isclosed(self):
475+
"""True if the connection is closed."""
472476
# NOTE: it is possible that we will not ever call self.close(). This
473477
# case occurs when will_close is TRUE, length is None, and we
474478
# read up to the last byte, but NOT past it.
@@ -482,7 +486,7 @@ def read(self, amt=None):
482486
return b""
483487

484488
if self._method == "HEAD":
485-
self.close()
489+
self._close_conn()
486490
return b""
487491

488492
if self.chunked:
@@ -496,10 +500,10 @@ def read(self, amt=None):
496500
try:
497501
s = self._safe_read(self.length)
498502
except IncompleteRead:
499-
self.close()
503+
self._close_conn()
500504
raise
501505
self.length = 0
502-
self.close() # we read everything
506+
self._close_conn() # we read everything
503507
return s
504508

505509
if self.length is not None:
@@ -514,11 +518,11 @@ def read(self, amt=None):
514518
if not s:
515519
# Ideally, we would raise IncompleteRead if the content-length
516520
# wasn't satisfied, but it might break compatibility.
517-
self.close()
521+
self._close_conn()
518522
elif self.length is not None:
519523
self.length -= len(s)
520524
if not self.length:
521-
self.close()
525+
self._close_conn()
522526

523527
return s
524528

@@ -539,7 +543,7 @@ def _read_chunked(self, amt):
539543
except ValueError:
540544
# close the connection as protocol synchronisation is
541545
# probably lost
542-
self.close()
546+
self._close_conn()
543547
raise IncompleteRead(b''.join(value))
544548
if chunk_left == 0:
545549
break
@@ -576,7 +580,7 @@ def _read_chunked(self, amt):
576580
break
577581

578582
# we read everything; close the "file"
579-
self.close()
583+
self._close_conn()
580584

581585
return b''.join(value)
582586

Lib/test/test_httplib.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ def test_status_lines(self):
164164
resp.begin()
165165
self.assertEqual(resp.read(), b"Text")
166166
self.assertTrue(resp.isclosed())
167+
self.assertFalse(resp.closed)
168+
resp.close()
169+
self.assertTrue(resp.closed)
167170

168171
body = "HTTP/1.1 400.100 Not Ok\r\n\r\nText"
169172
sock = FakeSocket(body)
@@ -185,6 +188,9 @@ def test_partial_reads(self):
185188
self.assertFalse(resp.isclosed())
186189
self.assertEqual(resp.read(2), b'xt')
187190
self.assertTrue(resp.isclosed())
191+
self.assertFalse(resp.closed)
192+
resp.close()
193+
self.assertTrue(resp.closed)
188194

189195
def test_partial_reads_no_content_length(self):
190196
# when no length is present, the socket should be gracefully closed when
@@ -198,6 +204,9 @@ def test_partial_reads_no_content_length(self):
198204
self.assertEqual(resp.read(2), b'xt')
199205
self.assertEqual(resp.read(1), b'')
200206
self.assertTrue(resp.isclosed())
207+
self.assertFalse(resp.closed)
208+
resp.close()
209+
self.assertTrue(resp.closed)
201210

202211
def test_partial_reads_incomplete_body(self):
203212
# if the server shuts down the connection before the whole
@@ -211,6 +220,9 @@ def test_partial_reads_incomplete_body(self):
211220
self.assertEqual(resp.read(2), b'xt')
212221
self.assertEqual(resp.read(1), b'')
213222
self.assertTrue(resp.isclosed())
223+
self.assertFalse(resp.closed)
224+
resp.close()
225+
self.assertTrue(resp.closed)
214226

215227
def test_host_port(self):
216228
# Check invalid host_port
@@ -355,6 +367,9 @@ def test_chunked_head(self):
355367
self.assertEqual(resp.status, 200)
356368
self.assertEqual(resp.reason, 'OK')
357369
self.assertTrue(resp.isclosed())
370+
self.assertFalse(resp.closed)
371+
resp.close()
372+
self.assertTrue(resp.closed)
358373

359374
def test_negative_content_length(self):
360375
sock = FakeSocket(
@@ -430,6 +445,9 @@ def test_early_eof(self):
430445
resp.begin()
431446
self.assertEqual(resp.read(), b'')
432447
self.assertTrue(resp.isclosed())
448+
self.assertFalse(resp.closed)
449+
resp.close()
450+
self.assertTrue(resp.closed)
433451

434452
class OfflineTest(TestCase):
435453
def test_responses(self):

Misc/NEWS

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

215+
- Issue #16723: httplib.HTTPResponse no longer marked closed when the connection
216+
is automatically closed.
215217

216218
- Issue #16948: Fix quoted printable body encoding for non-latin1 character
217219
sets in the email package.

0 commit comments

Comments
 (0)