mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Allow prefixed bytes with fat JARs
Update `spring-boot-loader` ZIP processing code to support prefixed bytes within the fat jar. This technique allows a bash script to be embedded at the start of the JAR whilst still allowing `java -jar` execution. Fixes gh-1073
This commit is contained in:
parent
a374929c90
commit
54dc46f777
@ -87,6 +87,20 @@ class CentralDirectoryEndRecord {
|
||||
return this.size == MINIMUM_SIZE + commentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location in the data that the archive actually starts. For most files
|
||||
* the archive data will start at 0, however, it is possible to have prefixed bytes
|
||||
* (often used for startup scripts) at the beginning of the data.
|
||||
* @param data the source data
|
||||
* @return the offset within the data where the archive begins
|
||||
*/
|
||||
public long getStartOfArchive(RandomAccessData data) {
|
||||
long length = Bytes.littleEndianValue(this.block, this.offset + 12, 4);
|
||||
long specifiedOffset = Bytes.littleEndianValue(this.block, this.offset + 16, 4);
|
||||
long actualOffset = data.getSize() - this.size - length;
|
||||
return actualOffset - specifiedOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bytes of the "Central directory" based on the offset indicated in this
|
||||
* record.
|
||||
|
@ -119,15 +119,25 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
private JarFile(RandomAccessDataFile rootFile, String name, RandomAccessData data,
|
||||
JarEntryFilter... filters) throws IOException {
|
||||
super(rootFile.getFile());
|
||||
CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(data);
|
||||
this.data = getArchiveData(endRecord, data);
|
||||
this.rootFile = rootFile;
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
this.size = data.getSize();
|
||||
loadJarEntries(filters);
|
||||
loadJarEntries(endRecord, filters);
|
||||
}
|
||||
|
||||
private void loadJarEntries(JarEntryFilter[] filters) throws IOException {
|
||||
CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(this.data);
|
||||
private RandomAccessData getArchiveData(CentralDirectoryEndRecord endRecord,
|
||||
RandomAccessData data) {
|
||||
long offset = endRecord.getStartOfArchive(data);
|
||||
if (offset == 0) {
|
||||
return data;
|
||||
}
|
||||
return data.getSubsection(offset, data.getSize() - offset);
|
||||
}
|
||||
|
||||
private void loadJarEntries(CentralDirectoryEndRecord endRecord,
|
||||
JarEntryFilter[] filters) throws IOException {
|
||||
RandomAccessData centralDirectory = endRecord.getCentralDirectory(this.data);
|
||||
int numberOfRecords = endRecord.getNumberOfRecords();
|
||||
this.entries = new ArrayList<JarEntryData>(numberOfRecords);
|
||||
|
@ -17,11 +17,14 @@
|
||||
package org.springframework.boot.loader.jar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.Manifest;
|
||||
@ -35,6 +38,8 @@ import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.boot.loader.TestJarCreator;
|
||||
import org.springframework.boot.loader.data.RandomAccessDataFile;
|
||||
import org.springframework.boot.loader.util.AsciiBytes;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
@ -389,4 +394,18 @@ public class JarFileTests {
|
||||
}
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jarFileWithScriptAtTheStart() throws Exception {
|
||||
File file = this.temporaryFolder.newFile();
|
||||
InputStream sourceJarContent = new FileInputStream(this.rootJarFile);
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
StreamUtils.copy("#/bin/bash", Charset.defaultCharset(), outputStream);
|
||||
FileCopyUtils.copy(sourceJarContent, outputStream);
|
||||
this.rootJarFile = file;
|
||||
this.jarFile = new JarFile(file);
|
||||
// Call some other tests to verify
|
||||
getEntries();
|
||||
getNestedJarFile();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user