Fix static resource handling when run in IDE or using Maven or Gradle
The changes made for gh-8299 attempted to make static resource handling consistent across Jetty, Tomcat, and Undertow. They did so for application's launched using JarLauncher or WarLauncher but did not consider application's launched in an IDE or using spring-boot:run in Maven or bootRun in Gradle. Running in an IDE or via Maven or Gradle introduces two new resource locations: - Jars on the classpath with file protocol URLs (they are always jar protocol URLs when using either launcher) - Directories on the classpath from a project that is depended upon and contains resources in META-INF/resources This commit updates the factories for all three containers to handle these new resources locations. The integration tests have also been updated.
This commit is contained in:
@@ -96,15 +96,23 @@ public abstract class AbstractEmbeddedServletContainerFactory
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
|
||||
try {
|
||||
URLConnection connection = url.openConnection();
|
||||
if (connection instanceof JarURLConnection) {
|
||||
JarURLConnection jarConnection = (JarURLConnection) connection;
|
||||
JarFile jar = jarConnection.getJarFile();
|
||||
if (jar.getName().endsWith(".jar")
|
||||
&& jar.getJarEntry("META-INF/resources") != null) {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
File file = new File(url.getFile());
|
||||
if (file.isDirectory()
|
||||
&& new File(file, "META-INF/resources").isDirectory()) {
|
||||
staticResourceUrls.add(url);
|
||||
}
|
||||
jar.close();
|
||||
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) {
|
||||
@@ -115,6 +123,34 @@ public abstract class AbstractEmbeddedServletContainerFactory
|
||||
return staticResourceUrls;
|
||||
}
|
||||
|
||||
private boolean isResourcesJar(JarURLConnection connection) {
|
||||
try {
|
||||
return isResourcesJar(connection.getJarFile());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResourcesJar(File file) {
|
||||
try {
|
||||
return isResourcesJar(new JarFile(file));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResourcesJar(JarFile jar) throws IOException {
|
||||
try {
|
||||
return jar.getName().endsWith(".jar")
|
||||
&& (jar.getJarEntry("META-INF/resources") != null);
|
||||
}
|
||||
finally {
|
||||
jar.close();
|
||||
}
|
||||
}
|
||||
|
||||
File getExplodedWarFileDocumentRoot(File codeSourceFile) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Code archive: " + codeSourceFile);
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.boot.context.embedded.jetty;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
@@ -410,8 +411,7 @@ public class JettyEmbeddedServletContainerFactory
|
||||
root.isDirectory() ? Resource.newResource(root.getCanonicalFile())
|
||||
: JarResource.newJarResource(Resource.newResource(root)));
|
||||
for (URL resourceJarUrl : this.getUrlsOfJarsWithMetaInfResources()) {
|
||||
Resource resource = Resource
|
||||
.newResource(resourceJarUrl + "META-INF/resources");
|
||||
Resource resource = createResource(resourceJarUrl);
|
||||
// Jetty 9.2 and earlier do not support nested jars. See
|
||||
// https://github.com/eclipse/jetty.project/issues/518
|
||||
if (resource.exists() && resource.isDirectory()) {
|
||||
@@ -426,6 +426,16 @@ public class JettyEmbeddedServletContainerFactory
|
||||
}
|
||||
}
|
||||
|
||||
private Resource createResource(URL url) throws MalformedURLException {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
File file = new File(url.getFile());
|
||||
if (file.isFile()) {
|
||||
return Resource.newResource("jar:" + url + "!/META-INF/resources");
|
||||
}
|
||||
}
|
||||
return Resource.newResource(url + "META-INF/resources");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Jetty's {@code DefaultServlet} to the given {@link WebAppContext}.
|
||||
* @param context the jetty {@link WebAppContext}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.WebResourceRoot.ResourceSetType;
|
||||
@@ -57,6 +56,9 @@ abstract class TomcatResources {
|
||||
}
|
||||
addJar(jar);
|
||||
}
|
||||
else {
|
||||
addDir(file, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +129,7 @@ abstract class TomcatResources {
|
||||
|
||||
@Override
|
||||
protected void addDir(String dir, URL url) {
|
||||
if (getContext() instanceof ServletContext) {
|
||||
if (getContext() instanceof StandardContext) {
|
||||
try {
|
||||
Class<?> fileDirContextClass = Class
|
||||
.forName("org.apache.naming.resources.FileDirContext");
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.boot.context.embedded.undertow;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -468,11 +469,35 @@ public class UndertowEmbeddedServletContainerFactory
|
||||
|
||||
private ResourceManager getDocumentRootResourceManager() {
|
||||
File root = getCanonicalDocumentRoot();
|
||||
List<URL> metaInfResourceJarUrls = getUrlsOfJarsWithMetaInfResources();
|
||||
List<URL> metaInfResourceUrls = getUrlsOfJarsWithMetaInfResources();
|
||||
List<URL> resourceJarUrls = new ArrayList<URL>();
|
||||
List<ResourceManager> resourceManagers = new ArrayList<ResourceManager>();
|
||||
ResourceManager rootResourceManager = root.isDirectory()
|
||||
? new FileResourceManager(root, 0) : new JarResourceManager(root);
|
||||
return new CompositeResourceManager(rootResourceManager,
|
||||
new MetaInfResourcesResourceManager(metaInfResourceJarUrls));
|
||||
resourceManagers.add(rootResourceManager);
|
||||
for (URL url : metaInfResourceUrls) {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
File file = new File(url.getFile());
|
||||
if (file.isFile()) {
|
||||
try {
|
||||
resourceJarUrls.add(new URL("jar:" + url + "!/"));
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
resourceManagers.add(new FileResourceManager(
|
||||
new File(file, "META-INF/resources"), 0));
|
||||
}
|
||||
}
|
||||
else {
|
||||
resourceJarUrls.add(url);
|
||||
}
|
||||
}
|
||||
resourceManagers.add(new MetaInfResourcesResourceManager(resourceJarUrls));
|
||||
return new CompositeResourceManager(
|
||||
resourceManagers.toArray(new ResourceManager[resourceManagers.size()]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -617,12 +642,17 @@ public class UndertowEmbeddedServletContainerFactory
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String path) throws IOException {
|
||||
public Resource getResource(String path) {
|
||||
for (URL url : this.metaInfResourceJarUrls) {
|
||||
URL resourceUrl = new URL(url + "META-INF/resources" + path);
|
||||
URLConnection connection = resourceUrl.openConnection();
|
||||
if (connection.getContentLength() >= 0) {
|
||||
return new URLResource(resourceUrl, connection, path);
|
||||
try {
|
||||
URL resourceUrl = new URL(url + "META-INF/resources" + path);
|
||||
URLConnection connection = resourceUrl.openConnection();
|
||||
if (connection.getContentLength() >= 0) {
|
||||
return new URLResource(resourceUrl, connection, path);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user