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();
             }
         };
     }

Reply via email to