diff --git a/src/java.xml/share/classes/jdk/xml/internal/AccessRule.java b/src/java.xml/share/classes/jdk/xml/internal/AccessRule.java index e7895bfd015..7f718e5cd13 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/AccessRule.java +++ b/src/java.xml/share/classes/jdk/xml/internal/AccessRule.java @@ -382,19 +382,42 @@ public class AccessRule { return new PathPattern(pattern, true, false); } if (pattern.endsWith("/*")) { - return new PathPattern(pattern.substring(0, pattern.length() - 2), false, true); + return new PathPattern(normalizePath(pattern.substring(0, pattern.length() - 2)), false, true); } - return new PathPattern(pattern, false, false); + return new PathPattern(normalizePath(pattern), false, false); } public boolean matches(String testPath) { if (isAny) return true; if (testPath == null) return false; + testPath = normalizePath(testPath); if (isDirectory) { // Path starts with this directory return testPath.startsWith(pattern + "/") || testPath.equals(pattern); } return testPath.equals(pattern); } + + // Normalizes URI path for rule matching, consistent with URI.normalize(). + private static String normalizePath(String path) { + boolean absolute = path.startsWith("/"); + List segments = new ArrayList<>(); + for (String segment : path.split("/")) { + if (segment.isEmpty() || segment.equals(".")) { + continue; + } + if (segment.equals("..")) { + if (!segments.isEmpty()) { + segments.remove(segments.size() - 1); + } else if (!absolute) { + segments.add(segment); + } + } else { + segments.add(segment); + } + } + String normalizedPath = String.join("/", segments); + return absolute ? "/" + normalizedPath : normalizedPath; + } } } diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java index b507a331b85..583dd1d7788 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java @@ -63,6 +63,9 @@ public class AccessRuleTest { "http://www.oracle.com/dtds/example.dtd; http://subdomains.oracle.com/dtds/example.dtd", true), Arguments.of("file:/dtds/dtd1.dtd", "file:/dtds/dtd1.dtd", true), Arguments.of("file:/dtds/dtd1.dtd, file:/xsds/*", "file:/dtds/dtd1.dtd; file:/xsds/example.xsd", true), + Arguments.of("file:/dir/*", "file:/dir/child.dtd", true), + Arguments.of("file:/dir/*", "file:/dir/../foo.dtd; file:/dir/%2e%2e/foo.dtd", false), + Arguments.of("file:/*", "file:/dir/../../foo.dtd; file:/../foo.dtd", true), Arguments.of("http://www.oracle.com, file:/dtds/dtd1.dtd, file:/xsds/*", "http://www.oracle.com/dtds/example.dtd; file:/dtds/dtd1.dtd; file:/xsds/example.xsd", true), Arguments.of("http://[2001:db8::1]",