Fail fast when a Zip64 jar is encountered
Previously, jars (either top-level or nested) in Zip64 format were treated as normal jar files. This would lead to a failure later on when an attempt was made to read an entry from the file. This commit updates the loader to fail fast when it encounters a Zip64 jar file. Such files are identified by the number of entries in the central directory end record being 0xFFFF. Closes gh-8735
This commit is contained in:
parent
b280e3092d
commit
456327260b
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* 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.
|
||||
|
@ -100,8 +100,14 @@ public class JarFileArchive implements Archive {
|
|||
if (jarEntry.getComment().startsWith(UNPACK_MARKER)) {
|
||||
return getUnpackedNestedArchive(jarEntry);
|
||||
}
|
||||
JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
|
||||
return new JarFileArchive(jarFile);
|
||||
try {
|
||||
JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
|
||||
return new JarFileArchive(jarFile);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
"Failed to get nested archive for entry " + entry.getName(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Archive getUnpackedNestedArchive(JarEntry jarEntry) throws IOException {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* 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.
|
||||
|
@ -24,6 +24,7 @@ import org.springframework.boot.loader.data.RandomAccessData;
|
|||
* A ZIP File "End of central directory record" (EOCD).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Andy Wilkinson
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Zip_%28file_format%29">Zip File Format</a>
|
||||
*/
|
||||
class CentralDirectoryEndRecord {
|
||||
|
@ -118,7 +119,11 @@ class CentralDirectoryEndRecord {
|
|||
* @return the number of records in the zip
|
||||
*/
|
||||
public int getNumberOfRecords() {
|
||||
return (int) Bytes.littleEndianValue(this.block, this.offset + 10, 2);
|
||||
long numberOfRecords = Bytes.littleEndianValue(this.block, this.offset + 10, 2);
|
||||
if (numberOfRecords == 0xFFFF) {
|
||||
throw new IllegalStateException("Zip64 archives are not supported");
|
||||
}
|
||||
return (int) numberOfRecords;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
* 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.
|
||||
|
@ -16,20 +16,30 @@
|
|||
|
||||
package org.springframework.boot.loader.archive;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.archive.Archive.Entry;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
/**
|
||||
* Tests for {@link JarFileArchive}.
|
||||
|
@ -42,6 +52,9 @@ public class JarFileArchiveTests {
|
|||
@Rule
|
||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private File rootJarFile;
|
||||
|
||||
private JarFileArchive archive;
|
||||
|
@ -120,6 +133,48 @@ public class JarFileArchiveTests {
|
|||
assertThat(nested.getParent()).isEqualTo(anotherNested.getParent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void zip64ArchivesAreHandledGracefully() throws IOException {
|
||||
File file = this.temporaryFolder.newFile("test.jar");
|
||||
FileCopyUtils.copy(writeZip64Jar(), file);
|
||||
this.thrown.expectMessage(equalTo("Zip64 archives are not supported"));
|
||||
new JarFileArchive(file);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedZip64ArchivesAreHandledGracefully() throws IOException {
|
||||
File file = this.temporaryFolder.newFile("test.jar");
|
||||
JarOutputStream output = new JarOutputStream(new FileOutputStream(file));
|
||||
JarEntry zip64JarEntry = new JarEntry("nested/zip64.jar");
|
||||
output.putNextEntry(zip64JarEntry);
|
||||
byte[] zip64JarData = writeZip64Jar();
|
||||
zip64JarEntry.setSize(zip64JarData.length);
|
||||
zip64JarEntry.setCompressedSize(zip64JarData.length);
|
||||
zip64JarEntry.setMethod(ZipEntry.STORED);
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(zip64JarData);
|
||||
zip64JarEntry.setCrc(crc32.getValue());
|
||||
output.write(zip64JarData);
|
||||
output.closeEntry();
|
||||
output.close();
|
||||
JarFileArchive jarFileArchive = new JarFileArchive(file);
|
||||
this.thrown.expectMessage(
|
||||
equalTo("Failed to get nested archive for entry nested/zip64.jar"));
|
||||
jarFileArchive
|
||||
.getNestedArchive(getEntriesMap(jarFileArchive).get("nested/zip64.jar"));
|
||||
}
|
||||
|
||||
private byte[] writeZip64Jar() throws IOException {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
JarOutputStream jarOutput = new JarOutputStream(bytes);
|
||||
for (int i = 0; i < 65537; i++) {
|
||||
jarOutput.putNextEntry(new JarEntry(i + ".dat"));
|
||||
jarOutput.closeEntry();
|
||||
}
|
||||
jarOutput.close();
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
private Map<String, Archive.Entry> getEntriesMap(Archive archive) {
|
||||
Map<String, Archive.Entry> entries = new HashMap<String, Archive.Entry>();
|
||||
for (Archive.Entry entry : archive) {
|
||||
|
|
Loading…
Reference in New Issue