diff --git a/src/requests/adapters.py b/src/requests/adapters.py index 40fe8a6d5a..b5d0f0a65b 100644 --- a/src/requests/adapters.py +++ b/src/requests/adapters.py @@ -742,6 +742,17 @@ def send( raise ReadTimeout(e, request=request) elif isinstance(e, _InvalidHeader): raise InvalidHeader(e, request=request) + elif isinstance(e, LocationValueError): + # urllib3 may raise LocationParseError (subclass of + # LocationValueError) from inside `create_connection` when the + # hostname has labels that fail validation (e.g. a label longer + # than 63 characters). prepare_url catches this at parse time, + # but the same exception can also be raised later from the + # socket layer where it would otherwise bubble up to the caller + # as a urllib3 exception. Wrap it in InvalidURL so users see a + # requests-native exception, matching the behaviour of + # get_connection_with_tls_context above. See GH #5744. + raise InvalidURL(e, request=request) else: raise diff --git a/tests/test_requests.py b/tests/test_requests.py index 571535fe79..c00f24c81f 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -588,6 +588,13 @@ def test_basicauth_encodes_byte_strings(self): ("http://localhost:1", ConnectionError), # Inputting a URL that cannot be parsed should raise an InvalidURL error ("http://fe80::5054:ff:fe5a:fc0", InvalidURL), + # A DNS label longer than 63 chars survives prepare_url but is + # rejected by urllib3 inside create_connection. Should surface as + # InvalidURL, not as a raw urllib3.LocationParseError. GH #5744. + ( + "http://" + ("a" * 64) + ".example.com", + InvalidURL, + ), ), ) def test_errors(self, url, exception):