Skip to content

Commit

Permalink
fix: add file handling to URL fields
Browse files Browse the repository at this point in the history
Requires a modicum of special handling due to hostnames being
optional.

Fixes: Issue #2249
  • Loading branch information
0xDEC0DE committed Jan 21, 2025
1 parent 944f6de commit eca2725
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 1 deletion.
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,4 @@ Contributors (chronological)
- Peter C `@somethingnew2-0 <https://github.com/somethingnew2-0>`_
- Marcel Jackwerth `@mrcljx` <https://github.com/mrcljx>`_
- Fares Abubaker `@Fares-Abubaker <https://github.com/Fares-Abubaker>`_
- Nicolas Simonds `@0xDEC0DE <https://github.com/0xDEC0DE>`_
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ Features:
accept their internal value types as valid input (:issue:`1415`).
Thanks :user:`bitdancer` for the suggestion.

Bug Fixes:

- ``URL`` fields now properly validate ``file`` paths.

Other changes:

- Typing: `Field <marshmallow.fields.Field>` is now a generic type with a type argument for the internal value type.
Expand Down
11 changes: 10 additions & 1 deletion src/marshmallow/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def __call__(self, value: str) -> str:
raise ValidationError(message)

# Check first if the scheme is valid
scheme = None
if "://" in value:
scheme = value.split("://")[0].lower()
if scheme not in self.schemes:
Expand All @@ -212,7 +213,15 @@ def __call__(self, value: str) -> str:
relative=self.relative, absolute=self.absolute, require_tld=self.require_tld
)

if not regex.search(value):
# The `file` scheme is a slightly-special case: hostnames are optional,
# and if absent it means `localhost`; fill it in for the validation if
# needed
if scheme == "file" and value.startswith("file:///"):
matched = regex.search(value.replace("file:///", "file://localhost/", 1))
else:
matched = regex.search(value)

if not matched:
raise ValidationError(message)

return value
Expand Down
7 changes: 7 additions & 0 deletions tests/test_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ def test_url_custom_scheme():
assert validator(url) == url


def test_url_file_scheme():
# Ensure that file URLs don't get confused
url = "file:///tmp/tmp1234"
validator = validate.URL(schemes={"file"})
assert validator(url) == url


def test_url_relative_and_custom_schemes():
validator = validate.URL(relative=True)
# By default, ws not allowed
Expand Down

0 comments on commit eca2725

Please sign in to comment.