mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-03 06:35:31 +00:00
address jar spec change
This commit is contained in:
parent
8f0207a8f2
commit
9dec74fc4f
@ -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 {
|
||||
|
||||
|
||||
@ -44,11 +44,11 @@ import java.util.Locale;
|
||||
* Supported rule format:
|
||||
* <pre>
|
||||
* [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)
|
||||
* </pre>
|
||||
* <ul>
|
||||
* <li><b>scheme</b>: The URI scheme (e.g., http, https, ftp, file, jar, jrt).</li>
|
||||
* <li><b>host</b>: Domain name, IPv4, or IPv6 address. For local schemes ("file", "jar", "jrt"), host is omitted.</li>
|
||||
* <li><b>scheme</b>: The URI scheme (e.g., http, https, ftp, file, jrt).</li>
|
||||
* <li><b>host</b>: Domain name, IPv4, or IPv6 address. For local schemes ("file", "jrt"), host is omitted.</li>
|
||||
* <li><b>port</b>: (optional) Port number to match. If omitted, matches the default port for the scheme.</li>
|
||||
* <li><b>path-pattern</b>: (optional) Resource path. Supports wildcards (e.g., {@code /*}, {@code /dtds/*}).</li>
|
||||
* </ul>
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user