Prevent webapp class loader from finding resources
Previously, TomcatEmbeddedWebappClassLoader would find resources in WEB-INF/classes. However, unlike standalone Tomcat, we know that in a Boot app WEB-INF/classes is on the class path of the parent class loader so the resources will be found when the parent is queried (which happens as part of the normal search algortithm for both getResource(String) and getResources(String)). This commit overrides findResource(String) and findResources(String) to return null and an empty enumeration respectively. This prevents TomcatEmbeddedWebappClassLoader from finding resources in WEB-INF/classes and returning war: URLs for them that duplicate the jar: URLs that will be found when the parent is queried. Closes gh-9014pull/9829/merge
parent
00feae7e8a
commit
ded7cea761
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2017 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.web.embedded.tomcat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.loader.WebappClassLoader;
|
||||
import org.apache.catalina.webresources.StandardRoot;
|
||||
import org.apache.catalina.webresources.WarResourceSet;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link TomcatEmbeddedWebappClassLoader}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class TomcatEmbeddedWebappClassLoaderTests {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
@Test
|
||||
public void getResourceFindsResourceFromParentClassLoader() throws Exception {
|
||||
File war = createWar();
|
||||
withWebappClassLoader(war, (classLoader) -> {
|
||||
assertThat(classLoader.getResource("test.txt"))
|
||||
.isEqualTo(new URL(webInfClassesUrlString(war) + "test.txt"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getResourcesOnlyFindsResourcesFromParentClassLoader() throws Exception {
|
||||
File warFile = createWar();
|
||||
withWebappClassLoader(warFile, (classLoader) -> {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
CollectionUtils.toIterator(classLoader.getResources("test.txt"))
|
||||
.forEachRemaining(urls::add);
|
||||
assertThat(urls).containsExactly(
|
||||
new URL(webInfClassesUrlString(warFile) + "test.txt"));
|
||||
});
|
||||
}
|
||||
|
||||
private void withWebappClassLoader(File war, ClassLoaderConsumer consumer)
|
||||
throws Exception {
|
||||
URLClassLoader parent = new URLClassLoader(
|
||||
new URL[] { new URL(webInfClassesUrlString(war)) }, null);
|
||||
try (WebappClassLoader classLoader = new TomcatEmbeddedWebappClassLoader(
|
||||
parent)) {
|
||||
StandardContext context = new StandardContext();
|
||||
context.setName("test");
|
||||
StandardRoot resources = new StandardRoot();
|
||||
resources.setContext(context);
|
||||
resources.addJarResources(
|
||||
new WarResourceSet(resources, "/", war.getAbsolutePath()));
|
||||
resources.start();
|
||||
classLoader.setResources(resources);
|
||||
classLoader.start();
|
||||
consumer.accept(classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private String webInfClassesUrlString(File war) {
|
||||
return "jar:file:" + war.getAbsolutePath() + "!/WEB-INF/classes/";
|
||||
}
|
||||
|
||||
private File createWar() throws IOException, FileNotFoundException {
|
||||
File warFile = this.temp.newFile("test.war");
|
||||
try (JarOutputStream warOut = new JarOutputStream(
|
||||
new FileOutputStream(warFile))) {
|
||||
createEntries(warOut, "WEB-INF/", "WEB-INF/classes/",
|
||||
"WEB-INF/classes/test.txt");
|
||||
}
|
||||
return warFile;
|
||||
}
|
||||
|
||||
private void createEntries(JarOutputStream out, String... names) throws IOException {
|
||||
for (String name : names) {
|
||||
out.putNextEntry(new ZipEntry(name));
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private interface ClassLoaderConsumer {
|
||||
|
||||
void accept(ClassLoader classLoader) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue