-
Bug
-
Resolution: Fixed
-
P3
-
11.0.2, 12
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8223755 | 11.0.5-oracle | Sean Coffey | P3 | Resolved | Fixed | b01 |
JDK-8227097 | 11.0.5 | Sean Coffey | P3 | Resolved | Fixed | b01 |
ADDITIONAL SYSTEM INFORMATION :
JDK 11.0.2
A DESCRIPTION OF THE PROBLEM :
java.net.URL.isOverrideable(String) for "jrt" or "file" returns false,
but custom URLStreamHandlerFactory can override URLStreamHandler for jrt or file protocol
providing the default URLStreamHandlerFactory.
In java.net.URL#getURLStreamHandler,
custom URLStreamHandler's createURLStreamHandler is invoked twice.
But the 2nd invocation does not check by isOverrideable(protocol).
So, custom URLStreamHandlerFactory can override URLStreamHandler for jrt or file protocol
providing the default URLStreamHandlerFactory.
==== the 1st invocation ====
if (isOverrideable(protocol) && jdk.internal.misc.VM.isBooted()) {
// Use the factory (if any). Volatile read makes
// URLStreamHandlerFactory appear fully initialized to current thread.
fac = factory;
if (fac != null) {
handler = fac.createURLStreamHandler(protocol);
checkedWithFactory = true;
}
if (handler == null && !protocol.equalsIgnoreCase("jar")) {
handler = lookupViaProviders(protocol);
}
if (handler == null) {
handler = lookupViaProperty(protocol);
}
}
==== the 2nd invocation ====
// Check with factory if another thread set a
// factory since our last check
if (!checkedWithFactory && (fac = factory) != null) {
handler2 = fac.createURLStreamHandler(protocol);
}
REGRESSION : Last worked in version 11.0.1
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the following test case to reproduce
java CustomURLStreamHandlerFactory jrt:/foo
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[output]
Default URLStreamHandler used for jrt:/foo
ACTUAL -
[output]
java.lang.RuntimeException: CustomURLStreamHandler used for jrt:/foo
at CustomURLStreamHandlerFactory$CustomURLStreamHandler.openConnection(CustomURLStreamHandlerFactory.java:13)
at java.base/java.net.URL.openConnection(URL.java:1051)
at CustomURLStreamHandlerFactory.main(CustomURLStreamHandlerFactory.java:22)
---------- BEGIN SOURCE ----------
import java.io.*;
import java.net.*;
public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
return new CustomURLStreamHandler();
}
private static class CustomURLStreamHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL u) throws IOException {
throw new RuntimeException("CustomURLStreamHandler used for " + u);
}
}
public static void main(String[] args) {
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
for (String url : args) {
try {
new URL(url).openConnection();
System.out.println("Default URLStreamHandler used for " + url);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
JDK 11.0.2
A DESCRIPTION OF THE PROBLEM :
java.net.URL.isOverrideable(String) for "jrt" or "file" returns false,
but custom URLStreamHandlerFactory can override URLStreamHandler for jrt or file protocol
providing the default URLStreamHandlerFactory.
In java.net.URL#getURLStreamHandler,
custom URLStreamHandler's createURLStreamHandler is invoked twice.
But the 2nd invocation does not check by isOverrideable(protocol).
So, custom URLStreamHandlerFactory can override URLStreamHandler for jrt or file protocol
providing the default URLStreamHandlerFactory.
==== the 1st invocation ====
if (isOverrideable(protocol) && jdk.internal.misc.VM.isBooted()) {
// Use the factory (if any). Volatile read makes
// URLStreamHandlerFactory appear fully initialized to current thread.
fac = factory;
if (fac != null) {
handler = fac.createURLStreamHandler(protocol);
checkedWithFactory = true;
}
if (handler == null && !protocol.equalsIgnoreCase("jar")) {
handler = lookupViaProviders(protocol);
}
if (handler == null) {
handler = lookupViaProperty(protocol);
}
}
==== the 2nd invocation ====
// Check with factory if another thread set a
// factory since our last check
if (!checkedWithFactory && (fac = factory) != null) {
handler2 = fac.createURLStreamHandler(protocol);
}
REGRESSION : Last worked in version 11.0.1
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the following test case to reproduce
java CustomURLStreamHandlerFactory jrt:/foo
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
[output]
Default URLStreamHandler used for jrt:/foo
ACTUAL -
[output]
java.lang.RuntimeException: CustomURLStreamHandler used for jrt:/foo
at CustomURLStreamHandlerFactory$CustomURLStreamHandler.openConnection(CustomURLStreamHandlerFactory.java:13)
at java.base/java.net.URL.openConnection(URL.java:1051)
at CustomURLStreamHandlerFactory.main(CustomURLStreamHandlerFactory.java:22)
---------- BEGIN SOURCE ----------
import java.io.*;
import java.net.*;
public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
return new CustomURLStreamHandler();
}
private static class CustomURLStreamHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL u) throws IOException {
throw new RuntimeException("CustomURLStreamHandler used for " + u);
}
}
public static void main(String[] args) {
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
for (String url : args) {
try {
new URL(url).openConnection();
System.out.println("Default URLStreamHandler used for " + url);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
- backported by
-
JDK-8223755 Custom URLStreamHandler for jrt or file protocol can override default handler.
- Resolved
-
JDK-8227097 Custom URLStreamHandler for jrt or file protocol can override default handler.
- Resolved
- relates to
-
JDK-8213942 URLStreamHandler initialization race
- Closed