Update WarLauncher to remove the root of the war from the classpath

Previously, WarLauncher included its root on the classpath. It also used
a filtered version of its root archive to hide both the WEB-INF and
META-INF directories. This meant that files in WEB-INF and META-INF
could be found by the classloader (as they were on the classpath) but
could not be read as the filtered archive was hiding them.

This commit updates WarLauncher to remove the root of the war file from
the classpath. It also removes the filtering of the archive, thereby
allowing files in META-INF and WEB-INF to be accessed via the
ServletContext.

Closes gh-1792
pull/1873/merge
Andy Wilkinson 10 years ago
parent 215689bd4d
commit ade22c87ec

@ -54,6 +54,11 @@ public abstract class ExecutableArchiveLauncher extends Launcher {
this.javaAgentDetector = javaAgentDetector;
}
ExecutableArchiveLauncher(Archive archive) {
this.javaAgentDetector = new InputArgumentsJavaAgentDetector();
this.archive = archive;
}
protected final Archive getArchive() {
return this.archive;
}

@ -16,9 +16,6 @@
package org.springframework.boot.loader;
import java.io.IOException;
import java.util.List;
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.util.AsciiBytes;
@ -28,13 +25,12 @@ import org.springframework.boot.loader.util.AsciiBytes;
* classes are loaded from {@code WEB-INF/classes}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class WarLauncher extends ExecutableArchiveLauncher {
private static final AsciiBytes WEB_INF = new AsciiBytes("WEB-INF/");
private static final AsciiBytes META_INF = new AsciiBytes("META-INF/");
private static final AsciiBytes WEB_INF_CLASSES = WEB_INF.append("classes/");
private static final AsciiBytes WEB_INF_LIB = WEB_INF.append("lib/");
@ -42,6 +38,14 @@ public class WarLauncher extends ExecutableArchiveLauncher {
private static final AsciiBytes WEB_INF_LIB_PROVIDED = WEB_INF
.append("lib-provided/");
public WarLauncher() {
super();
}
WarLauncher(Archive archive) {
super(archive);
}
@Override
public boolean isNestedArchive(Archive.Entry entry) {
if (entry.isDirectory()) {
@ -53,29 +57,6 @@ public class WarLauncher extends ExecutableArchiveLauncher {
}
}
@Override
protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
archives.add(0, getFilteredArchive());
}
/**
* Filter the specified WAR file to exclude elements that should not appear on the
* classpath.
* @return the filtered archive
* @throws IOException on error
*/
protected Archive getFilteredArchive() throws IOException {
return getArchive().getFilteredArchive(new Archive.EntryRenameFilter() {
@Override
public AsciiBytes apply(AsciiBytes entryName, Archive.Entry entry) {
if (entryName.startsWith(META_INF) || entryName.startsWith(WEB_INF)) {
return null;
}
return entryName;
}
});
}
public static void main(String[] args) {
new WarLauncher().launch(args);
}

@ -0,0 +1,124 @@
/*
* Copyright 2012-2014 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;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import org.junit.Test;
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.archive.ExplodedArchive;
import org.springframework.boot.loader.archive.JarFileArchive;
import org.springframework.util.FileSystemUtils;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link WarLauncher}
*
* @author Andy Wilkinson
*/
public class WarLauncherTests {
@Test
public void explodedWarHasOnlyWebInfClassesAndContentsOfWebInfLibOnClasspath()
throws Exception {
File warRoot = new File("target/exploded-war");
FileSystemUtils.deleteRecursively(warRoot);
warRoot.mkdirs();
File webInfClasses = new File(warRoot, "WEB-INF/classes");
webInfClasses.mkdirs();
File webInfLib = new File(warRoot, "WEB-INF/lib");
webInfLib.mkdirs();
File webInfLibFoo = new File(webInfLib, "foo.jar");
new JarOutputStream(new FileOutputStream(webInfLibFoo)).close();
WarLauncher launcher = new WarLauncher(new ExplodedArchive(warRoot, true));
List<Archive> archives = launcher.getClassPathArchives();
assertEquals(2, archives.size());
assertThat(
getUrls(archives),
hasItems(webInfClasses.toURI().toURL(), new URL("jar:"
+ webInfLibFoo.toURI().toURL() + "!/")));
}
@Test
public void archivedWarHasOnlyWebInfClassesAndContentsOfWebInfLibOnClasspath()
throws Exception {
File warRoot = createWarArchive();
WarLauncher launcher = new WarLauncher(new JarFileArchive(warRoot));
List<Archive> archives = launcher.getClassPathArchives();
assertEquals(2, archives.size());
assertThat(
getUrls(archives),
hasItems(
new URL("jar:" + warRoot.toURI().toURL() + "!/WEB-INF/classes!/"),
new URL("jar:" + warRoot.toURI().toURL()
+ "!/WEB-INF/lib/foo.jar!/")));
}
private Set<URL> getUrls(List<Archive> archives) throws MalformedURLException {
Set<URL> urls = new HashSet<URL>(archives.size());
for (Archive archive : archives) {
urls.add(archive.getUrl());
}
return urls;
}
private File createWarArchive() throws IOException, FileNotFoundException {
File warRoot = new File("target/archive.war");
warRoot.delete();
JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(
warRoot));
jarOutputStream.putNextEntry(new JarEntry("WEB-INF/"));
jarOutputStream.putNextEntry(new JarEntry("WEB-INF/classes/"));
jarOutputStream.putNextEntry(new JarEntry("WEB-INF/lib/"));
JarEntry webInfLibFoo = new JarEntry("WEB-INF/lib/foo.jar");
webInfLibFoo.setMethod(ZipEntry.STORED);
ByteArrayOutputStream fooJarStream = new ByteArrayOutputStream();
new JarOutputStream(fooJarStream).close();
webInfLibFoo.setSize(fooJarStream.size());
CRC32 crc32 = new CRC32();
crc32.update(fooJarStream.toByteArray());
webInfLibFoo.setCrc(crc32.getValue());
jarOutputStream.putNextEntry(webInfLibFoo);
jarOutputStream.write(fooJarStream.toByteArray());
jarOutputStream.close();
return warRoot;
}
}
Loading…
Cancel
Save