diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java index 4a64223cc03..917f35706d7 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/Handler.java @@ -203,7 +203,34 @@ public class Handler extends URLStreamHandler { } private void setFile(URL context, String file) { - setURL(context, JAR_PROTOCOL, null, -1, null, null, file, null, null); + setURL(context, JAR_PROTOCOL, null, -1, null, null, normalize(file), null, null); + } + + private String normalize(String file) { + int afterLastSeparatorIndex = file.lastIndexOf(SEPARATOR) + SEPARATOR.length(); + String afterSeparator = file.substring(afterLastSeparatorIndex); + afterSeparator = replaceParentDir(afterSeparator); + afterSeparator = replaceCurrentDir(afterSeparator); + return file.substring(0, afterLastSeparatorIndex) + afterSeparator; + } + + private String replaceParentDir(String file) { + int parentDirIndex; + while ((parentDirIndex = file.indexOf("/../")) >= 0) { + int precedingSlashIndex = file.lastIndexOf('/', parentDirIndex - 1); + if (precedingSlashIndex >= 0) { + file = file.substring(0, precedingSlashIndex) + + file.substring(parentDirIndex + 3); + } + else { + file = file.substring(parentDirIndex + 4); + } + } + return file; + } + + private String replaceCurrentDir(String file) { + return file.replace("/./", "/"); } @Override diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/HandlerTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/HandlerTests.java index 2fc34b35b10..4744e94199f 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/HandlerTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/HandlerTests.java @@ -136,6 +136,36 @@ public class HandlerTests { new URL("jar:file:/test.jar!/BOOT-INF/classes/foo.txt"))); } + @Test + public void urlWithSpecReferencingParentDirectory() throws MalformedURLException { + assertStandardAndCustomHandlerUrlsAreEqual( + "file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd", + "../folderB/b.xsd"); + } + + @Test + public void urlWithSpecReferencingAncestorDirectoryOutsideJarStopsAtJarRoot() + throws MalformedURLException { + assertStandardAndCustomHandlerUrlsAreEqual( + "file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd", + "../../../../../../folderB/b.xsd"); + } + + @Test + public void urlWithSpecReferencingCurrentDirectory() throws MalformedURLException { + assertStandardAndCustomHandlerUrlsAreEqual( + "file:/test.jar!/BOOT-INF/classes!/xsd/folderA/a.xsd", + "./folderB/./b.xsd"); + } + + private void assertStandardAndCustomHandlerUrlsAreEqual(String context, String spec) + throws MalformedURLException { + URL standardUrl = new URL(new URL("jar:" + context), spec); + URL customHandlerUrl = new URL(new URL("jar", null, -1, context, this.handler), + spec); + assertThat(customHandlerUrl.toString()).isEqualTo(standardUrl.toString()); + } + private URL createUrl(String file) throws MalformedURLException { return new URL("jar", null, -1, file, this.handler); }