diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index 75f7d5216c7..db598c6c356 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -93,7 +93,7 @@ import org.xml.sax.InputSource;
* @author K.Venugopal SUN Microsystems
* @author Neeraj Bajaj SUN Microsystems
* @author Sunitha Reddy SUN Microsystems
- * @LastModified: May 2025
+ * @LastModified: July 2026
*/
public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
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 87af7c23994..e7895bfd015 100644
--- a/src/java.xml/share/classes/jdk/xml/internal/AccessRule.java
+++ b/src/java.xml/share/classes/jdk/xml/internal/AccessRule.java
@@ -44,11 +44,11 @@ import java.util.Locale;
* Supported rule format:
*
* [scheme]://host[:port][/path-pattern]
- * [scheme]:/[path-pattern] (for local schemes such as file, jar, jrt)
+ * [scheme]:/[path-pattern] (for local schemes such as file and jrt)
*
*
- * - scheme: The URI scheme (e.g., http, https, ftp, file, jar, jrt).
- * - host: Domain name, IPv4, or IPv6 address. For local schemes ("file", "jar", "jrt"), host is omitted.
+ * - scheme: The URI scheme (e.g., http, https, ftp, file, jrt).
+ * - host: Domain name, IPv4, or IPv6 address. For local schemes ("file", "jrt"), host is omitted.
* - port: (optional) Port number to match. If omitted, matches the default port for the scheme.
* - path-pattern: (optional) Resource path. Supports wildcards (e.g., {@code /*}, {@code /dtds/*}).
*
@@ -129,28 +129,11 @@ public class AccessRule {
private final HostPattern hostPattern;
private final Integer port; // null if not set
private final PathPattern pathPattern;
- // for scheme==jar
- private final URIPatternRule jarBaseRule;
- private final PathPattern jarEntryPathPattern;
-
- // Constructor for schemes other than jar
private URIPatternRule(String scheme, HostPattern hostPattern, Integer port, PathPattern pathPattern) {
this.scheme = scheme;
this.hostPattern = hostPattern;
this.port = port;
this.pathPattern = pathPattern;
- this.jarBaseRule = null;
- this.jarEntryPathPattern = null;
- }
-
- // Constructor for jar patterns
- public URIPatternRule(URIPatternRule jarBaseRule, PathPattern jarEntryPathPattern) {
- this.scheme = "jar";
- this.hostPattern = null;
- this.port = null;
- this.pathPattern = null;
- this.jarBaseRule = jarBaseRule;
- this.jarEntryPathPattern = jarEntryPathPattern;
}
/**
@@ -169,36 +152,6 @@ public class AccessRule {
if (!isSupportedScheme(scheme))
throw new IllegalArgumentException("Unsupported scheme in resource access pattern: " + pattern);
- if ("jar".equals(scheme)) {
- int exclIdx = pattern.indexOf('!', scheme.length() + 1);
- String nestedPart, entryPart;
- boolean isLocalScheme = false;
- if (exclIdx < 0) {
- nestedPart = pattern.substring(scheme.length() + 1); // after "jar:"
- entryPart = null;
- isLocalScheme = nestedPart.startsWith("file") || nestedPart.startsWith("jar") || nestedPart.startsWith("jrt");
- } else {
- nestedPart = pattern.substring(scheme.length() + 1, exclIdx);
- entryPart = pattern.substring(exclIdx + 1);
- }
-
- // Check for illegal forms
- if (Utils.isEmpty(nestedPart) && Utils.isNotEmpty(entryPart))
- throw new IllegalArgumentException("Invalid JAR rule: entry pattern present but missing jar base: " + pattern);
- if (!isLocalScheme && Utils.isEmpty(entryPart) && Utils.isNotEmptyOrWildcard(nestedPart))
- throw new IllegalArgumentException("Invalid JAR rule: entry pattern is empty: " + pattern);
-
- URIPatternRule jarBaseRule = null;
- if (Utils.isNotEmptyOrWildcard(nestedPart)) {
- jarBaseRule = URIPatternRule.parse(nestedPart);
- }
- PathPattern jarEntryPathPattern = (entryPart == null || entryPart.isEmpty() || entryPart.equals("/*") || entryPart.equals("*"))
- ? PathPattern.of("*")
- : PathPattern.of(entryPart.startsWith("/") ? entryPart : "/" + entryPart);
-
- return new URIPatternRule(jarBaseRule, jarEntryPathPattern);
- }
-
String rest = pattern.substring(schemeSep + 1);
// Remove up to 3 leading slashes
String afterSlashes;
@@ -206,8 +159,8 @@ public class AccessRule {
HostPattern hostPattern = null;
Integer port = null;
PathPattern pathPattern = null;
- // Handle file/jar/jrt schemes as path patterns
- boolean isLocalScheme = scheme.equals("file") || scheme.equals("jar") || scheme.equals("jrt");
+ // Handle file and jrt schemes as path patterns.
+ boolean isLocalScheme = scheme.equals("file") || scheme.equals("jrt");
if (isLocalScheme) {
// Remove up to 3 leading slashes
afterSlashes = rest.replaceFirst("^/{0,3}", "");
@@ -243,6 +196,9 @@ public class AccessRule {
throw new IllegalArgumentException("Host must not be blank for scheme: " + scheme);
// Port
int portSep = hostPart.lastIndexOf(':');
+ if (portSep == hostPart.length() - 1) {
+ throw new IllegalArgumentException("Empty port: " + pattern);
+ }
if (portSep > 0 && portSep < hostPart.length() - 1
&& isPortNumber(hostPart.substring(portSep + 1))) {
hostPattern = HostPattern.of(hostPart.substring(0, portSep));
@@ -272,27 +228,17 @@ public class AccessRule {
}
public boolean matches(URI uri) {
- if (uri == null) return false;
+ if (uri != null && "jar".equalsIgnoreCase(uri.getScheme())) {
+ URI jarFile = getJarFileURI(uri);
+ return jarFile != null && matches(jarFile);
+ }
+
+ // Resource access matching applies only to hierarchical URIs. Opaque URIs
+ // have no hierarchical host/port/path components to match.
+ if (uri == null || uri.isOpaque()) return false;
String testScheme = uri.getScheme();
if (testScheme == null || !testScheme.equalsIgnoreCase(scheme)) return false;
- if ("jar".equalsIgnoreCase(testScheme)) {
- String ssp = uri.getSchemeSpecificPart();
- int exclIdx = ssp.indexOf("!/");
- String basePart, entryPart;
- if (exclIdx < 0) {
- basePart = ssp;
- entryPart = "";
- } else {
- basePart = ssp.substring(0, exclIdx);
- entryPart = ssp.substring(exclIdx + 1); // may be empty
- }
- URI baseUri = URI.create(basePart);
- boolean baseMatches = (jarBaseRule == null) || jarBaseRule.matches(baseUri); // wildcard/null means match any
- boolean entryMatches = jarEntryPathPattern == null || jarEntryPathPattern.matches(entryPart); // always at least "/*"
- return baseMatches && entryMatches;
- }
-
// Local: path-pattern match only
if (hostPattern == null) {
if (pathPattern == null) return true; // match all local of that scheme
@@ -312,9 +258,22 @@ public class AccessRule {
return true;
}
+ private static URI getJarFileURI(URI jarURI) {
+ String schemeSpecificPart = jarURI.getRawSchemeSpecificPart();
+ int separator = schemeSpecificPart.indexOf("!/");
+ if (separator < 0) {
+ return null;
+ }
+ try {
+ return URI.create(schemeSpecificPart.substring(0, separator));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
private static boolean isSupportedScheme(String scheme) {
return switch (scheme) {
- case "http", "https", "ftp", "file", "jar", "jrt" -> true;
+ case "http", "https", "ftp", "file", "jrt" -> true;
default -> false;
};
}
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 0513896a7f6..b507a331b85 100644
--- a/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
+++ b/test/jaxp/javax/xml/jaxp/unittest/common/access/AccessRuleTest.java
@@ -71,8 +71,9 @@ public class AccessRuleTest {
Arguments.of("http://[2001:0db8:0000:0000:0000:0000:0000:0001]",
"http://[2001:db8::1]/dtds/example.dtd", true),
Arguments.of("jrt:*; jrt:/java.xml/*", "jrt:/java.xml/jdk/xml/internal/jdkcatalog/JDKCatalog.xml", true),
- Arguments.of("jar:file:/tmp/foo.jar; jar:file:/tmp/foo.jar!/dtds/*", "jar:file:/tmp/foo.jar!/dtds/example.dtd", true),
- Arguments.of("jar:*; jar:file:*", "jar:file://all.file.access", true)
+ Arguments.of("file:/tmp/foo.jar",
+ "jar:file:/tmp/foo.jar!/dtds/example.dtd; jar:file:/tmp/foo.jar!/xsds/example.xsd", true),
+ Arguments.of("file:/tmp/foo.jar", "jar:file:/tmp/bar.jar!/dtds/example.dtd", false)
);
}
@@ -90,9 +91,11 @@ public class AccessRuleTest {
Arguments.of("http", IllegalArgumentException.class),
Arguments.of("http:", IllegalArgumentException.class),
Arguments.of("http://:8080", IllegalArgumentException.class),
+ Arguments.of("http://example.com:", IllegalArgumentException.class),
Arguments.of("http:///dtds", IllegalArgumentException.class),
Arguments.of("http://example.com, , file:*", IllegalArgumentException.class),
- Arguments.of("http://example.com, *, file:*", IllegalArgumentException.class)
+ Arguments.of("http://example.com, *, file:*", IllegalArgumentException.class),
+ Arguments.of("jar:file:/tmp/foo.jar!/dtds/*", IllegalArgumentException.class)
);
}