Skip to content

Commit 0d40264

Browse files
miss-islingtongraingertgpshead
authored
[3.11] GH-103472: close response in HTTPConnection._tunnel (GH-103473) (#104077)
GH-103472: close response in HTTPConnection._tunnel (GH-103473) Avoid a potential `ResourceWarning` in `http.client.HTTPConnection` by closing the proxy / tunnel's CONNECT response explicitly. --------- (cherry picked from commit 9de0cf2) Co-authored-by: Thomas Grainger <tagrain@gmail.com> Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parent b07bae6 commit 0d40264

File tree

3 files changed

+43
-15
lines changed

3 files changed

+43
-15
lines changed

Lib/http/client.py

+18-15
Original file line numberDiff line numberDiff line change
@@ -918,23 +918,26 @@ def _tunnel(self):
918918
del headers
919919

920920
response = self.response_class(self.sock, method=self._method)
921-
(version, code, message) = response._read_status()
921+
try:
922+
(version, code, message) = response._read_status()
922923

923-
if code != http.HTTPStatus.OK:
924-
self.close()
925-
raise OSError(f"Tunnel connection failed: {code} {message.strip()}")
926-
while True:
927-
line = response.fp.readline(_MAXLINE + 1)
928-
if len(line) > _MAXLINE:
929-
raise LineTooLong("header line")
930-
if not line:
931-
# for sites which EOF without sending a trailer
932-
break
933-
if line in (b'\r\n', b'\n', b''):
934-
break
924+
if code != http.HTTPStatus.OK:
925+
self.close()
926+
raise OSError(f"Tunnel connection failed: {code} {message.strip()}")
927+
while True:
928+
line = response.fp.readline(_MAXLINE + 1)
929+
if len(line) > _MAXLINE:
930+
raise LineTooLong("header line")
931+
if not line:
932+
# for sites which EOF without sending a trailer
933+
break
934+
if line in (b'\r\n', b'\n', b''):
935+
break
935936

936-
if self.debuglevel > 0:
937-
print('header:', line.decode())
937+
if self.debuglevel > 0:
938+
print('header:', line.decode())
939+
finally:
940+
response.close()
938941

939942
def connect(self):
940943
"""Connect to the host and port specified in __init__."""

Lib/test/test_httplib.py

+23
Original file line numberDiff line numberDiff line change
@@ -2249,6 +2249,29 @@ def test_tunnel_debuglog(self):
22492249
lines = output.getvalue().splitlines()
22502250
self.assertIn('header: {}'.format(expected_header), lines)
22512251

2252+
def test_tunnel_leak(self):
2253+
sock = None
2254+
2255+
def _create_connection(address, timeout=None, source_address=None):
2256+
nonlocal sock
2257+
sock = FakeSocket(
2258+
'HTTP/1.1 404 NOT FOUND\r\n\r\n',
2259+
host=address[0],
2260+
port=address[1],
2261+
)
2262+
return sock
2263+
2264+
self.conn._create_connection = _create_connection
2265+
self.conn.set_tunnel('destination.com')
2266+
exc = None
2267+
try:
2268+
self.conn.request('HEAD', '/', '')
2269+
except OSError as e:
2270+
# keeping a reference to exc keeps response alive in the traceback
2271+
exc = e
2272+
self.assertIsNotNone(exc)
2273+
self.assertTrue(sock.file_closed)
2274+
22522275

22532276
if __name__ == '__main__':
22542277
unittest.main(verbosity=2)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Avoid a potential :exc:`ResourceWarning` in :class:`http.client.HTTPConnection`
2+
by closing the proxy / tunnel's CONNECT response explicitly.

0 commit comments

Comments
 (0)