Merge branch '3.3.x'
This commit is contained in:
commit
5c7ea741f2
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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
|
||||||
|
*
|
||||||
|
* https://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.jar;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarInputStream;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to iterate entries in a jar file and check that content matches a related
|
||||||
|
* entry.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class JarEntriesStream implements Closeable {
|
||||||
|
|
||||||
|
private static final int BUFFER_SIZE = 4 * 1024;
|
||||||
|
|
||||||
|
private final JarInputStream in;
|
||||||
|
|
||||||
|
private final byte[] inBuffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
private final byte[] compareBuffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
private final Inflater inflater = new Inflater(true);
|
||||||
|
|
||||||
|
private JarEntry entry;
|
||||||
|
|
||||||
|
JarEntriesStream(InputStream in) throws IOException {
|
||||||
|
this.in = new JarInputStream(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
JarEntry getNextEntry() throws IOException {
|
||||||
|
this.entry = this.in.getNextJarEntry();
|
||||||
|
if (this.entry != null) {
|
||||||
|
this.entry.getSize();
|
||||||
|
}
|
||||||
|
this.inflater.reset();
|
||||||
|
return this.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matches(boolean directory, int size, int compressionMethod, InputStreamSupplier streamSupplier)
|
||||||
|
throws IOException {
|
||||||
|
if (this.entry.isDirectory() != directory) {
|
||||||
|
fail("directory");
|
||||||
|
}
|
||||||
|
if (this.entry.getMethod() != compressionMethod) {
|
||||||
|
fail("compression method");
|
||||||
|
}
|
||||||
|
if (this.entry.isDirectory()) {
|
||||||
|
this.in.closeEntry();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try (DataInputStream expected = new DataInputStream(getInputStream(size, streamSupplier))) {
|
||||||
|
assertSameContent(expected);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(int size, InputStreamSupplier streamSupplier) throws IOException {
|
||||||
|
InputStream inputStream = streamSupplier.get();
|
||||||
|
return (this.entry.getMethod() != ZipEntry.DEFLATED) ? inputStream
|
||||||
|
: new ZipInflaterInputStream(inputStream, this.inflater, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSameContent(DataInputStream expected) throws IOException {
|
||||||
|
int len;
|
||||||
|
while ((len = this.in.read(this.inBuffer)) > 0) {
|
||||||
|
try {
|
||||||
|
expected.readFully(this.compareBuffer, 0, len);
|
||||||
|
if (Arrays.equals(this.inBuffer, 0, len, this.compareBuffer, 0, len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (EOFException ex) {
|
||||||
|
// Continue and throw exception due to mismatched content length.
|
||||||
|
}
|
||||||
|
fail("content");
|
||||||
|
}
|
||||||
|
if (expected.read() != -1) {
|
||||||
|
fail("content");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fail(String check) {
|
||||||
|
throw new IllegalStateException("Content mismatch when reading security info for entry '%s' (%s check)"
|
||||||
|
.formatted(this.entry.getName(), check));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
this.inflater.end();
|
||||||
|
this.in.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface InputStreamSupplier {
|
||||||
|
|
||||||
|
InputStream get() throws IOException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -26,7 +26,6 @@ import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.Attributes.Name;
|
import java.util.jar.Attributes.Name;
|
||||||
import java.util.jar.JarInputStream;
|
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
@ -334,37 +333,30 @@ class JarFileEntries implements CentralDirectoryVisitor, Iterable<JarEntry> {
|
||||||
JarEntryCertification getCertification(JarEntry entry) throws IOException {
|
JarEntryCertification getCertification(JarEntry entry) throws IOException {
|
||||||
JarEntryCertification[] certifications = this.certifications;
|
JarEntryCertification[] certifications = this.certifications;
|
||||||
if (certifications == null) {
|
if (certifications == null) {
|
||||||
certifications = new JarEntryCertification[this.size];
|
certifications = getCertifications();
|
||||||
// We fall back to use JarInputStream to obtain the certs. This isn't that
|
|
||||||
// fast, but hopefully doesn't happen too often.
|
|
||||||
try (JarInputStream certifiedJarStream = new JarInputStream(this.jarFile.getData().getInputStream())) {
|
|
||||||
java.util.jar.JarEntry certifiedEntry;
|
|
||||||
while ((certifiedEntry = certifiedJarStream.getNextJarEntry()) != null) {
|
|
||||||
// Entry must be closed to trigger a read and set entry certificates
|
|
||||||
certifiedJarStream.closeEntry();
|
|
||||||
int index = getEntryIndex(certifiedEntry.getName());
|
|
||||||
if (index != -1) {
|
|
||||||
certifications[index] = JarEntryCertification.from(certifiedEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.certifications = certifications;
|
this.certifications = certifications;
|
||||||
}
|
}
|
||||||
JarEntryCertification certification = certifications[entry.getIndex()];
|
JarEntryCertification certification = certifications[entry.getIndex()];
|
||||||
return (certification != null) ? certification : JarEntryCertification.NONE;
|
return (certification != null) ? certification : JarEntryCertification.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getEntryIndex(CharSequence name) {
|
private JarEntryCertification[] getCertifications() throws IOException {
|
||||||
int hashCode = AsciiBytes.hashCode(name);
|
JarEntryCertification[] certifications = new JarEntryCertification[this.size];
|
||||||
int index = getFirstIndex(hashCode);
|
try (JarEntriesStream entries = new JarEntriesStream(this.jarFile.getData().getInputStream())) {
|
||||||
while (index >= 0 && index < this.size && this.hashCodes[index] == hashCode) {
|
java.util.jar.JarEntry entry = entries.getNextEntry();
|
||||||
FileHeader candidate = getEntry(index, FileHeader.class, false, null);
|
while (entry != null) {
|
||||||
if (candidate.hasName(name, NO_SUFFIX)) {
|
JarEntry relatedEntry = this.doGetEntry(entry.getName(), JarEntry.class, false, null);
|
||||||
return index;
|
if (relatedEntry != null && entries.matches(relatedEntry.isDirectory(), (int) relatedEntry.getSize(),
|
||||||
|
relatedEntry.getMethod(), () -> getEntryData(relatedEntry).getInputStream())) {
|
||||||
|
int index = relatedEntry.getIndex();
|
||||||
|
if (index != -1) {
|
||||||
|
certifications[index] = JarEntryCertification.from(entry);
|
||||||
}
|
}
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
return -1;
|
entry = entries.getNextEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return certifications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void swap(int[] array, int i, int j) {
|
private static void swap(int[] array, int i, int j) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -30,12 +30,23 @@ import java.util.zip.InflaterInputStream;
|
||||||
*/
|
*/
|
||||||
class ZipInflaterInputStream extends InflaterInputStream {
|
class ZipInflaterInputStream extends InflaterInputStream {
|
||||||
|
|
||||||
|
private final boolean ownsInflator;
|
||||||
|
|
||||||
private int available;
|
private int available;
|
||||||
|
|
||||||
private boolean extraBytesWritten;
|
private boolean extraBytesWritten;
|
||||||
|
|
||||||
ZipInflaterInputStream(InputStream inputStream, int size) {
|
ZipInflaterInputStream(InputStream inputStream, int size) {
|
||||||
super(inputStream, new Inflater(true), getInflaterBufferSize(size));
|
this(inputStream, new Inflater(true), size, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipInflaterInputStream(InputStream inputStream, Inflater inflater, int size) {
|
||||||
|
this(inputStream, inflater, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZipInflaterInputStream(InputStream inputStream, Inflater inflater, int size, boolean ownsInflator) {
|
||||||
|
super(inputStream, inflater, getInflaterBufferSize(size));
|
||||||
|
this.ownsInflator = ownsInflator;
|
||||||
this.available = size;
|
this.available = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +70,10 @@ class ZipInflaterInputStream extends InflaterInputStream {
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
super.close();
|
super.close();
|
||||||
|
if (this.ownsInflator) {
|
||||||
this.inf.end();
|
this.inf.end();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fill() throws IOException {
|
protected void fill() throws IOException {
|
||||||
|
|
|
@ -666,6 +666,26 @@ class JarFileTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void mismatchedStreamEntriesThrowsException() throws IOException {
|
||||||
|
File mismatchJar = new File("src/test/resources/jars/mismatch.jar");
|
||||||
|
IllegalStateException failure = null;
|
||||||
|
try (JarFile jarFile = new JarFile(mismatchJar)) {
|
||||||
|
JarFile nestedJarFile = jarFile.getNestedJarFile(jarFile.getJarEntry("inner.jar"));
|
||||||
|
Enumeration<JarEntry> entries = nestedJarFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
try {
|
||||||
|
entries.nextElement().getCodeSigners();
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ex) {
|
||||||
|
failure = (failure != null) ? failure : ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThat(failure)
|
||||||
|
.hasMessage("Content mismatch when reading security info for entry 'content' (content check)");
|
||||||
|
}
|
||||||
|
|
||||||
private File createJarFileWithEpochTimeOfZero() throws Exception {
|
private File createJarFileWithEpochTimeOfZero() throws Exception {
|
||||||
File jarFile = new File(this.tempDir, "temp.jar");
|
File jarFile = new File(this.tempDir, "temp.jar");
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream(jarFile);
|
FileOutputStream fileOutputStream = new FileOutputStream(jarFile);
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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
|
||||||
|
*
|
||||||
|
* https://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.jar;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarInputStream;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to iterate entries in a jar file and check that content matches a related
|
||||||
|
* entry.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class JarEntriesStream implements Closeable {
|
||||||
|
|
||||||
|
private static final int BUFFER_SIZE = 4 * 1024;
|
||||||
|
|
||||||
|
private final JarInputStream in;
|
||||||
|
|
||||||
|
private final byte[] inBuffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
private final byte[] compareBuffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
private final Inflater inflater = new Inflater(true);
|
||||||
|
|
||||||
|
private JarEntry entry;
|
||||||
|
|
||||||
|
JarEntriesStream(InputStream in) throws IOException {
|
||||||
|
this.in = new JarInputStream(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
JarEntry getNextEntry() throws IOException {
|
||||||
|
this.entry = this.in.getNextJarEntry();
|
||||||
|
if (this.entry != null) {
|
||||||
|
this.entry.getSize();
|
||||||
|
}
|
||||||
|
this.inflater.reset();
|
||||||
|
return this.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean matches(boolean directory, int size, int compressionMethod, InputStreamSupplier streamSupplier)
|
||||||
|
throws IOException {
|
||||||
|
if (this.entry.isDirectory() != directory) {
|
||||||
|
fail("directory");
|
||||||
|
}
|
||||||
|
if (this.entry.getMethod() != compressionMethod) {
|
||||||
|
fail("compression method");
|
||||||
|
}
|
||||||
|
if (this.entry.isDirectory()) {
|
||||||
|
this.in.closeEntry();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try (DataInputStream expected = new DataInputStream(getInputStream(size, streamSupplier))) {
|
||||||
|
assertSameContent(expected);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream getInputStream(int size, InputStreamSupplier streamSupplier) throws IOException {
|
||||||
|
InputStream inputStream = streamSupplier.get();
|
||||||
|
return (this.entry.getMethod() != ZipEntry.DEFLATED) ? inputStream
|
||||||
|
: new ZipInflaterInputStream(inputStream, this.inflater, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSameContent(DataInputStream expected) throws IOException {
|
||||||
|
int len;
|
||||||
|
while ((len = this.in.read(this.inBuffer)) > 0) {
|
||||||
|
try {
|
||||||
|
expected.readFully(this.compareBuffer, 0, len);
|
||||||
|
if (Arrays.equals(this.inBuffer, 0, len, this.compareBuffer, 0, len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (EOFException ex) {
|
||||||
|
// Continue and throw exception due to mismatched content length.
|
||||||
|
}
|
||||||
|
fail("content");
|
||||||
|
}
|
||||||
|
if (expected.read() != -1) {
|
||||||
|
fail("content");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fail(String check) {
|
||||||
|
throw new IllegalStateException("Content mismatch when reading security info for entry '%s' (%s check)"
|
||||||
|
.formatted(this.entry.getName(), check));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
this.inflater.end();
|
||||||
|
this.in.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface InputStreamSupplier {
|
||||||
|
|
||||||
|
InputStream get() throws IOException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -81,30 +81,31 @@ final class SecurityInfo {
|
||||||
* @return the security info
|
* @return the security info
|
||||||
* @throws IOException on I/O error
|
* @throws IOException on I/O error
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("resource")
|
||||||
private static SecurityInfo load(ZipContent content) throws IOException {
|
private static SecurityInfo load(ZipContent content) throws IOException {
|
||||||
int size = content.size();
|
int size = content.size();
|
||||||
boolean hasSecurityInfo = false;
|
boolean hasSecurityInfo = false;
|
||||||
Certificate[][] entryCertificates = new Certificate[size][];
|
Certificate[][] entryCertificates = new Certificate[size][];
|
||||||
CodeSigner[][] entryCodeSigners = new CodeSigner[size][];
|
CodeSigner[][] entryCodeSigners = new CodeSigner[size][];
|
||||||
try (JarInputStream in = new JarInputStream(content.openRawZipData().asInputStream())) {
|
try (JarEntriesStream entries = new JarEntriesStream(content.openRawZipData().asInputStream())) {
|
||||||
JarEntry jarEntry = in.getNextJarEntry();
|
JarEntry entry = entries.getNextEntry();
|
||||||
while (jarEntry != null) {
|
while (entry != null) {
|
||||||
in.closeEntry(); // Close to trigger a read and set certs/signers
|
ZipContent.Entry relatedEntry = content.getEntry(entry.getName());
|
||||||
Certificate[] certificates = jarEntry.getCertificates();
|
if (relatedEntry != null && entries.matches(relatedEntry.isDirectory(),
|
||||||
CodeSigner[] codeSigners = jarEntry.getCodeSigners();
|
relatedEntry.getUncompressedSize(), relatedEntry.getCompressionMethod(),
|
||||||
|
() -> relatedEntry.openContent().asInputStream())) {
|
||||||
|
Certificate[] certificates = entry.getCertificates();
|
||||||
|
CodeSigner[] codeSigners = entry.getCodeSigners();
|
||||||
if (certificates != null || codeSigners != null) {
|
if (certificates != null || codeSigners != null) {
|
||||||
ZipContent.Entry contentEntry = content.getEntry(jarEntry.getName());
|
|
||||||
if (contentEntry != null) {
|
|
||||||
hasSecurityInfo = true;
|
hasSecurityInfo = true;
|
||||||
entryCertificates[contentEntry.getLookupIndex()] = certificates;
|
entryCertificates[relatedEntry.getLookupIndex()] = certificates;
|
||||||
entryCodeSigners[contentEntry.getLookupIndex()] = codeSigners;
|
entryCodeSigners[relatedEntry.getLookupIndex()] = codeSigners;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jarEntry = in.getNextJarEntry();
|
entry = entries.getNextEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (!hasSecurityInfo) ? NONE : new SecurityInfo(entryCertificates, entryCodeSigners);
|
return (!hasSecurityInfo) ? NONE : new SecurityInfo(entryCertificates, entryCodeSigners);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -29,7 +29,7 @@ import java.util.zip.InflaterInputStream;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
abstract class ZipInflaterInputStream extends InflaterInputStream {
|
class ZipInflaterInputStream extends InflaterInputStream {
|
||||||
|
|
||||||
private int available;
|
private int available;
|
||||||
|
|
||||||
|
|
|
@ -412,6 +412,25 @@ class NestedJarFileTests {
|
||||||
assertThat(nested).isEqualTo(jdk);
|
assertThat(nested).isEqualTo(jdk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void mismatchedStreamEntriesThrowsException() throws IOException {
|
||||||
|
File mismatchJar = new File("src/test/resources/jars/mismatch.jar");
|
||||||
|
IllegalStateException failure = null;
|
||||||
|
try (NestedJarFile innerJar = new NestedJarFile(mismatchJar, "inner.jar")) {
|
||||||
|
Enumeration<JarEntry> entries = innerJar.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
try {
|
||||||
|
entries.nextElement().getCodeSigners();
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ex) {
|
||||||
|
failure = (failure != null) ? failure : ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThat(failure)
|
||||||
|
.hasMessage("Content mismatch when reading security info for entry 'content' (content check)");
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> collectComments(JarFile jarFile) throws IOException {
|
private List<String> collectComments(JarFile jarFile) throws IOException {
|
||||||
try (jarFile) {
|
try (jarFile) {
|
||||||
List<String> comments = new ArrayList<>();
|
List<String> comments = new ArrayList<>();
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue