This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat-jakartaee-migration.git
The following commit(s) were added to refs/heads/main by this push:
new ec45564 Avoid buffering very large STORED zip entries
ec45564 is described below
commit ec45564f26901a4423d0623123150f776815c7aa
Author: remm <[email protected]>
AuthorDate: Fri Jun 5 17:01:39 2026 +0200
Avoid buffering very large STORED zip entries
The scenario is extremely unlikely, but it is best to avoid crashing.
STORED entries are notoriously difficult to process since we need to
know their size and crc, but we only know that from before conversion.
Co authored by OpenCode.
---
CHANGES.md | 1 +
.../org/apache/tomcat/jakartaee/Migration.java | 105 ++++++++++++++++++---
2 files changed, 91 insertions(+), 15 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 21785d1..a509782 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,7 @@
## 1.0.13
- Properly reconstruct the original pool in the ClassConverter transformer if
a class is found to be available. (remm)
+- Do not buffer very large STORED zip entries when processing them in
streaming mode. (remm)
## 1.0.12
- Add Maven Wrapper Plugin to manage the Maven wrapper. (markt)
diff --git a/src/main/java/org/apache/tomcat/jakartaee/Migration.java
b/src/main/java/org/apache/tomcat/jakartaee/Migration.java
index 4c1c7d6..e29c7ca 100644
--- a/src/main/java/org/apache/tomcat/jakartaee/Migration.java
+++ b/src/main/java/org/apache/tomcat/jakartaee/Migration.java
@@ -326,7 +326,6 @@ public class Migration {
try (ZipArchiveInputStream srcZipStream = new
ZipArchiveInputStream(CloseShieldInputStream.wrap(src));
ZipArchiveOutputStream destZipStream = new
ZipArchiveOutputStream(CloseShieldOutputStream.wrap(dest))) {
ZipArchiveEntry srcZipEntry;
- CRC32 crc32 = new CRC32();
while ((srcZipEntry = srcZipStream.getNextEntry()) != null) {
boolean convertedStream = false;
String srcName = srcZipEntry.getName();
@@ -345,21 +344,19 @@ public class Migration {
}
String destName = profile.convert(srcName);
if (srcZipEntry.getMethod() == ZipEntry.STORED) {
- ByteArrayOutputStream tempBuffer =
- new ByteArrayOutputStream(Math.toIntExact((long)
(srcZipEntry.getSize() * 1.05)));
- convertedStream = migrateStream(srcName, srcZipStream,
tempBuffer);
- crc32.update(tempBuffer.toByteArray(), 0,
tempBuffer.size());
- MigrationZipArchiveEntry destZipEntry = new
MigrationZipArchiveEntry(srcZipEntry);
- destZipEntry.setName(destName);
- destZipEntry.setSize(tempBuffer.size());
- destZipEntry.setCrc(crc32.getValue());
- if (convertedStream) {
-
destZipEntry.setLastModifiedTime(FileTime.fromMillis(System.currentTimeMillis()));
+ try (CrcSizeTrackingOutputStream trackingStream = new
CrcSizeTrackingOutputStream()) {
+ convertedStream = migrateStream(srcName, srcZipStream,
trackingStream);
+ MigrationZipArchiveEntry destZipEntry = new
MigrationZipArchiveEntry(srcZipEntry);
+ destZipEntry.setName(destName);
+ destZipEntry.setSize(trackingStream.getSize());
+ destZipEntry.setCrc(trackingStream.getCrc());
+ if (convertedStream) {
+
destZipEntry.setLastModifiedTime(FileTime.fromMillis(System.currentTimeMillis()));
+ }
+ destZipStream.putArchiveEntry(destZipEntry);
+ trackingStream.writeTo(destZipStream);
+ destZipStream.closeArchiveEntry();
}
- destZipStream.putArchiveEntry(destZipEntry);
- tempBuffer.writeTo(destZipStream);
- destZipStream.closeArchiveEntry();
- crc32.reset();
} else {
MigrationZipArchiveEntry destZipEntry = new
MigrationZipArchiveEntry(srcZipEntry);
destZipEntry.setName(destName);
@@ -538,4 +535,82 @@ public class Migration {
super.setName(name);
}
}
+
+ private static class CrcSizeTrackingOutputStream extends OutputStream {
+
+ private static final long TEMP_FILE_THRESHOLD = 10L * 1024 * 1024;
+
+ private final CRC32 crc = new CRC32();
+ private long size;
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ private FileOutputStream fileOutput;
+ private File tempFile;
+
+ @Override
+ public void write(int b) throws IOException {
+ if (fileOutput != null) {
+ fileOutput.write(b);
+ } else {
+ buffer.write(b);
+ maybeSwitchToFile();
+ }
+ crc.update(b);
+ size++;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (fileOutput != null) {
+ fileOutput.write(b, off, len);
+ } else {
+ buffer.write(b, off, len);
+ maybeSwitchToFile();
+ }
+ crc.update(b, off, len);
+ size += len;
+ }
+
+ private void maybeSwitchToFile() throws IOException {
+ if (buffer != null && buffer.size() > TEMP_FILE_THRESHOLD &&
fileOutput == null) {
+ tempFile = File.createTempFile("jakartaee-migration-", ".tmp");
+ tempFile.deleteOnExit();
+ fileOutput = new FileOutputStream(tempFile);
+ buffer.writeTo(fileOutput);
+ fileOutput.flush();
+ buffer = null;
+ }
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public long getCrc() {
+ return crc.getValue();
+ }
+
+ public void writeTo(OutputStream out) throws IOException {
+ if (fileOutput != null) {
+ fileOutput.close();
+ fileOutput = null;
+ try (FileInputStream fis = new FileInputStream(tempFile)) {
+ IOUtils.copy(fis, out);
+ }
+ } else if (buffer != null) {
+ buffer.writeTo(out);
+ }
+ }
+
+ public void close() throws IOException {
+ if (fileOutput != null) {
+ fileOutput.close();
+ if (tempFile != null && tempFile.exists()) {
+ tempFile.delete();
+ }
+ }
+ if (buffer != null) {
+ buffer.close();
+ }
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]