mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Allow URL resolution within nested JARs
Update JarURLConnection to allow the resolution of items within a nested jar, even if the jarFile passed to the connection is several levels up. This prevent a connection from incorrectly resolving an entry against the wrong jar file. See gh-1070
This commit is contained in:
parent
5de2661b43
commit
3d6c8a85f4
@ -83,7 +83,7 @@ public class Handler extends URLStreamHandler {
|
||||
return new JarURLConnection(url, this.jarFile);
|
||||
}
|
||||
try {
|
||||
return new JarURLConnection(url, getJarFileFromUrl(url));
|
||||
return new JarURLConnection(url, getRootJarFileFromUrl(url));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return openFallbackConnection(url, ex);
|
||||
@ -135,24 +135,14 @@ public class Handler extends URLStreamHandler {
|
||||
return (URLConnection) OPEN_CONNECTION_METHOD.invoke(handler, url);
|
||||
}
|
||||
|
||||
public JarFile getJarFileFromUrl(URL url) throws IOException {
|
||||
|
||||
public JarFile getRootJarFileFromUrl(URL url) throws IOException {
|
||||
String spec = url.getFile();
|
||||
|
||||
int separatorIndex = spec.indexOf(SEPARATOR);
|
||||
if (separatorIndex == -1) {
|
||||
throw new MalformedURLException("Jar URL does not contain !/ separator");
|
||||
}
|
||||
|
||||
JarFile jar = null;
|
||||
while (separatorIndex != -1) {
|
||||
String name = spec.substring(0, separatorIndex);
|
||||
jar = (jar == null ? getRootJarFile(name) : getNestedJarFile(jar, name));
|
||||
spec = spec.substring(separatorIndex + SEPARATOR.length());
|
||||
separatorIndex = spec.indexOf(SEPARATOR);
|
||||
}
|
||||
|
||||
return jar;
|
||||
String name = spec.substring(0, separatorIndex);
|
||||
return getRootJarFile(name);
|
||||
}
|
||||
|
||||
private JarFile getRootJarFile(String name) throws IOException {
|
||||
@ -175,15 +165,6 @@ public class Handler extends URLStreamHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private JarFile getNestedJarFile(JarFile jarFile, String name) throws IOException {
|
||||
JarEntry jarEntry = jarFile.getJarEntry(name);
|
||||
if (jarEntry == null) {
|
||||
throw new IOException("Unable to find nested jar '" + name + "' from '"
|
||||
+ jarFile + "'");
|
||||
}
|
||||
return jarFile.getNestedJarFile(jarEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given {@link JarFile} to the root file cache.
|
||||
* @param sourceFile the source file to add
|
||||
|
@ -61,8 +61,6 @@ class JarURLConnection extends java.net.JarURLConnection {
|
||||
|
||||
private static ThreadLocal<Boolean> useFastExceptions = new ThreadLocal<Boolean>();
|
||||
|
||||
private final String jarFileUrlSpec;
|
||||
|
||||
private final JarFile jarFile;
|
||||
|
||||
private JarEntryData jarEntryData;
|
||||
@ -71,19 +69,26 @@ class JarURLConnection extends java.net.JarURLConnection {
|
||||
|
||||
private JarEntryName jarEntryName;
|
||||
|
||||
protected JarURLConnection(URL url, JarFile jarFile) throws MalformedURLException {
|
||||
protected JarURLConnection(URL url, JarFile jarFile) throws IOException {
|
||||
// What we pass to super is ultimately ignored
|
||||
super(EMPTY_JAR_URL);
|
||||
this.url = url;
|
||||
this.jarFile = jarFile;
|
||||
String spec = url.getFile();
|
||||
int separator = spec.lastIndexOf(SEPARATOR);
|
||||
if (separator == -1) {
|
||||
throw new MalformedURLException("no " + SEPARATOR + " found in url spec:"
|
||||
+ spec);
|
||||
String spec = url.getFile().substring(jarFile.getUrl().getFile().length());
|
||||
int separator;
|
||||
while ((separator = spec.indexOf(SEPARATOR)) > 0) {
|
||||
jarFile = getNestedJarFile(jarFile, spec.substring(0, separator));
|
||||
spec = spec.substring(separator + SEPARATOR.length());
|
||||
}
|
||||
this.jarFileUrlSpec = spec.substring(0, separator);
|
||||
this.jarEntryName = getJarEntryName(spec.substring(separator + 2));
|
||||
this.jarFile = jarFile;
|
||||
this.jarEntryName = getJarEntryName(spec);
|
||||
}
|
||||
|
||||
private JarFile getNestedJarFile(JarFile jarFile, String name) throws IOException {
|
||||
JarEntry jarEntry = jarFile.getJarEntry(name);
|
||||
if (jarEntry == null) {
|
||||
throwFileNotFound(jarEntry, jarFile);
|
||||
}
|
||||
return jarFile.getNestedJarFile(jarEntry);
|
||||
}
|
||||
|
||||
private JarEntryName getJarEntryName(String spec) {
|
||||
@ -99,16 +104,20 @@ class JarURLConnection extends java.net.JarURLConnection {
|
||||
this.jarEntryData = this.jarFile.getJarEntryData(this.jarEntryName
|
||||
.asAsciiBytes());
|
||||
if (this.jarEntryData == null) {
|
||||
if (Boolean.TRUE.equals(useFastExceptions.get())) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
throw new FileNotFoundException("JAR entry " + this.jarEntryName
|
||||
+ " not found in " + this.jarFile.getName());
|
||||
throwFileNotFound(this.jarEntryName, this.jarFile);
|
||||
}
|
||||
}
|
||||
this.connected = true;
|
||||
}
|
||||
|
||||
private void throwFileNotFound(Object entry, JarFile jarFile) throws FileNotFoundException {
|
||||
if (Boolean.TRUE.equals(useFastExceptions.get())) {
|
||||
throw FILE_NOT_FOUND_EXCEPTION;
|
||||
}
|
||||
throw new FileNotFoundException("JAR entry " + entry + " not found in "
|
||||
+ jarFile.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
try {
|
||||
@ -135,10 +144,14 @@ class JarURLConnection extends java.net.JarURLConnection {
|
||||
|
||||
private URL buildJarFileUrl() {
|
||||
try {
|
||||
if (this.jarFileUrlSpec.indexOf(SEPARATOR) == -1) {
|
||||
return new URL(this.jarFileUrlSpec);
|
||||
String spec = this.jarFile.getUrl().getFile();
|
||||
if (spec.endsWith(SEPARATOR)) {
|
||||
spec = spec.substring(0, spec.length() - SEPARATOR.length());
|
||||
}
|
||||
return new URL("jar:" + this.jarFileUrlSpec);
|
||||
if (spec.indexOf(SEPARATOR) == -1) {
|
||||
return new URL(spec);
|
||||
}
|
||||
return new URL("jar:" + spec);
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
|
@ -16,21 +16,32 @@
|
||||
|
||||
package org.springframework.boot.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.jar.JarFile;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests for {@link LaunchedURLClassLoader}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public class LaunchedURLClassLoaderTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void resolveResourceFromWindowsFilesystem() throws Exception {
|
||||
// This path is invalid - it should return null even on Windows.
|
||||
@ -76,4 +87,17 @@ public class LaunchedURLClassLoaderTests {
|
||||
assertTrue(loader.getResources("").hasMoreElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveFromNested() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
TestJarCreator.createTestJar(file);
|
||||
JarFile jarFile = new JarFile(file);
|
||||
URL url = jarFile.getUrl();
|
||||
LaunchedURLClassLoader loader = new LaunchedURLClassLoader(new URL[] { url },
|
||||
null);
|
||||
URL resource = loader.getResource("nested.jar!/3.dat");
|
||||
assertThat(resource.toString(), equalTo(url + "nested.jar!/3.dat"));
|
||||
assertThat(resource.openConnection().getInputStream().read(), equalTo(3));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -408,4 +408,16 @@ public class JarFileTests {
|
||||
getEntries();
|
||||
getNestedJarFile();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotLoadMissingJar() throws Exception {
|
||||
// relates to gh-1070
|
||||
JarFile nestedJarFile = this.jarFile.getNestedJarFile(this.jarFile
|
||||
.getEntry("nested.jar"));
|
||||
URL nestedUrl = nestedJarFile.getUrl();
|
||||
URL url = new URL(nestedUrl, nestedJarFile.getUrl() + "missing.jar!/3.dat");
|
||||
this.thrown.expect(FileNotFoundException.class);
|
||||
url.openConnection().getInputStream();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user