From 07369db39460ce0dd3ad9d6a971717266f29495c Mon Sep 17 00:00:00 2001 From: apoorvdarshan Date: Sat, 4 Jul 2026 22:55:49 +0530 Subject: [PATCH] Anchor is_valid_scheme regex so invalid schemes are rejected is_valid_scheme matched with re.match against an unanchored pattern, so any string whose prefix looked like a scheme was accepted -- e.g. furl('a b:c').scheme returned 'a b' instead of None, corrupting the parse. Anchor the pattern with ^...$ like the module's other validators, and add 0-9 to the character class (valid in schemes per RFC 3986) so digit-bearing schemes such as 'ws2' keep parsing. Fixes #192. --- furl/furl.py | 2 +- tests/test_furl.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/furl/furl.py b/furl/furl.py index cd6d710..67c275c 100644 --- a/furl/furl.py +++ b/furl/furl.py @@ -223,7 +223,7 @@ def is_valid_encoded_query_value(value): return is_valid_encoded_query_value.regex.match(value) is not None -@static_vars(regex=re.compile(r'[a-zA-Z][a-zA-Z\-\.\+]*')) +@static_vars(regex=re.compile(r'^[a-zA-Z][a-zA-Z0-9\-\.\+]*$')) def is_valid_scheme(scheme): return is_valid_scheme.regex.match(scheme) is not None diff --git a/tests/test_furl.py b/tests/test_furl.py index bc268c8..8c1167c 100644 --- a/tests/test_furl.py +++ b/tests/test_furl.py @@ -1290,6 +1290,17 @@ def test_scheme(self): assert furl.furl('+invalid$scheme://lolsup').scheme is None assert furl.furl('/api/test?url=http://a.com').scheme is None + # A prefix that looks like a scheme isn't one: the scheme regex must be + # anchored at both ends, so a ':' after invalid scheme characters + # doesn't get mis-parsed as a scheme separator. + f = furl.furl('a b:c') + assert f.scheme is None and str(f.path) == 'a%20b:c' + assert furl.furl('foo bar:baz').scheme is None + + # Digits are valid in schemes (RFC 3986) and must still parse. + assert furl.furl('ws2://host').scheme == 'ws2' + assert furl.furl('a1b://host').scheme == 'a1b' + # Empty scheme. f = furl.furl(':') assert f.scheme == '' and f.netloc is None and f.url == ':'