diff --git a/requests/adapters.py b/requests/adapters.py index 43addb1b..dd10e959 100644 --- a/requests/adapters.py +++ b/requests/adapters.py @@ -286,10 +286,6 @@ class HTTPAdapter(BaseAdapter): username, password = get_auth_from_url(proxy) if username and password: - # Proxy auth usernames and passwords will be urlencoded, we need - # to decode them. - username = unquote(username) - password = unquote(password) headers['Proxy-Authorization'] = _basic_auth_str(username, password) diff --git a/requests/utils.py b/requests/utils.py index 7a4d44d5..7b7ff0a7 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -634,12 +634,14 @@ def except_on_missing_scheme(url): def get_auth_from_url(url): """Given a url with authentication components, extract them into a tuple of username,password.""" - if url: - url = unquote(url) - parsed = urlparse(url) - return (parsed.username, parsed.password) - else: - return ('', '') + parsed = urlparse(url) + + try: + auth = (unquote(parsed.username), unquote(parsed.password)) + except (AttributeError, TypeError): + auth = ('', '') + + return auth def to_native_string(string, encoding='ascii'): diff --git a/test_requests.py b/test_requests.py index 1e8e723f..63897bb5 100755 --- a/test_requests.py +++ b/test_requests.py @@ -194,7 +194,7 @@ class RequestsTestCase(unittest.TestCase): assert r.json()['cookies']['foo'] == 'bar' # Make sure the session cj is still the custom one assert s.cookies is cj - + def test_param_cookiejar_works(self): cj = cookielib.CookieJar() cookiejar_from_dict({'foo' : 'bar'}, cj) @@ -702,9 +702,13 @@ class RequestsTestCase(unittest.TestCase): assert ('user', 'pass pass') == requests.utils.get_auth_from_url(url) def test_get_auth_from_url_percent_chars(self): - url = 'http://user%user:pass@complex.url.com/path?query=yes' + url = 'http://user%25user:pass@complex.url.com/path?query=yes' assert ('user%user', 'pass') == requests.utils.get_auth_from_url(url) + def test_get_auth_from_url_encoded_hashes(self): + url = 'http://user:pass%23pass@complex.url.com/path?query=yes' + assert ('user', 'pass#pass') == requests.utils.get_auth_from_url(url) + def test_cannot_send_unprepared_requests(self): r = requests.Request(url=HTTPBIN) with pytest.raises(ValueError): @@ -1092,6 +1096,16 @@ class UtilsTestCase(unittest.TestCase): assert address_in_network('192.168.1.1', '192.168.1.0/24') assert not address_in_network('172.16.0.1', '192.168.1.0/24') + def test_get_auth_from_url(self): + """ Ensures that username and password in well-encoded URI as per RFC 3986 are correclty extracted """ + from requests.utils import get_auth_from_url + from requests.compat import quote + percent_encoding_test_chars = "%!*'();:@&=+$,/?#[] " + url_address = "request.com/url.html#test" + url = "http://" + quote(percent_encoding_test_chars, '') + ':' + quote(percent_encoding_test_chars, '') + '@' + url_address + (username, password) = get_auth_from_url(url) + assert username == percent_encoding_test_chars + assert password == percent_encoding_test_chars class TestMorselToCookieExpires(unittest.TestCase):