diff --git a/changelogs/fragments/urls-ipv6-redirects.yml b/changelogs/fragments/urls-ipv6-redirects.yml new file mode 100644 index 0000000000..a159e7fd48 --- /dev/null +++ b/changelogs/fragments/urls-ipv6-redirects.yml @@ -0,0 +1,4 @@ +bugfixes: +- urls - Handle redirects properly for IPv6 address by not splitting on ``:`` + and rely on already parsed hostname and port values + (https://github.com/ansible/ansible/issues/56258) diff --git a/lib/ansible/module_utils/urls.py b/lib/ansible/module_utils/urls.py index bd8365702b..895ae71487 100644 --- a/lib/ansible/module_utils/urls.py +++ b/lib/ansible/module_utils/urls.py @@ -559,8 +559,24 @@ def generic_urlparse(parts): generic_parts['fragment'] = parts.fragment generic_parts['username'] = parts.username generic_parts['password'] = parts.password - generic_parts['hostname'] = parts.hostname - generic_parts['port'] = parts.port + hostname = parts.hostname + if hostname and hostname[0] == '[' and '[' in parts.netloc and ']' in parts.netloc: + # Py2.6 doesn't parse IPv6 addresses correctly + hostname = parts.netloc.split(']')[0][1:].lower() + generic_parts['hostname'] = hostname + + try: + port = parts.port + except ValueError: + # Py2.6 doesn't parse IPv6 addresses correctly + netloc = parts.netloc.split('@')[-1].split(']')[-1] + if ':' in netloc: + port = netloc.split(':')[1] + if port: + port = int(port) + else: + port = None + generic_parts['port'] = port else: # we have to use indexes, and then parse out # the other parts not supported by indexing @@ -963,19 +979,9 @@ def maybe_add_ssl_handler(url, validate_certs): raise NoSSLError('SSL validation is not available in your version of python. You can use validate_certs=False,' ' however this is unsafe and not recommended') - # do the cert validation - netloc = parsed.netloc - if '@' in netloc: - netloc = netloc.split('@', 1)[1] - if ':' in netloc: - hostname, port = netloc.split(':', 1) - port = int(port) - else: - hostname = netloc - port = 443 # create the SSL validation handler and # add it to the list of handlers - return SSLValidationHandler(hostname, port) + return SSLValidationHandler(parsed.hostname, parsed.port or 443) def rfc2822_date_string(timetuple, zone='-0000'): diff --git a/test/units/module_utils/urls/test_urls.py b/test/units/module_utils/urls/test_urls.py index 3dfe28e0cb..69c1b8240c 100644 --- a/test/units/module_utils/urls/test_urls.py +++ b/test/units/module_utils/urls/test_urls.py @@ -76,6 +76,16 @@ def test_maybe_add_ssl_handler(mocker): handler = urls.maybe_add_ssl_handler(url, True) assert handler is None + url = 'https://[2a00:16d8:0:7::205]:4443/' + handler = urls.maybe_add_ssl_handler(url, True) + assert handler.hostname == '2a00:16d8:0:7::205' + assert handler.port == 4443 + + url = 'https://[2a00:16d8:0:7::205]/' + handler = urls.maybe_add_ssl_handler(url, True) + assert handler.hostname == '2a00:16d8:0:7::205' + assert handler.port == 443 + def test_basic_auth_header(): header = urls.basic_auth_header('user', 'passwd')