]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Allow URLs where username or password contains unescaped '@'. (#2986)
authorTom Christie <tom@tomchristie.com>
Thu, 7 Dec 2023 10:08:14 +0000 (10:08 +0000)
committerGitHub <noreply@github.com>
Thu, 7 Dec 2023 10:08:14 +0000 (10:08 +0000)
* Add test cases for userinfo in URL

* Resolve failing test cases

* Update CHANGELOG.md

* Update CHANGELOG.md

CHANGELOG.md
httpx/_urlparse.py
tests/models/test_url.py

index 02ccc86a03522e8ce3cd716ef5d1e5c91d00d326..f81d973e4bf083155319d28671fbabfc84b3c1f8 100644 (file)
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## Unreleased
+
+### Fixed
+
+* Allow URLs where username or password contains unescaped '@'. (#2986)
+
 ## 0.25.2 (24th November, 2023)
 
 ### Added
index a9a0aecd9b3e4e80d3e09a8899854c4eeef4424f..c44e3519a032d96ad2abf086a214e79027a329cf 100644 (file)
@@ -62,8 +62,8 @@ AUTHORITY_REGEX = re.compile(
     (
         r"(?:(?P<userinfo>{userinfo})@)?" r"(?P<host>{host})" r":?(?P<port>{port})?"
     ).format(
-        userinfo="[^@]*",  # Any character sequence not including '@'.
-        host="(\\[.*\\]|[^:]*)",  # Either any character sequence not including ':',
+        userinfo=".*",  # Any character sequence.
+        host="(\\[.*\\]|[^:@]*)",  # Either any character sequence excluding ':' or '@',
         # or an IPv6 address enclosed within square brackets.
         port=".*",  # Any character sequence.
     )
index 34250e3830c89396a6b5e82e0c14c9de86971012..4683a321d6035c5891c65610ed7cc37fed6240a2 100644 (file)
@@ -132,6 +132,54 @@ def test_url_params():
     assert url.params == httpx.QueryParams({"a": "123"})
 
 
+# Tests for username and password
+
+
+@pytest.mark.parametrize(
+    "url,userinfo,username,password",
+    [
+        # username and password in URL.
+        (
+            "https://username:password@example.com",
+            b"username:password",
+            "username",
+            "password",
+        ),
+        # username and password in URL with percent escape sequences.
+        (
+            "https://username%40gmail.com:pa%20ssword@example.com",
+            b"username%40gmail.com:pa%20ssword",
+            "username@gmail.com",
+            "pa ssword",
+        ),
+        (
+            "https://user%20name:p%40ssword@example.com",
+            b"user%20name:p%40ssword",
+            "user name",
+            "p@ssword",
+        ),
+        # username and password in URL without percent escape sequences.
+        (
+            "https://username@gmail.com:pa ssword@example.com",
+            b"username%40gmail.com:pa%20ssword",
+            "username@gmail.com",
+            "pa ssword",
+        ),
+        (
+            "https://user name:p@ssword@example.com",
+            b"user%20name:p%40ssword",
+            "user name",
+            "p@ssword",
+        ),
+    ],
+)
+def test_url_username_and_password(url, userinfo, username, password):
+    url = httpx.URL(url)
+    assert url.userinfo == userinfo
+    assert url.username == username
+    assert url.password == password
+
+
 # Tests for different host types