This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new aa68003fabf3 CAMEL-24166: Enforce maxDecompressedSize in
iterator/splitter mode for zip and tar (#24817)
aa68003fabf3 is described below
commit aa68003fabf357e22a37461f8aa2b7db1c81fc03
Author: Federico Mariani <[email protected]>
AuthorDate: Fri Jul 17 14:48:29 2026 +0200
CAMEL-24166: Enforce maxDecompressedSize in iterator/splitter mode for zip
and tar (#24817)
* CAMEL-24166: Enforce maxDecompressedSize in iterator/splitter mode for
zip and tar
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
* CAMEL-24166: Enforce maxDecompressedSize in ZipSplitter and TarSplitter
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
* CAMEL-24166: Replace custom MaxDecompressedSizeInputStream with
commons-io BoundedInputStream and add splitter tests
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
---
.../dataformat/tarfile/TarFileDataFormat.java | 1 +
.../camel/dataformat/tarfile/TarIterator.java | 23 ++++++++++++++-
.../camel/dataformat/tarfile/TarSplitter.java | 16 +++++++++-
.../dataformat/tarfile/TarFileDataFormatTest.java | 34 ++++++++++++++++++++++
.../dataformat/zipfile/ZipFileDataFormat.java | 1 +
.../camel/dataformat/zipfile/ZipIterator.java | 11 ++++++-
.../camel/dataformat/zipfile/ZipSplitter.java | 16 +++++++++-
.../dataformat/zipfile/ZipFileDataFormatTest.java | 30 +++++++++++++++++++
8 files changed, 128 insertions(+), 4 deletions(-)
diff --git
a/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarFileDataFormat.java
b/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarFileDataFormat.java
index 91255727418a..d65639c5627e 100644
---
a/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarFileDataFormat.java
+++
b/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarFileDataFormat.java
@@ -102,6 +102,7 @@ public class TarFileDataFormat extends ServiceSupport
implements DataFormat, Dat
if (usingIterator) {
TarIterator tarIterator = new TarIterator(exchange, stream);
tarIterator.setAllowEmptyDirectory(allowEmptyDirectory);
+ tarIterator.setMaxDecompressedSize(maxDecompressedSize);
return tarIterator;
} else {
BufferedInputStream bis = new BufferedInputStream(stream);
diff --git
a/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarIterator.java
b/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarIterator.java
index 032a3eacaca8..bfb8f695d797 100644
---
a/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarIterator.java
+++
b/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarIterator.java
@@ -33,6 +33,7 @@ import
org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.io.input.BoundedInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -50,6 +51,7 @@ public class TarIterator implements Iterator<Message>,
Closeable {
private static final Logger LOGGER =
LoggerFactory.getLogger(TarIterator.class);
private final Exchange exchange;
+ private long maxDecompressedSize = -1;
private volatile TarArchiveInputStream tarInputStream;
private volatile Message parent;
private volatile boolean first;
@@ -132,7 +134,18 @@ public class TarIterator implements Iterator<Message>,
Closeable {
answer.setHeader(TARFILE_ENTRY_NAME_HEADER, current.getName());
answer.setHeader(Exchange.FILE_NAME, current.getName());
if (current.getSize() > 0) {
- answer.setBody(new
TarElementInputStreamWrapper(tarInputStream));
+ if (maxDecompressedSize > 0) {
+ answer.setBody(BoundedInputStream.builder()
+ .setInputStream(new
TarElementInputStreamWrapper(tarInputStream))
+ .setMaxCount(maxDecompressedSize)
+ .setOnMaxCount((max, count) -> {
+ throw new IOException(
+ "The InputStream entry being
decompressed exceeds the maximum allowed size");
+ })
+ .get());
+ } else {
+ answer.setBody(new
TarElementInputStreamWrapper(tarInputStream));
+ }
} else {
// Workaround for the case when the entry is zero bytes big
answer.setBody(new ByteArrayInputStream(new byte[0]));
@@ -188,4 +201,12 @@ public class TarIterator implements Iterator<Message>,
Closeable {
public void setAllowEmptyDirectory(boolean allowEmptyDirectory) {
this.allowEmptyDirectory = allowEmptyDirectory;
}
+
+ public long getMaxDecompressedSize() {
+ return maxDecompressedSize;
+ }
+
+ public void setMaxDecompressedSize(long maxDecompressedSize) {
+ this.maxDecompressedSize = maxDecompressedSize;
+ }
}
diff --git
a/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarSplitter.java
b/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarSplitter.java
index 7381a29b4b30..6156f890df9c 100644
---
a/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarSplitter.java
+++
b/components/camel-tarfile/src/main/java/org/apache/camel/dataformat/tarfile/TarSplitter.java
@@ -28,13 +28,27 @@ import org.apache.camel.Message;
*/
public class TarSplitter implements Expression {
+ private static final long DEFAULT_MAXIMUM_DECOMPRESSED_SIZE = 1073741824;
+
+ private long maxDecompressedSize = DEFAULT_MAXIMUM_DECOMPRESSED_SIZE;
+
public TarSplitter() {
}
public Object evaluate(Exchange exchange) {
Message inputMessage = exchange.getIn();
InputStream inputStream = inputMessage.getBody(InputStream.class);
- return new TarIterator(exchange, inputStream);
+ TarIterator tarIterator = new TarIterator(exchange, inputStream);
+ tarIterator.setMaxDecompressedSize(maxDecompressedSize);
+ return tarIterator;
+ }
+
+ public long getMaxDecompressedSize() {
+ return maxDecompressedSize;
+ }
+
+ public void setMaxDecompressedSize(long maxDecompressedSize) {
+ this.maxDecompressedSize = maxDecompressedSize;
}
@Override
diff --git
a/components/camel-tarfile/src/test/java/org/apache/camel/dataformat/tarfile/TarFileDataFormatTest.java
b/components/camel-tarfile/src/test/java/org/apache/camel/dataformat/tarfile/TarFileDataFormatTest.java
index 4ae92ca8197e..3b61cc959b2a 100644
---
a/components/camel-tarfile/src/test/java/org/apache/camel/dataformat/tarfile/TarFileDataFormatTest.java
+++
b/components/camel-tarfile/src/test/java/org/apache/camel/dataformat/tarfile/TarFileDataFormatTest.java
@@ -297,6 +297,24 @@ class TarFileDataFormatTest extends CamelTestSupport {
() -> template.sendBody("direct:untarMaxDecompressedSize",
files));
}
+ @Test
+ void testUntarMaxDecompressedSizeWithIterator() throws Exception {
+ final byte[] files = getTaredText("file");
+
+ // maxDecompressedSize must also be enforced in iterator/splitter mode
+ assertThrows(CamelExecutionException.class,
+ () ->
template.sendBody("direct:untarMaxDecompressedSizeIterator", files));
+ }
+
+ @Test
+ void testUntarMaxDecompressedSizeWithSplitter() throws Exception {
+ final byte[] files = getTaredText("file");
+
+ // maxDecompressedSize must also be enforced via TarSplitter
+ assertThrows(CamelExecutionException.class,
+ () ->
template.sendBody("direct:tarSplitterMaxDecompressedSize", files));
+ }
+
@AfterEach
public void cleanOutputDirectory() {
deleteDirectory(TEST_DIR);
@@ -371,6 +389,22 @@ class TarFileDataFormatTest extends CamelTestSupport {
// Only allow 10 bytes to be decompressed
maxDecompressedSizeTar.setMaxDecompressedSize(10L);
from("direct:untarMaxDecompressedSize").unmarshal(maxDecompressedSizeTar).to("mock:untar");
+
+ TarFileDataFormat maxDecompSizeIterTar = new
TarFileDataFormat();
+ maxDecompSizeIterTar.setUsingIterator(true);
+ maxDecompSizeIterTar.setMaxDecompressedSize(10L);
+ from("direct:untarMaxDecompressedSizeIterator")
+ .unmarshal(maxDecompSizeIterTar)
+ .split(bodyAs(Iterator.class)).streaming()
+ .to("mock:untarMaxDecompressedSizeIterator")
+ .end();
+
+ TarSplitter tarSplitter = new TarSplitter();
+ tarSplitter.setMaxDecompressedSize(10L);
+ from("direct:tarSplitterMaxDecompressedSize")
+ .split(tarSplitter).streaming()
+ .to("mock:tarSplitterMaxDecompressedSize")
+ .end();
}
};
}
diff --git
a/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormat.java
b/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormat.java
index b1b1447e6ea0..4b92ffe23fb4 100644
---
a/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormat.java
+++
b/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormat.java
@@ -105,6 +105,7 @@ public class ZipFileDataFormat extends ServiceSupport
implements DataFormat, Dat
if (usingIterator) {
ZipIterator zipIterator = new ZipIterator(exchange, inputStream);
zipIterator.setAllowEmptyDirectory(allowEmptyDirectory);
+ zipIterator.setMaxDecompressedSize(maxDecompressedSize);
return zipIterator;
} else {
BufferedInputStream bis = new BufferedInputStream(inputStream);
diff --git
a/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipIterator.java
b/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipIterator.java
index 45228890dd11..2849cb330921 100644
---
a/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipIterator.java
+++
b/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipIterator.java
@@ -49,6 +49,7 @@ public class ZipIterator implements Iterator<Message>,
Closeable {
private final Exchange exchange;
private boolean allowEmptyDirectory;
+ private long maxDecompressedSize = -1;
private volatile ZipArchiveInputStream zipInputStream;
private volatile ZipArchiveEntry currentEntry;
private volatile List<CachedOutputStream> cachedOutputStreamsToClose = new
ArrayList<>();
@@ -153,7 +154,7 @@ public class ZipIterator implements Iterator<Message>,
Closeable {
}
} else {
CachedOutputStream cos = new CachedOutputStream(exchange);
- IOHelper.copy(zipInputStream, cos);
+ IOHelper.copy(zipInputStream, cos,
IOHelper.DEFAULT_BUFFER_SIZE, false, maxDecompressedSize);
answer.setBody(cos.getInputStream());
cachedOutputStreamsToClose.add(cos);
}
@@ -214,4 +215,12 @@ public class ZipIterator implements Iterator<Message>,
Closeable {
public void setAllowEmptyDirectory(boolean allowEmptyDirectory) {
this.allowEmptyDirectory = allowEmptyDirectory;
}
+
+ public long getMaxDecompressedSize() {
+ return maxDecompressedSize;
+ }
+
+ public void setMaxDecompressedSize(long maxDecompressedSize) {
+ this.maxDecompressedSize = maxDecompressedSize;
+ }
}
diff --git
a/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipSplitter.java
b/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipSplitter.java
index 98369f35709f..fe23cd2f95af 100644
---
a/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipSplitter.java
+++
b/components/camel-zipfile/src/main/java/org/apache/camel/dataformat/zipfile/ZipSplitter.java
@@ -28,13 +28,27 @@ import org.apache.camel.Message;
*/
public class ZipSplitter implements Expression {
+ private static final long DEFAULT_MAXIMUM_DECOMPRESSED_SIZE = 1073741824;
+
+ private long maxDecompressedSize = DEFAULT_MAXIMUM_DECOMPRESSED_SIZE;
+
public ZipSplitter() {
}
public Object evaluate(Exchange exchange) {
Message inputMessage = exchange.getIn();
InputStream inputStream = inputMessage.getBody(InputStream.class);
- return new ZipIterator(exchange, inputStream);
+ ZipIterator zipIterator = new ZipIterator(exchange, inputStream);
+ zipIterator.setMaxDecompressedSize(maxDecompressedSize);
+ return zipIterator;
+ }
+
+ public long getMaxDecompressedSize() {
+ return maxDecompressedSize;
+ }
+
+ public void setMaxDecompressedSize(long maxDecompressedSize) {
+ this.maxDecompressedSize = maxDecompressedSize;
}
@Override
diff --git
a/components/camel-zipfile/src/test/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormatTest.java
b/components/camel-zipfile/src/test/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormatTest.java
index e129d1c55366..83820f165d69 100644
---
a/components/camel-zipfile/src/test/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormatTest.java
+++
b/components/camel-zipfile/src/test/java/org/apache/camel/dataformat/zipfile/ZipFileDataFormatTest.java
@@ -257,6 +257,20 @@ public class ZipFileDataFormatTest extends
CamelTestSupport {
() -> template.sendBody("direct:unzipMaxDecompressedSize",
getZippedText("file")));
}
+ @Test
+ public void testUnzipMaxDecompressedSizeWithIterator() {
+ // maxDecompressedSize must also be enforced in iterator/splitter mode
+ assertThrows(CamelExecutionException.class,
+ () ->
template.sendBody("direct:unzipMaxDecompressedSizeIterator",
getZippedText("file")));
+ }
+
+ @Test
+ public void testUnzipMaxDecompressedSizeWithSplitter() {
+ // maxDecompressedSize must also be enforced via ZipSplitter
+ assertThrows(CamelExecutionException.class,
+ () ->
template.sendBody("direct:zipSplitterMaxDecompressedSize",
getZippedText("file")));
+ }
+
@Override
public void doPostSetup() {
deleteDirectory(TEST_DIR);
@@ -331,6 +345,22 @@ public class ZipFileDataFormatTest extends
CamelTestSupport {
// Only allow 10 bytes to be decompressed
maxDecompressedSizeZip.setMaxDecompressedSize(10L);
from("direct:unzipMaxDecompressedSize").unmarshal(maxDecompressedSizeZip).to("mock:unzip");
+
+ ZipFileDataFormat maxDecompSizeIterZip = new
ZipFileDataFormat();
+ maxDecompSizeIterZip.setUsingIterator(true);
+ maxDecompSizeIterZip.setMaxDecompressedSize(10L);
+ from("direct:unzipMaxDecompressedSizeIterator")
+ .unmarshal(maxDecompSizeIterZip)
+ .split(bodyAs(Iterator.class)).streaming()
+ .to("mock:unzipMaxDecompressedSizeIterator")
+ .end();
+
+ ZipSplitter zipSplitter = new ZipSplitter();
+ zipSplitter.setMaxDecompressedSize(10L);
+ from("direct:zipSplitterMaxDecompressedSize")
+ .split(zipSplitter).streaming()
+ .to("mock:zipSplitterMaxDecompressedSize")
+ .end();
}
};
}