diff options
author | Michael <35783820+mib1185@users.noreply.github.com> | 2023-11-19 22:37:13 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-19 22:37:13 (GMT) |
commit | ce1096f974d3158a92e050f9226700775b8db398 (patch) | |
tree | 3c0ef4e51e7b67383d513df34f47b0a492ca7dd2 | |
parent | 7c9f2677fbb8805f7d531fb96731339727e8ea20 (diff) | |
download | cpython-ce1096f974d3158a92e050f9226700775b8db398.zip cpython-ce1096f974d3158a92e050f9226700775b8db398.tar.gz cpython-ce1096f974d3158a92e050f9226700775b8db398.tar.bz2 |
gh-73561: Omit interface scope from IPv6 when used as Host header (#93324)
Omit the `@interface_scope` from an IPv6 address when used as Host header by `http.client`.
---------
Co-authored-by: Gregory P. Smith <greg@krypto.org> [Google LLC]
-rw-r--r-- | Lib/http/client.py | 12 | ||||
-rw-r--r-- | Lib/test/test_httplib.py | 16 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2022-05-28-20-55-07.gh-issue-73561.YRmAvy.rst | 1 |
3 files changed, 27 insertions, 2 deletions
diff --git a/Lib/http/client.py b/Lib/http/client.py index b35b1d6..7bb5d82 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -172,6 +172,13 @@ def _encode(data, name='data'): "if you want to send it encoded in UTF-8." % (name.title(), data[err.start:err.end], name)) from None +def _strip_ipv6_iface(enc_name: bytes) -> bytes: + """Remove interface scope from IPv6 address.""" + enc_name, percent, _ = enc_name.partition(b"%") + if percent: + assert enc_name.startswith(b'['), enc_name + enc_name += b']' + return enc_name class HTTPMessage(email.message.Message): # XXX The only usage of this method is in @@ -1194,7 +1201,7 @@ class HTTPConnection: netloc_enc = netloc.encode("ascii") except UnicodeEncodeError: netloc_enc = netloc.encode("idna") - self.putheader('Host', netloc_enc) + self.putheader('Host', _strip_ipv6_iface(netloc_enc)) else: if self._tunnel_host: host = self._tunnel_host @@ -1211,8 +1218,9 @@ class HTTPConnection: # As per RFC 273, IPv6 address should be wrapped with [] # when used as Host header - if host.find(':') >= 0: + if ":" in host: host_enc = b'[' + host_enc + b']' + host_enc = _strip_ipv6_iface(host_enc) if port == self.default_port: self.putheader('Host', host_enc) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 5d5832b..caa4c76 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -283,6 +283,22 @@ class HeaderTests(TestCase): conn.request('GET', '/foo') self.assertTrue(sock.data.startswith(expected)) + expected = b'GET /foo HTTP/1.1\r\nHost: [fe80::]\r\n' \ + b'Accept-Encoding: identity\r\n\r\n' + conn = client.HTTPConnection('[fe80::%2]') + sock = FakeSocket('') + conn.sock = sock + conn.request('GET', '/foo') + self.assertTrue(sock.data.startswith(expected)) + + expected = b'GET /foo HTTP/1.1\r\nHost: [fe80::]:81\r\n' \ + b'Accept-Encoding: identity\r\n\r\n' + conn = client.HTTPConnection('[fe80::%2]:81') + sock = FakeSocket('') + conn.sock = sock + conn.request('GET', '/foo') + self.assertTrue(sock.data.startswith(expected)) + def test_malformed_headers_coped_with(self): # Issue 19996 body = "HTTP/1.1 200 OK\r\nFirst: val\r\n: nval\r\nSecond: val\r\n\r\n" diff --git a/Misc/NEWS.d/next/Library/2022-05-28-20-55-07.gh-issue-73561.YRmAvy.rst b/Misc/NEWS.d/next/Library/2022-05-28-20-55-07.gh-issue-73561.YRmAvy.rst new file mode 100644 index 0000000..5e00b7d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-28-20-55-07.gh-issue-73561.YRmAvy.rst @@ -0,0 +1 @@ +Omit the interface scope from an IPv6 address when used as Host header by :mod:`http.client`. |