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 6395f2d92..5c6b9059e 100644 --- a/src/main/java/org/apache/commons/validator/routines/UrlValidator.java +++ b/src/main/java/org/apache/commons/validator/routines/UrlValidator.java @@ -118,8 +118,9 @@ public class UrlValidator implements Serializable { // TODO does not allow for optional userinfo. // Validation of character set is done by isValidAuthority private static final String AUTHORITY_CHARS_REGEX = "\\p{Alnum}\\-\\."; // allows for IPV4 but not IPV6 - // Allow for IPv4 mapped addresses: ::FFF:123.123.123.123 - private static final String IPV6_REGEX = "::FFFF:(?:\\d{1,3}\\.){3}\\d{1,3}|[0-9a-fA-F:]+"; // do this as separate match because : could cause ambiguity with port prefix + // Captured inside [ ] in AUTHORITY_REGEX and validated by InetAddressValidator.isValidInet6Address, so the + // dot is allowed for IPv4-mapped/embedded forms (for example ::ffff:1.2.3.4 or 2001:db8::1.2.3.4), not just ::FFFF: + private static final String IPV6_REGEX = "[0-9a-fA-F:.]+"; // the brackets remove the port-prefix ':' ambiguity // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 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 169e17bf7..8c92c2faa 100644 --- a/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java +++ b/src/test/java/org/apache/commons/validator/routines/UrlValidatorTest.java @@ -624,6 +624,18 @@ void testValidator452() { assertTrue(urlValidator.isValid("http://[::FFFF:129.144.52.38]:80/index.html")); } + @Test + void testIpv6EmbeddedIpv4() { + final UrlValidator urlValidator = new UrlValidator(); + // ::FFFF: in upper case already worked (testValidator452); the lower-case mapped form + // and the other IPv4-embedded notations must validate the same way. + assertTrue(urlValidator.isValid("http://[::ffff:129.144.52.38]:80/index.html")); + assertTrue(urlValidator.isValid("http://[::1.2.3.4]/")); + assertTrue(urlValidator.isValid("http://[2001:db8::1.2.3.4]/")); + // an embedded IPv4 part with an out-of-range octet is still rejected + assertFalse(urlValidator.isValid("http://[::ffff:129.144.52.999]/")); + } + @Test void testValidator464() { final String[] schemes = { "file" };