diff --git a/httpie/cli/argparser.py b/httpie/cli/argparser.py index 9bf09b3b73..56deffee59 100644 --- a/httpie/cli/argparser.py +++ b/httpie/cli/argparser.py @@ -5,7 +5,7 @@ import sys from argparse import RawDescriptionHelpFormatter from textwrap import dedent -from urllib.parse import urlsplit +from urllib.parse import urlsplit, unquote from requests.utils import get_netrc_auth @@ -289,8 +289,9 @@ def _process_auth(self): if self.args.auth is None and not auth_type_set: if url.username is not None: # Handle http://username:password@hostname/ - username = url.username - password = url.password or '' + # Decode percent-encoded characters in credentials + username = unquote(url.username) + password = unquote(url.password) if url.password else '' self.args.auth = AuthCredentials( key=username, value=password, diff --git a/tests/test_auth.py b/tests/test_auth.py index 83423efec0..795c0e2346 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -153,3 +153,25 @@ def test_ignore_netrc_null_auth(): env=MockEnvironment(), ) assert isinstance(args.auth, ExplicitNullAuth) + + +def test_percent_encoded_credentials_in_url(httpbin_both): + """ + Test that percent-encoded characters in URL credentials are decoded. + + https://github.com/httpie/cli/issues/1623 + + When credentials contain special characters (like @, =, ?) they need to be + percent-encoded in the URL. HTTPie should decode these before using them + for authentication. + """ + # The credentials are: username="u@d", password="1=2?" + # Percent-encoded: username="u%40d", password="1%3d2%3f" + url = httpbin_both.url + '/basic-auth/u%40d/1%3d2%3f' + url_with_auth = add_auth(url, auth='u%40d:1%3d2%3f') + + r = http('GET', url_with_auth) + + # This should succeed with 200 OK, not 401 + assert HTTP_OK in r + assert r.json == {'authenticated': True, 'user': 'u@d'}