From ee5cf09ae8151fcf021e0e26f37a08d04a4743cc Mon Sep 17 00:00:00 2001 From: Sahana Bogar Date: Tue, 11 Aug 2026 23:35:12 +0530 Subject: [PATCH] compare the file scheme case-insensitively in isValid --- .../commons/validator/routines/UrlValidator.java | 7 +++++-- .../validator/routines/UrlValidatorTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/validator/routines/UrlValidator.java b/src/main/java/org/apache/commons/validator/routines/UrlValidator.java index 4d100dce0..3cead7bfe 100644 --- a/src/main/java/org/apache/commons/validator/routines/UrlValidator.java +++ b/src/main/java/org/apache/commons/validator/routines/UrlValidator.java @@ -384,12 +384,15 @@ public boolean isValid(final String value) { return false; } final String authority = uri.getRawAuthority(); + // URI schemes are case-insensitive (RFC 3986 3.1) and isValidScheme already matches case-blind, + // so the file: handling has to recognise the scheme case-blind too + final boolean fileScheme = "file".equalsIgnoreCase(scheme); // Special case - file: allows an empty authority, so only the authority check is skipped for it; // the path, query and fragment below are validated as they are for any other scheme - final boolean emptyFileAuthority = "file".equals(scheme) && GenericValidator.isBlankOrNull(authority); + final boolean emptyFileAuthority = fileScheme && GenericValidator.isBlankOrNull(authority); // Validate the authority if (!emptyFileAuthority - && ("file".equals(scheme) && authority != null && authority.contains(":") || !isValidAuthority(authority))) { + && (fileScheme && authority != null && authority.contains(":") || !isValidAuthority(authority))) { return false; } if (!isValidPath(uri.getRawPath()) || !isValidQuery(uri.getRawQuery()) || !isValidFragment(uri.getRawFragment())) { diff --git a/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java b/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java index c18fe7d99..735fa294d 100644 --- a/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java +++ b/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java @@ -173,6 +173,22 @@ void testFileSchemePath() { assertTrue(urlValidator.isValid("file:/C:/path/to/dir/")); } + @Test + void testFileSchemeCaseInsensitive() { + final String[] schemes = { "file" }; + final UrlValidator urlValidator = new UrlValidator(schemes, UrlValidator.ALLOW_LOCAL_URLS); + + // the scheme is case-insensitive, so an upper or mixed case file: URL is treated like the lower case form + assertTrue(urlValidator.isValid("file:///etc/hosts")); + assertTrue(urlValidator.isValid("FILE:///etc/hosts")); + assertTrue(urlValidator.isValid("File:///etc/hosts")); + + // a Windows drive letter in the authority is never valid, whatever the scheme case, and must not + // slip past the guard the lower case form is checked against + assertFalse(urlValidator.isValid("file://C:/some.file")); + assertFalse(urlValidator.isValid("FILE://C:/some.file")); + } + @Test void testFileSchemePathOptions() { final String[] schemes = { "file" };