Commit dfe6de8c authored by Phillip Webb's avatar Phillip Webb

Fallback to JVM URL handler on exception

Update the executable JAR `Handler` to fallback to the JVM handler if
the jar cannot be opened. This prevents exceptions when trying to
open URLs in the form "jar:jndi:/localhost...".

Fixes gh-347
parent 97c258a2
...@@ -18,10 +18,13 @@ package org.springframework.boot.loader.jar; ...@@ -18,10 +18,13 @@ package org.springframework.boot.loader.jar;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.net.URLStreamHandler; import java.net.URLStreamHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s. * {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s.
...@@ -38,8 +41,26 @@ public class Handler extends URLStreamHandler { ...@@ -38,8 +41,26 @@ public class Handler extends URLStreamHandler {
private static final String SEPARATOR = JarURLConnection.SEPARATOR; private static final String SEPARATOR = JarURLConnection.SEPARATOR;
private static final String[] FALLBACK_HANDLERS = { "sun.net.www.protocol.jar.Handler" };
private static final Method OPEN_CONNECTION_METHOD;
static {
Method method = null;
try {
method = URLStreamHandler.class
.getDeclaredMethod("openConnection", URL.class);
}
catch (Exception ex) {
}
OPEN_CONNECTION_METHOD = method;
}
private final Logger logger = Logger.getLogger(getClass().getName());
private final JarFile jarFile; private final JarFile jarFile;
private URLStreamHandler fallbackHandler;
public Handler() { public Handler() {
this(null); this(null);
} }
...@@ -50,8 +71,60 @@ public class Handler extends URLStreamHandler { ...@@ -50,8 +71,60 @@ public class Handler extends URLStreamHandler {
@Override @Override
protected URLConnection openConnection(URL url) throws IOException { protected URLConnection openConnection(URL url) throws IOException {
JarFile jarFile = (this.jarFile != null ? this.jarFile : getJarFileFromUrl(url)); if (this.jarFile != null) {
return new JarURLConnection(url, jarFile); return new JarURLConnection(url, this.jarFile);
}
try {
return new JarURLConnection(url, getJarFileFromUrl(url));
}
catch (Exception ex) {
return openFallbackConnection(url, ex);
}
}
private URLConnection openFallbackConnection(URL url, Exception reason)
throws IOException {
try {
return openConnection(getFallbackHandler(), url);
}
catch (Exception ex) {
this.logger.log(Level.WARNING, "Unable to open fallback handler", ex);
if (reason instanceof IOException) {
throw (IOException) reason;
}
if (reason instanceof RuntimeException) {
throw (RuntimeException) reason;
}
throw new IllegalStateException(reason);
}
}
private URLStreamHandler getFallbackHandler() {
if (this.fallbackHandler != null) {
return this.fallbackHandler;
}
for (String handlerClassName : FALLBACK_HANDLERS) {
try {
Class<?> handlerClass = Class.forName(handlerClassName);
this.fallbackHandler = (URLStreamHandler) handlerClass.newInstance();
return this.fallbackHandler;
}
catch (Exception ex) {
// Ignore
}
}
throw new IllegalStateException("Unable to find fallback handler");
}
private URLConnection openConnection(URLStreamHandler handler, URL url)
throws Exception {
if (OPEN_CONNECTION_METHOD == null) {
throw new IllegalStateException(
"Unable to invoke fallback open connection method");
}
OPEN_CONNECTION_METHOD.setAccessible(true);
return (URLConnection) OPEN_CONNECTION_METHOD.invoke(handler, url);
} }
public JarFile getJarFileFromUrl(URL url) throws IOException { public JarFile getJarFileFromUrl(URL url) throws IOException {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment