[3.12] gh-100985: Consistently wrap IPv6 IP address during CONNECT (GH-100986) (GH-115591)

Update _get_hostport to always remove square brackets
from IPv6 addresses. Then add them if needed
in "CONNECT .." and "Host: ".
(cherry picked from commit 465db27cb9)

Co-authored-by: Derek Higgins <derekh@redhat.com>
This commit is contained in:
Miss Islington (bot) 2024-02-17 14:01:48 +01:00 committed by GitHub
parent 9148b77e0a
commit 23aef575c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 29 additions and 5 deletions

View file

@ -936,17 +936,23 @@ class HTTPConnection:
host = host[:i] host = host[:i]
else: else:
port = self.default_port port = self.default_port
if host and host[0] == '[' and host[-1] == ']': if host and host[0] == '[' and host[-1] == ']':
host = host[1:-1] host = host[1:-1]
return (host, port) return (host, port)
def set_debuglevel(self, level): def set_debuglevel(self, level):
self.debuglevel = level self.debuglevel = level
def _wrap_ipv6(self, ip):
if b':' in ip and ip[0] != b'['[0]:
return b"[" + ip + b"]"
return ip
def _tunnel(self): def _tunnel(self):
connect = b"CONNECT %s:%d %s\r\n" % ( connect = b"CONNECT %s:%d %s\r\n" % (
self._tunnel_host.encode("idna"), self._tunnel_port, self._wrap_ipv6(self._tunnel_host.encode("idna")),
self._tunnel_port,
self._http_vsn_str.encode("ascii")) self._http_vsn_str.encode("ascii"))
headers = [connect] headers = [connect]
for header, value in self._tunnel_headers.items(): for header, value in self._tunnel_headers.items():
@ -1221,9 +1227,8 @@ class HTTPConnection:
# As per RFC 273, IPv6 address should be wrapped with [] # As per RFC 273, IPv6 address should be wrapped with []
# when used as Host header # when used as Host header
host_enc = self._wrap_ipv6(host_enc)
if ":" in host: if ":" in host:
host_enc = b'[' + host_enc + b']'
host_enc = _strip_ipv6_iface(host_enc) host_enc = _strip_ipv6_iface(host_enc)
if port == self.default_port: if port == self.default_port:

View file

@ -2408,6 +2408,22 @@ class TunnelTests(TestCase):
self.assertIn(b'PUT / HTTP/1.1\r\nHost: %(host)s\r\n' % d, self.assertIn(b'PUT / HTTP/1.1\r\nHost: %(host)s\r\n' % d,
self.conn.sock.data) self.conn.sock.data)
def test_connect_put_request_ipv6(self):
self.conn.set_tunnel('[1:2:3::4]', 1234)
self.conn.request('PUT', '/', '')
self.assertEqual(self.conn.sock.host, self.host)
self.assertEqual(self.conn.sock.port, client.HTTP_PORT)
self.assertIn(b'CONNECT [1:2:3::4]:1234', self.conn.sock.data)
self.assertIn(b'Host: [1:2:3::4]:1234', self.conn.sock.data)
def test_connect_put_request_ipv6_port(self):
self.conn.set_tunnel('[1:2:3::4]:1234')
self.conn.request('PUT', '/', '')
self.assertEqual(self.conn.sock.host, self.host)
self.assertEqual(self.conn.sock.port, client.HTTP_PORT)
self.assertIn(b'CONNECT [1:2:3::4]:1234', self.conn.sock.data)
self.assertIn(b'Host: [1:2:3::4]:1234', self.conn.sock.data)
def test_tunnel_debuglog(self): def test_tunnel_debuglog(self):
expected_header = 'X-Dummy: 1' expected_header = 'X-Dummy: 1'
response_text = 'HTTP/1.0 200 OK\r\n{}\r\n\r\n'.format(expected_header) response_text = 'HTTP/1.0 200 OK\r\n{}\r\n\r\n'.format(expected_header)

View file

@ -752,6 +752,7 @@ Raymond Hettinger
Lisa Hewus Fresh Lisa Hewus Fresh
Kevan Heydon Kevan Heydon
Wouter van Heyst Wouter van Heyst
Derek Higgins
Kelsey Hightower Kelsey Hightower
Jason Hildebrand Jason Hildebrand
Ryan Hileman Ryan Hileman

View file

@ -0,0 +1,2 @@
Update HTTPSConnection to consistently wrap IPv6 Addresses when using a
proxy.