From 76410afd9b8d4365156367d1ee945b935e10de4b Mon Sep 17 00:00:00 2001 From: Sasha Mitchell Date: Thu, 1 Oct 2026 18:18:12 +0700 Subject: [PATCH] Reject a comma in a URL scheme The scheme check used "+-." as a character range, so a comma was accepted. The error text only allows letters, digits, "+", "-", and ".". --- CHANGELOG.md | 1 + src/hyperlink/_url.py | 3 ++- src/hyperlink/test/test_url.py | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50f34c6a..25861187 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next +* A URL scheme no longer accepts a comma. `+-.` in the scheme check was a character range, so `,` sat between `+` and `.`. ([#199](https://github.com/python-hyper/hyperlink/issues/199)) * CPython 3.9 added to test matrix ## 21.0.0 diff --git a/src/hyperlink/_url.py b/src/hyperlink/_url.py index 8797b5cc..636a95c5 100644 --- a/src/hyperlink/_url.py +++ b/src/hyperlink/_url.py @@ -154,7 +154,8 @@ def __nonzero__(self): r"(\?(?P[^#]*))?" r"(#(?P.*))?$" ) -_SCHEME_RE = re.compile(r"^[a-zA-Z0-9+-.]*$") +# Hyphen is last so it is a literal. "+-." would be the range from "+" to ".". +_SCHEME_RE = re.compile(r"^[a-zA-Z0-9.+-]*$") _AUTHORITY_RE = re.compile( r"^(?:(?P[^@/?#]*)@)?" r"(?P" diff --git a/src/hyperlink/test/test_url.py b/src/hyperlink/test/test_url.py index 37c91726..ba72dcdd 100644 --- a/src/hyperlink/test/test_url.py +++ b/src/hyperlink/test/test_url.py @@ -1261,6 +1261,11 @@ def test_wrong_constructor(self): with self.assertRaises(ValueError): # explicitly bad scheme not allowed URL("HTTP_____more_like_imHoTTeP") + with self.assertRaises(ValueError): + # "+-." is not a range, so a comma is not a scheme character + URL(scheme="ht,tp") + with self.assertRaises(ValueError): + URL.from_text("ht,tp://example.com") def test_encoded_userinfo(self): # type: () -> None