From: Tom Christie Date: Tue, 11 Aug 2020 16:18:12 +0000 (+0100) Subject: Handle URL quoting username and password components. (#1159) X-Git-Tag: 0.14.2~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=655773e1c1b75895eda927d5a9d22a3b5b8f572d;p=thirdparty%2Fhttpx.git Handle URL quoting username and password components. (#1159) * Handle URL quoting username and password components * Tweak userinfo quoting --- diff --git a/httpx/_models.py b/httpx/_models.py index 8d294e7f..d6bc46e1 100644 --- a/httpx/_models.py +++ b/httpx/_models.py @@ -7,7 +7,7 @@ import urllib.request import warnings from collections.abc import MutableMapping from http.cookiejar import Cookie, CookieJar -from urllib.parse import parse_qsl, urlencode +from urllib.parse import parse_qsl, quote, unquote, urlencode import chardet import rfc3986 @@ -100,12 +100,12 @@ class URL: @property def username(self) -> str: userinfo = self._uri_reference.userinfo or "" - return userinfo.partition(":")[0] + return unquote(userinfo.partition(":")[0]) @property def password(self) -> str: userinfo = self._uri_reference.userinfo or "" - return userinfo.partition(":")[2] + return unquote(userinfo.partition(":")[2]) @property def host(self) -> str: @@ -175,8 +175,8 @@ class URL: ): host = kwargs.pop("host", self.host) port = kwargs.pop("port", self.port) - username = kwargs.pop("username", self.username) - password = kwargs.pop("password", self.password) + username = quote(kwargs.pop("username", self.username) or "") + password = quote(kwargs.pop("password", self.password) or "") authority = host if port is not None: @@ -193,7 +193,7 @@ class URL: def join(self, url: URLTypes) -> "URL": """ - Return an absolute URL, using given this URL as the base. + Return an absolute URL, using this URL as the base. """ if self.is_relative_url: return URL(url) diff --git a/tests/models/test_url.py b/tests/models/test_url.py index 19e07575..c4975a92 100644 --- a/tests/models/test_url.py +++ b/tests/models/test_url.py @@ -187,6 +187,18 @@ def test_url_copywith_for_authority(): assert str(new) == "https://username:password@example.net:444" +def test_url_copywith_for_userinfo(): + copy_with_kwargs = { + "username": "tom@example.org", + "password": "abc123@ %", + } + url = URL("https://example.org") + new = url.copy_with(**copy_with_kwargs) + assert str(new) == "https://tom%40example.org:abc123%40%20%25@example.org" + assert new.username == "tom@example.org" + assert new.password == "abc123@ %" + + def test_url_invalid(): with pytest.raises(InvalidURL): URL("https://😇/")