[Python-checkins] [3.11] GH-103472: close response in HTTPConnection._tunnel (GH-103473) (#104077)
gpshead
webhook-mailer at python.org
Tue May 2 02:48:22 EDT 2023
https://github.com/python/cpython/commit/0d4026432591d43185568dd31cef6a034c4b9261
commit: 0d4026432591d43185568dd31cef6a034c4b9261
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: gpshead <greg at krypto.org>
date: 2023-05-01T23:48:07-07:00
summary:
[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 9de0cf20fa0485e327e57cc0864c7476da85cfad)
Co-authored-by: Thomas Grainger <tagrain at gmail.com>
Co-authored-by: Gregory P. Smith <greg at krypto.org>
files:
A Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst
M Lib/http/client.py
M Lib/test/test_httplib.py
diff --git a/Lib/http/client.py b/Lib/http/client.py
index eabb0ca26940..5d2196dd79af 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -918,23 +918,26 @@ def _tunnel(self):
del headers
response = self.response_class(self.sock, method=self._method)
- (version, code, message) = response._read_status()
+ try:
+ (version, code, message) = response._read_status()
- if code != http.HTTPStatus.OK:
- self.close()
- raise OSError(f"Tunnel connection failed: {code} {message.strip()}")
- while True:
- line = response.fp.readline(_MAXLINE + 1)
- if len(line) > _MAXLINE:
- raise LineTooLong("header line")
- if not line:
- # for sites which EOF without sending a trailer
- break
- if line in (b'\r\n', b'\n', b''):
- break
+ if code != http.HTTPStatus.OK:
+ self.close()
+ raise OSError(f"Tunnel connection failed: {code} {message.strip()}")
+ while True:
+ line = response.fp.readline(_MAXLINE + 1)
+ if len(line) > _MAXLINE:
+ raise LineTooLong("header line")
+ if not line:
+ # for sites which EOF without sending a trailer
+ break
+ if line in (b'\r\n', b'\n', b''):
+ break
- if self.debuglevel > 0:
- print('header:', line.decode())
+ if self.debuglevel > 0:
+ print('header:', line.decode())
+ finally:
+ response.close()
def connect(self):
"""Connect to the host and port specified in __init__."""
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 15dab0356f5e..acae0127a13f 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -2249,6 +2249,29 @@ def test_tunnel_debuglog(self):
lines = output.getvalue().splitlines()
self.assertIn('header: {}'.format(expected_header), lines)
+ def test_tunnel_leak(self):
+ sock = None
+
+ def _create_connection(address, timeout=None, source_address=None):
+ nonlocal sock
+ sock = FakeSocket(
+ 'HTTP/1.1 404 NOT FOUND\r\n\r\n',
+ host=address[0],
+ port=address[1],
+ )
+ return sock
+
+ self.conn._create_connection = _create_connection
+ self.conn.set_tunnel('destination.com')
+ exc = None
+ try:
+ self.conn.request('HEAD', '/', '')
+ except OSError as e:
+ # keeping a reference to exc keeps response alive in the traceback
+ exc = e
+ self.assertIsNotNone(exc)
+ self.assertTrue(sock.file_closed)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst
new file mode 100644
index 000000000000..01d84f024bd4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst
@@ -0,0 +1,2 @@
+Avoid a potential :exc:`ResourceWarning` in :class:`http.client.HTTPConnection`
+by closing the proxy / tunnel's CONNECT response explicitly.
More information about the Python-checkins
mailing list