summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael <35783820+mib1185@users.noreply.github.com>2023-11-19 22:37:13 (GMT)
committerGitHub <noreply@github.com>2023-11-19 22:37:13 (GMT)
commitce1096f974d3158a92e050f9226700775b8db398 (patch)
tree3c0ef4e51e7b67383d513df34f47b0a492ca7dd2
parent7c9f2677fbb8805f7d531fb96731339727e8ea20 (diff)
downloadcpython-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.py12
-rw-r--r--Lib/test/test_httplib.py16
-rw-r--r--Misc/NEWS.d/next/Library/2022-05-28-20-55-07.gh-issue-73561.YRmAvy.rst1
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`.