diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactory.java index deaf44cc43..397d7710fd 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactory.java @@ -22,6 +22,7 @@ import java.net.JarURLConnection; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; +import java.net.URLDecoder; import java.security.CodeSource; import java.util.ArrayList; import java.util.Arrays; @@ -96,56 +97,64 @@ public abstract class AbstractEmbeddedServletContainerFactory List staticResourceUrls = new ArrayList(); if (classLoader instanceof URLClassLoader) { for (URL url : ((URLClassLoader) classLoader).getURLs()) { - try { - if ("file".equals(url.getProtocol())) { - File file = new File(url.getFile()); - if (file.isDirectory() - && new File(file, "META-INF/resources").isDirectory()) { - staticResourceUrls.add(url); - } - else if (isResourcesJar(file)) { - staticResourceUrls.add(url); - } - } - else { - URLConnection connection = url.openConnection(); - if (connection instanceof JarURLConnection) { - if (isResourcesJar((JarURLConnection) connection)) { - staticResourceUrls.add(url); - } - } - } - } - catch (IOException ex) { - throw new IllegalStateException(ex); + if (isStaticResource(url)) { + staticResourceUrls.add(url); } } } return staticResourceUrls; } + protected boolean isStaticResource(URL url) { + try { + if ("file".equals(url.getProtocol())) { + File file = new File(URLDecoder.decode(url.getFile(), "UTF-8")); + if (file.isDirectory() + && new File(file, "META-INF/resources").isDirectory()) { + return true; + } + else if (isResourcesJar(file)) { + return true; + } + } + else { + URLConnection connection = url.openConnection(); + if (connection instanceof JarURLConnection) { + if (isResourcesJar((JarURLConnection) connection)) { + return true; + } + } + } + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + return false; + } + private boolean isResourcesJar(JarURLConnection connection) { try { return isResourcesJar(connection.getJarFile()); } catch (IOException ex) { + logger.warn("Unable to open jar to determine if it contains static resources", ex); return false; } } private boolean isResourcesJar(File file) { try { - return isResourcesJar(new JarFile(file)); + return file.getName().endsWith(".jar") && isResourcesJar(new JarFile(file)); } catch (IOException ex) { + logger.warn("Unable to open jar to determine if it contains static resources", ex); return false; } } private boolean isResourcesJar(JarFile jar) throws IOException { try { - return jar.getName().endsWith(".jar") - && (jar.getJarEntry("META-INF/resources") != null); + return jar.getJarEntry("META-INF/resources") != null; } finally { jar.close(); diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java index 72f04946eb..5db6fc0356 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.embedded; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; @@ -49,6 +50,8 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; import java.util.zip.GZIPInputStream; import javax.net.ssl.SSLContext; @@ -1035,6 +1038,54 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { assertThat(documentRoot).isNull(); } + @Test + public void includeJarWithStaticResources() throws Exception { + AbstractEmbeddedServletContainerFactory factory = getFactory(); + File jarFile = this.temporaryFolder.newFile("test.jar"); + JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile)); + JarEntry jarEntry = new JarEntry("META-INF/resources"); + jarOutputStream.putNextEntry(jarEntry); + jarOutputStream.closeEntry(); + jarOutputStream.close(); + String path = "file:" + jarFile.getAbsolutePath(); + + boolean isStaticResource = factory.isStaticResource(new URL(path)); + + assertThat(isStaticResource).isTrue(); + } + + @Test + public void includeJarWithStaticResourcesWithUrlEncodedSpaces() throws Exception { + AbstractEmbeddedServletContainerFactory factory = getFactory(); + this.temporaryFolder.newFolder("test parent"); + File jarFile = this.temporaryFolder.newFile("test parent/test.jar"); + JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile)); + JarEntry jarEntry = new JarEntry("META-INF/resources"); + jarOutputStream.putNextEntry(jarEntry); + jarOutputStream.closeEntry(); + jarOutputStream.close(); + String path = "file:" + jarFile.getAbsolutePath().replaceAll(" ", "%20"); + + boolean isStaticResource = factory.isStaticResource(new URL(path)); + + assertThat(isStaticResource).isTrue(); + } + + @Test + public void excludeJarWithoutStaticResources() throws Exception { + AbstractEmbeddedServletContainerFactory factory = getFactory(); + File jarFile = this.temporaryFolder.newFile("test.jar"); + JarOutputStream jarOutputStream = new JarOutputStream( + new FileOutputStream(jarFile)); + jarOutputStream.closeEntry(); + jarOutputStream.close(); + String path = "file:" + jarFile.getAbsolutePath(); + + boolean isStaticResource = factory.isStaticResource(new URL(path)); + + assertThat(isStaticResource).isFalse(); + } + protected abstract void addConnector(int port, AbstractEmbeddedServletContainerFactory factory);