Fix Tomcat TldScanner issues by returning raw zip data for nested jars

Update JarUrlConnection so that the full raw zip data is returned from
nested jars when no entry name is specified. This update allows
Tomcat's `WarURLConnection` to work with our nested connections since
they can parse the returned raw zip data.

Fixes gh-38047
This commit is contained in:
Phillip Webb
2023-10-26 18:58:15 -07:00
parent bba323ba5f
commit 4af9ed4d1d
4 changed files with 60 additions and 9 deletions

View File

@@ -17,6 +17,7 @@
package org.springframework.boot.loader.jar;
import java.io.File;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
@@ -143,6 +144,13 @@ public class NestedJarFile extends JarFile {
this.version = (version != null) ? version.feature() : baseVersion().feature();
}
public InputStream getRawZipDataInputStream() throws IOException {
RawZipDataInputStream inputStream = new RawZipDataInputStream(
this.resources.zipContent().openRawZipData().asInputStream());
this.resources.addInputStream(inputStream);
return inputStream;
}
@Override
public Manifest getManifest() throws IOException {
try {
@@ -799,4 +807,27 @@ public class NestedJarFile extends JarFile {
}
/**
* {@link InputStream} for raw zip data.
*/
private class RawZipDataInputStream extends FilterInputStream {
private volatile boolean closed;
protected RawZipDataInputStream(InputStream in) {
super(in);
}
@Override
public void close() throws IOException {
if (this.closed) {
return;
}
this.closed = true;
super.close();
NestedJarFile.this.resources.removeInputStream(this);
}
}
}

View File

@@ -175,11 +175,12 @@ final class JarUrlConnection extends java.net.JarURLConnection {
if (this.notFound != null) {
throwFileNotFound();
}
if (this.entryName == null) {
URL jarFileURL = getJarFileURL();
if (this.entryName == null && !UrlJarFileFactory.isNestedUrl(jarFileURL)) {
throw new IOException("no entry name specified");
}
if (!getUseCaches() && Optimizations.isEnabled(false)) {
JarFile cached = jarFiles.getCached(getJarFileURL());
if (!getUseCaches() && Optimizations.isEnabled(false) && this.entryName != null) {
JarFile cached = jarFiles.getCached(jarFileURL);
if (cached != null) {
if (cached.getEntry(this.entryName) != null) {
return emptyInputStream;
@@ -188,6 +189,12 @@ final class JarUrlConnection extends java.net.JarURLConnection {
}
connect();
if (this.jarEntry == null) {
if (this.jarFile instanceof NestedJarFile nestedJarFile) {
// In order to work with Tomcat's TLD scanning and WarURLConnection we
// return the raw zip data rather than failing because there is no entry.
// See gh-38047 for details.
return nestedJarFile.getRawZipDataInputStream();
}
throwFileNotFound();
}
return new ConnectionInputStream();

View File

@@ -80,10 +80,6 @@ class UrlJarFileFactory {
return new UrlJarFile(new File(path), version, closeAction);
}
private boolean isNestedUrl(URL url) {
return url.getProtocol().equalsIgnoreCase("nested");
}
private JarFile createJarFileForNested(URL url, Runtime.Version version, Consumer<JarFile> closeAction)
throws IOException {
NestedLocation location = NestedLocation.fromUrl(url);
@@ -120,4 +116,8 @@ class UrlJarFileFactory {
}
}
static boolean isNestedUrl(URL url) {
return url.getProtocol().equalsIgnoreCase("nested");
}
}