mirror of
https://github.com/python/cpython
synced 2026-09-29 12:10:30 +03:00
gh-69152: add method get_proxy_response_headers to HTTPConnection class (#104248)
Add http.client.HTTPConnection method get_proxy_response_headers() - this is a followup to https://github.com/python/cpython/pull/26152 which added it as a non-public attribute. This way we don't pre-compute a headers dictionary that most users will never access. The new method is properly public and documented and triggers full proxy header parsing into a dict only when actually called. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
parent
24d8b88420
commit
85ec192ac4
4 changed files with 44 additions and 12 deletions
|
|
@ -394,6 +394,17 @@ HTTPConnection Objects
|
|||
one will be automatically generated and transmitted if not provided in
|
||||
the headers argument.
|
||||
|
||||
|
||||
.. method:: HTTPConnection.get_proxy_response_headers()
|
||||
|
||||
Returns a dictionary with the headers of the response received from
|
||||
the proxy server to the CONNECT request.
|
||||
|
||||
If the CONNECT request was not sent, the method returns an empty dictionary.
|
||||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
|
||||
.. method:: HTTPConnection.connect()
|
||||
|
||||
Connect to the server specified when the object was created. By default,
|
||||
|
|
|
|||
|
|
@ -221,8 +221,9 @@ def _read_headers(fp):
|
|||
break
|
||||
return headers
|
||||
|
||||
def parse_headers(fp, _class=HTTPMessage):
|
||||
"""Parses only RFC2822 headers from a file pointer.
|
||||
def _parse_header_lines(header_lines, _class=HTTPMessage):
|
||||
"""
|
||||
Parses only RFC2822 headers from header lines.
|
||||
|
||||
email Parser wants to see strings rather than bytes.
|
||||
But a TextIOWrapper around self.rfile would buffer too many bytes
|
||||
|
|
@ -231,10 +232,15 @@ def parse_headers(fp, _class=HTTPMessage):
|
|||
to parse.
|
||||
|
||||
"""
|
||||
headers = _read_headers(fp)
|
||||
hstring = b''.join(headers).decode('iso-8859-1')
|
||||
hstring = b''.join(header_lines).decode('iso-8859-1')
|
||||
return email.parser.Parser(_class=_class).parsestr(hstring)
|
||||
|
||||
def parse_headers(fp, _class=HTTPMessage):
|
||||
"""Parses only RFC2822 headers from a file pointer."""
|
||||
|
||||
headers = _read_headers(fp)
|
||||
return _parse_header_lines(headers, _class)
|
||||
|
||||
|
||||
class HTTPResponse(io.BufferedIOBase):
|
||||
|
||||
|
|
@ -858,7 +864,7 @@ class HTTPConnection:
|
|||
self._tunnel_host = None
|
||||
self._tunnel_port = None
|
||||
self._tunnel_headers = {}
|
||||
self._proxy_response_headers = None
|
||||
self._raw_proxy_headers = None
|
||||
|
||||
(self.host, self.port) = self._get_hostport(host, port)
|
||||
|
||||
|
|
@ -945,11 +951,11 @@ class HTTPConnection:
|
|||
try:
|
||||
(version, code, message) = response._read_status()
|
||||
|
||||
self._proxy_response_headers = parse_headers(response.fp)
|
||||
self._raw_proxy_headers = _read_headers(response.fp)
|
||||
|
||||
if self.debuglevel > 0:
|
||||
for hdr, val in self._proxy_response_headers.items():
|
||||
print("header:", hdr + ":", val)
|
||||
for header in self._raw_proxy_headers:
|
||||
print('header:', header.decode())
|
||||
|
||||
if code != http.HTTPStatus.OK:
|
||||
self.close()
|
||||
|
|
@ -958,6 +964,21 @@ class HTTPConnection:
|
|||
finally:
|
||||
response.close()
|
||||
|
||||
def get_proxy_response_headers(self):
|
||||
"""
|
||||
Returns a dictionary with the headers of the response
|
||||
received from the proxy server to the CONNECT request
|
||||
sent to set the tunnel.
|
||||
|
||||
If the CONNECT request was not sent, the method returns
|
||||
an empty dictionary.
|
||||
"""
|
||||
return (
|
||||
_parse_header_lines(self._raw_proxy_headers)
|
||||
if self._raw_proxy_headers is not None
|
||||
else {}
|
||||
)
|
||||
|
||||
def connect(self):
|
||||
"""Connect to the host and port specified in __init__."""
|
||||
sys.audit("http.client.connect", self, self.host, self.port)
|
||||
|
|
|
|||
|
|
@ -2401,7 +2401,7 @@ class TunnelTests(TestCase):
|
|||
self.conn.set_tunnel('destination.com')
|
||||
|
||||
self.conn.request('PUT', '/', '')
|
||||
headers = self.conn._proxy_response_headers
|
||||
headers = self.conn.get_proxy_response_headers()
|
||||
self.assertIn(expected_header, headers.items())
|
||||
|
||||
def test_tunnel_leak(self):
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
Added attribute '_proxy_response_headers' to HTTPConnection class. This
|
||||
attribute contains the headers of the proxy server response to the CONNECT
|
||||
request.
|
||||
Added :meth:`http.client.HTTPConnection.get_proxy_response_headers` that
|
||||
provides access to the HTTP headers on a proxy server response to the
|
||||
``CONNECT`` request.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue