8174151: URLClassLoader no longer uses custom URLStreamHandler for jar URLs
Reviewed-by: alanb, chegar
--- a/jdk/src/java.base/share/classes/java/net/URL.java Tue Feb 14 13:20:48 2017 -0800
+++ b/jdk/src/java.base/share/classes/java/net/URL.java Tue Feb 14 14:29:58 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,8 @@
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
+import jdk.internal.misc.JavaNetURLAccess;
+import jdk.internal.misc.SharedSecrets;
import sun.security.util.SecurityConstants;
import sun.security.action.GetPropertyAction;
@@ -1614,6 +1616,17 @@
private void setSerializedHashCode(int hc) {
this.hashCode = hc;
}
+
+ static {
+ SharedSecrets.setJavaNetURLAccess(
+ new JavaNetURLAccess() {
+ @Override
+ public URLStreamHandler getHandler(URL u) {
+ return u.handler;
+ }
+ }
+ );
+ }
}
final class UrlDeserializedState {
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java Tue Feb 14 13:20:48 2017 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java Tue Feb 14 14:29:58 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,6 +65,8 @@
import java.util.jar.Attributes.Name;
import java.util.zip.ZipFile;
+import jdk.internal.misc.JavaNetURLAccess;
+import jdk.internal.misc.JavaNetURLClassLoaderAccess;
import jdk.internal.misc.JavaUtilZipFileAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.util.jar.InvalidJarIndexError;
@@ -346,7 +348,7 @@
* path. The URLs are opened and expanded as needed. Returns null
* if the specified index is out of range.
*/
- private synchronized Loader getLoader(int index) {
+ private synchronized Loader getLoader(int index) {
if (closed) {
return null;
}
@@ -404,31 +406,40 @@
private Loader getLoader(final URL url) throws IOException {
try {
return java.security.AccessController.doPrivileged(
- new java.security.PrivilegedExceptionAction<>() {
- public Loader run() throws IOException {
- String protocol = url.getProtocol(); // lower cased in URL
- String file = url.getFile();
- if ("jar".equals(protocol)
- && file != null && (file.indexOf("!/") == file.length() - 2)) {
- // extract the nested URL
- URL nestedUrl = new URL(file.substring(0, file.length() - 2));
- return new JarLoader(nestedUrl, jarHandler, lmap, acc);
- } else if (file != null && file.endsWith("/")) {
- if ("file".equals(protocol)) {
- return new FileLoader(url);
- } else {
- return new Loader(url);
+ new java.security.PrivilegedExceptionAction<>() {
+ public Loader run() throws IOException {
+ String protocol = url.getProtocol(); // lower cased in URL
+ String file = url.getFile();
+ if (file != null && file.endsWith("/")) {
+ if ("file".equals(protocol)) {
+ return new FileLoader(url);
+ } else if ("jar".equals(protocol) &&
+ isDefaultJarHandler(url) &&
+ file.endsWith("!/")) {
+ // extract the nested URL
+ URL nestedUrl = new URL(file.substring(0, file.length() - 2));
+ return new JarLoader(nestedUrl, jarHandler, lmap, acc);
+ } else {
+ return new Loader(url);
+ }
+ } else {
+ return new JarLoader(url, jarHandler, lmap, acc);
+ }
}
- } else {
- return new JarLoader(url, jarHandler, lmap, acc);
- }
- }
- }, acc);
+ }, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (IOException)pae.getException();
}
}
+ private static final JavaNetURLAccess JNUA
+ = SharedSecrets.getJavaNetURLAccess();
+
+ private static boolean isDefaultJarHandler(URL u) {
+ URLStreamHandler h = JNUA.getHandler(u);
+ return h instanceof sun.net.www.protocol.jar.Handler;
+ }
+
/*
* Pushes the specified URLs onto the list of unopened URLs.
*/
@@ -493,7 +504,7 @@
}
/**
- * Inner class used to represent a loader of resources and classes
+ * Nested class used to represent a loader of resources and classes
* from a base URL.
*/
private static class Loader implements Closeable {
@@ -600,7 +611,8 @@
* close this loader and release all resources
* method overridden in sub-classes
*/
- public void close () throws IOException {
+ @Override
+ public void close() throws IOException {
if (jarfile != null) {
jarfile.close();
}
@@ -615,7 +627,7 @@
}
/*
- * Inner class used to represent a Loader of resources from a JAR URL.
+ * Nested class class used to represent a Loader of resources from a JAR URL.
*/
static class JarLoader extends Loader {
private JarFile jar;
@@ -798,7 +810,7 @@
/*
- * Returns true iff atleast one resource in the jar file has the same
+ * Returns true iff at least one resource in the jar file has the same
* package name as that of the specified resource name.
*/
boolean validIndex(final String name) {
@@ -826,6 +838,7 @@
/*
* Returns the URL for a resource with the specified name
*/
+ @Override
URL findResource(final String name, boolean check) {
Resource rsc = getResource(name, check);
if (rsc != null) {
@@ -837,6 +850,7 @@
/*
* Returns the JAR Resource for the specified name.
*/
+ @Override
Resource getResource(final String name, boolean check) {
try {
ensureOpen();
@@ -863,7 +877,6 @@
*/
Resource getResource(final String name, boolean check,
Set<String> visited) {
-
Resource res;
String[] jarFiles;
int count = 0;
@@ -919,7 +932,6 @@
continue;
}
-
/* Note that the addition of the url to the list of visited
* jars incorporates a check for presence in the hashmap
*/
@@ -975,6 +987,7 @@
/*
* Returns the JAR file local class path, or null if none.
*/
+ @Override
URL[] getClassPath() throws IOException {
if (index != null) {
return null;
@@ -1002,7 +1015,7 @@
* Parses value of the Class-Path manifest attribute and returns
* an array of URLs relative to the specified base URL.
*/
- private URL[] parseClassPath(URL base, String value)
+ private static URL[] parseClassPath(URL base, String value)
throws MalformedURLException
{
StringTokenizer st = new StringTokenizer(value);
@@ -1018,7 +1031,7 @@
}
/*
- * Inner class used to represent a loader of classes and resources
+ * Nested class used to represent a loader of classes and resources
* from a file URL that refers to a directory.
*/
private static class FileLoader extends Loader {
@@ -1038,6 +1051,7 @@
/*
* Returns the URL for a resource with the specified name
*/
+ @Override
URL findResource(final String name, boolean check) {
Resource rsc = getResource(name, check);
if (rsc != null) {
@@ -1046,6 +1060,7 @@
return null;
}
+ @Override
Resource getResource(final String name, boolean check) {
final URL url;
try {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaNetURLAccess.java Tue Feb 14 14:29:58 2017 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.misc;
+
+import java.net.URL;
+import java.net.URLStreamHandler;
+
+public interface JavaNetURLAccess {
+ URLStreamHandler getHandler(URL u);
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Tue Feb 14 13:20:48 2017 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Tue Feb 14 14:29:58 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -58,6 +58,7 @@
private static JavaNetHttpCookieAccess javaNetHttpCookieAccess;
private static JavaNetSocketAccess javaNetSocketAccess;
private static JavaNetUriAccess javaNetUriAccess;
+ private static JavaNetURLAccess javaNetURLAccess;
private static JavaNetURLClassLoaderAccess javaNetURLClassLoaderAccess;
private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
@@ -146,6 +147,16 @@
return javaNetUriAccess;
}
+ public static void setJavaNetURLAccess(JavaNetURLAccess jnua) {
+ javaNetURLAccess = jnua;
+ }
+
+ public static JavaNetURLAccess getJavaNetURLAccess() {
+ if (javaNetURLAccess == null)
+ unsafe.ensureClassInitialized(java.net.URL.class);
+ return javaNetURLAccess;
+ }
+
public static void setJavaNetURLClassLoaderAccess(JavaNetURLClassLoaderAccess jnua) {
javaNetURLClassLoaderAccess = jnua;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/URL/JarHandlerPkgPrefix/JarHandlerPkgPrefix.java Tue Feb 14 14:29:58 2017 -0800
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import handlers.jar.Handler;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * @test
+ * @bug 8174151
+ * @summary Test for java.protocol.handler.pkgs with jar protocol handler
+ * @library /lib/testlibrary/java/util/jar
+ * @compile handlers/jar/Handler.java
+ * @run main/othervm -Djava.protocol.handler.pkgs=handlers JarHandlerPkgPrefix
+ */
+public class JarHandlerPkgPrefix {
+
+ static void createJar(Path p) throws Exception {
+ JarBuilder jb = new JarBuilder(p.toString());
+ jb.addEntry("resource.txt", "CONTENTS".getBytes());
+ jb.build();
+ }
+
+ public static void main(String[] args) throws Exception {
+ Path jarPath = Paths.get(System.getProperty("user.dir", "."), "test.jar");
+ try {
+ createJar(jarPath);
+
+ URL j = new URL("jar:file:" + jarPath.toString() + "!/");
+ URLClassLoader ucl = new URLClassLoader(new URL[]{j});
+ ucl.findResource("resource.txt");
+
+ URL r = new URL("jar:file:" + jarPath.toString() + "!/resource.txt");
+ if (!Handler.URLS.contains(r))
+ throw new AssertionError("jar: URL handler not invoked");
+ }
+ finally {
+ Files.delete(jarPath);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/URL/JarHandlerPkgPrefix/handlers/jar/Handler.java Tue Feb 14 14:29:58 2017 -0800
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package handlers.jar;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class Handler extends URLStreamHandler {
+ public static Set<URL> URLS = Collections.synchronizedSet(new HashSet<>());
+
+ @Override
+ protected URLConnection openConnection(URL u) throws IOException {
+ URLS.add(u);
+ return null;
+ }
+}