]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-73561: Omit interface scope from IPv6 when used as Host header (#93324)
authorMichael <35783820+mib1185@users.noreply.github.com>
Sun, 19 Nov 2023 22:37:13 +0000 (23:37 +0100)
committerGitHub <noreply@github.com>
Sun, 19 Nov 2023 22:37:13 +0000 (22:37 +0000)
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]
Lib/http/client.py
Lib/test/test_httplib.py
Misc/NEWS.d/next/Library/2022-05-28-20-55-07.gh-issue-73561.YRmAvy.rst [new file with mode: 0644]

index b35b1d6368aae7d352677a5289ba1e5fd54024fd..7bb5d824bb6da432f3174c0118632c925ee7537d 100644 (file)
@@ -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)
index 5d5832b62b2f9438e52b0cc983d3524a9d781e7d..caa4c76a913a0125005762a0ad68f6e778167fad 100644 (file)
@@ -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 (file)
index 0000000..5e00b7d
--- /dev/null
@@ -0,0 +1 @@
+Omit the interface scope from an IPv6 address when used as Host header by :mod:`http.client`.