Skip to content

Commit e0521fd

Browse files
committed
Accept file:// URLs per RFC 8089
url() rejected file:// URLs like file:///var/www because their authority (netloc) is empty or "localhost", neither of which _validate_netloc accepts as a hostname. RFC 8089 defines both an empty and a "localhost" authority as valid for a local file URL. A file URL with a non-local authority (file://example.com/path) still goes through the normal hostname check, unchanged.
1 parent 70de324 commit e0521fd

2 files changed

Lines changed: 31 additions & 10 deletions

File tree

‎src/validators/url.py‎

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def _validate_scheme(value: str):
4646
value
4747
# fmt: off
4848
in {
49+
"file",
4950
"ftp",
5051
"ftps",
5152
"git",
@@ -240,18 +241,25 @@ def url(
240241
except ValueError:
241242
return False
242243

244+
# RFC 8089: a "file" URL's authority is commonly empty or "localhost",
245+
# neither of which is a hostname `_validate_netloc` would accept.
246+
is_local_file = scheme == "file" and netloc in ("", "localhost")
247+
243248
return (
244249
validate_scheme(scheme)
245-
and _validate_netloc(
246-
netloc,
247-
skip_ipv6_addr,
248-
skip_ipv4_addr,
249-
may_have_port,
250-
simple_host,
251-
consider_tld,
252-
private,
253-
rfc_1034,
254-
rfc_2782,
250+
and (
251+
is_local_file
252+
or _validate_netloc(
253+
netloc,
254+
skip_ipv6_addr,
255+
skip_ipv4_addr,
256+
may_have_port,
257+
simple_host,
258+
consider_tld,
259+
private,
260+
rfc_1034,
261+
rfc_2782,
262+
)
255263
)
256264
and _validate_optionals(path, query, fragment, strict_query)
257265
)

‎tests/test_url.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,16 @@ def test_returns_failed_validation_on_invalid_url(value: str):
219219
def test_returns_failed_validation_on_invalid_private_url(value: str, private: Optional[bool]):
220220
"""Test returns failed validation on invalid private url."""
221221
assert isinstance(url(value, private=private), ValidationError)
222+
223+
224+
@pytest.mark.parametrize(
225+
"value",
226+
[
227+
"file:///var/www",
228+
"file:///C:/Windows",
229+
"file://localhost/var/www",
230+
],
231+
)
232+
def test_returns_string_for_valid_file_url(value: str):
233+
"""Test returns true on valid file url. Ref: RFC 8089."""
234+
assert url(value)

0 commit comments

Comments
 (0)