Merge branch '1.4.x' into 1.5.x

pull/7225/merge
Phillip Webb 8 years ago
commit 3c5328924c

@ -34,6 +34,7 @@ import java.util.logging.Logger;
* {@link URLStreamHandler} for Spring Boot loader {@link JarFile}s.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @see JarFile#registerUrlProtocolHandler()
*/
public class Handler extends URLStreamHandler {
@ -41,6 +42,8 @@ public class Handler extends URLStreamHandler {
// NOTE: in order to be found as a URL protocol handler, this class must be public,
// must be named Handler and must be in a package ending '.jar'
private static final String JAR_PROTOCOL = "jar:";
private static final String FILE_PROTOCOL = "file:";
private static final String SEPARATOR = "!/";
@ -140,6 +143,85 @@ public class Handler extends URLStreamHandler {
return (URLConnection) OPEN_CONNECTION_METHOD.invoke(handler, url);
}
@Override
protected void parseURL(URL context, String spec, int start, int limit) {
if (spec.toLowerCase().startsWith(JAR_PROTOCOL)) {
setFile(context, getFileFromSpec(spec.substring(start, limit)));
}
else {
setFile(context, getFileFromContext(context, spec.substring(start, limit)));
}
}
private String getFileFromSpec(String spec) {
int separatorIndex = spec.lastIndexOf("!/");
if (separatorIndex == -1) {
throw new IllegalArgumentException("No !/ in spec '" + spec + "'");
}
try {
new URL(spec.substring(0, separatorIndex));
return spec;
}
catch (MalformedURLException ex) {
throw new IllegalArgumentException("Invalid spec URL '" + spec + "'", ex);
}
}
private String getFileFromContext(URL context, String spec) {
String file = context.getFile();
if (spec.startsWith("/")) {
return trimToJarRoot(file) + SEPARATOR + spec.substring(1);
}
if (file.endsWith("/")) {
return file + spec;
}
int lastSlashIndex = file.lastIndexOf('/');
if (lastSlashIndex == -1) {
throw new IllegalArgumentException(
"No / found in context URL's file '" + file + "'");
}
return file.substring(0, lastSlashIndex + 1) + spec;
}
private String trimToJarRoot(String file) {
int lastSeparatorIndex = file.lastIndexOf(SEPARATOR);
if (lastSeparatorIndex == -1) {
throw new IllegalArgumentException(
"No !/ found in context URL's file '" + file + "'");
}
return file.substring(0, lastSeparatorIndex);
}
private void setFile(URL context, String file) {
setURL(context, JAR_PROTOCOL, null, -1, null, null, file, null, null);
}
@Override
protected boolean sameFile(URL u1, URL u2) {
if (!u1.getProtocol().equals("jar") || u2.getProtocol().equals("jar")) {
return super.sameFile(u1, u2);
}
int separator1 = u1.getFile().indexOf(SEPARATOR);
int separator2 = u1.getFile().indexOf(SEPARATOR);
if (separator1 < 0 || separator2 < 0) {
return super.sameFile(u1, u2);
}
String root1 = u1.getFile().substring(separator1 + SEPARATOR.length());
String root2 = u2.getFile().substring(separator2 + SEPARATOR.length());
if (!root1.equals(root2)) {
return super.sameFile(u1, u2);
}
String nested1 = u1.getFile().substring(0, separator1);
String nested2 = u1.getFile().substring(0, separator2);
try {
return super.sameFile(new URL(nested1), new URL(nested2));
}
catch (MalformedURLException ex) {
// Continue
}
return super.sameFile(u1, u2);
}
public JarFile getRootJarFileFromUrl(URL url) throws IOException {
String spec = url.getFile();
int separatorIndex = spec.indexOf(SEPARATOR);

@ -0,0 +1,96 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.loader.jar;
import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link Handler}.
*
* @author Andy Wilkinson
*/
public class HandlerTests {
private final Handler handler = new Handler();
@Test
public void parseUrlWithJarRootContextAndAbsoluteSpecThatUsesContext()
throws MalformedURLException {
String spec = "/entry.txt";
URL context = createUrl("file:example.jar!/");
this.handler.parseURL(context, spec, 0, spec.length());
assertThat(context.toExternalForm()).isEqualTo("jar:file:example.jar!/entry.txt");
}
@Test
public void parseUrlWithDirectoryEntryContextAndAbsoluteSpecThatUsesContext()
throws MalformedURLException {
String spec = "/entry.txt";
URL context = createUrl("file:example.jar!/dir/");
this.handler.parseURL(context, spec, 0, spec.length());
assertThat(context.toExternalForm()).isEqualTo("jar:file:example.jar!/entry.txt");
}
@Test
public void parseUrlWithJarRootContextAndRelativeSpecThatUsesContext()
throws MalformedURLException {
String spec = "entry.txt";
URL context = createUrl("file:example.jar!/");
this.handler.parseURL(context, spec, 0, spec.length());
assertThat(context.toExternalForm()).isEqualTo("jar:file:example.jar!/entry.txt");
}
@Test
public void parseUrlWithDirectoryEntryContextAndRelativeSpecThatUsesContext()
throws MalformedURLException {
String spec = "entry.txt";
URL context = createUrl("file:example.jar!/dir/");
this.handler.parseURL(context, spec, 0, spec.length());
assertThat(context.toExternalForm())
.isEqualTo("jar:file:example.jar!/dir/entry.txt");
}
@Test
public void parseUrlWithFileEntryContextAndRelativeSpecThatUsesContext()
throws MalformedURLException {
String spec = "entry.txt";
URL context = createUrl("file:example.jar!/dir/file");
this.handler.parseURL(context, spec, 0, spec.length());
assertThat(context.toExternalForm())
.isEqualTo("jar:file:example.jar!/dir/entry.txt");
}
@Test
public void parseUrlWithSpecThatIgnoresContext() throws MalformedURLException {
JarFile.registerUrlProtocolHandler();
String spec = "jar:file:/other.jar!/nested!/entry.txt";
URL context = createUrl("file:example.jar!/dir/file");
this.handler.parseURL(context, spec, 0, spec.length());
assertThat(context.toExternalForm())
.isEqualTo("jar:jar:file:/other.jar!/nested!/entry.txt");
}
private URL createUrl(String file) throws MalformedURLException {
return new URL("jar", null, -1, file, this.handler);
}
}

@ -18,7 +18,6 @@ package org.springframework.boot.loader.jar;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;
import org.junit.Before;
@ -127,15 +126,14 @@ public class JarURLConnectionTests {
}
@Test
public void nestedJarNotFound() throws Exception {
URL url = new URL(
"jar:file:" + getAbsolutePath() + "!/nested.jar!/missing.jar!/1.dat");
public void connectionToEntryInNestedJarFromUrlThatUsesExistingUrlAsContext()
throws Exception {
URL url = new URL(new URL("jar", null, -1,
"file:" + getAbsolutePath() + "!/nested.jar!/", new Handler()), "/3.dat");
JarFile nested = this.jarFile
.getNestedJarFile(this.jarFile.getEntry("nested.jar"));
JarURLConnection connection = JarURLConnection.get(url, nested);
this.thrown.expect(FileNotFoundException.class);
this.thrown.expectMessage("JAR entry missing.jar not found in");
connection.connect();
assertThat(JarURLConnection.get(url, nested).getInputStream())
.hasSameContentAs(new ByteArrayInputStream(new byte[] { 3 }));
}
private String getAbsolutePath() {

Loading…
Cancel
Save