This is an automated email from the ASF dual-hosted git repository.

oscerd 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 3491e1b7a9ac CAMEL-24936: camel-netty - NettyConverter.toByteArray 
copies only the readable bytes of the ByteBuf (#26781)
3491e1b7a9ac is described below

commit 3491e1b7a9ac70663d83201b4ca47d5ff338109b
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Sep 25 10:57:42 2026 +0200

    CAMEL-24936: camel-netty - NettyConverter.toByteArray copies only the 
readable bytes of the ByteBuf (#26781)
    
    buffer.array() returned the whole backing array, ignoring 
arrayOffset()/readerIndex()/readableBytes();
    for a shared or pooled backing array that can include bytes outside this 
buffer's own slice, and it also
    handed back a reference to a buffer that may later be reused. Always copy 
exactly the readable region
    instead, consistent with the non-array branch, regardless of the underlying 
allocator.
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 .../camel/component/netty/NettyConverter.java      | 19 +++++--------
 .../camel/component/netty/NettyConverterTest.java  | 31 ++++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    | 14 ++++++++++
 3 files changed, 52 insertions(+), 12 deletions(-)

diff --git 
a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConverter.java
 
b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConverter.java
index 36920d1034df..98a4c2ffd3bc 100644
--- 
a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConverter.java
+++ 
b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConverter.java
@@ -32,6 +32,7 @@ import org.w3c.dom.Document;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufAllocator;
 import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.ByteBufUtil;
 import org.apache.camel.Converter;
 import org.apache.camel.Exchange;
 import org.apache.camel.support.DeserializationFilterHelper;
@@ -48,18 +49,12 @@ public final class NettyConverter {
 
     @Converter
     public static byte[] toByteArray(ByteBuf buffer, Exchange exchange) {
-        if (buffer.hasArray()) {
-            return buffer.array();
-        }
-        byte[] bytes = new byte[buffer.readableBytes()];
-        int readerIndex = buffer.readerIndex();
-        buffer.retain();
-        try {
-            buffer.getBytes(readerIndex, bytes);
-        } finally {
-            buffer.release();
-        }
-        return bytes;
+        // Copy only the readable region of the buffer. Returning 
buffer.array() directly would hand back the
+        // whole backing array, ignoring 
arrayOffset()/readerIndex()/readableBytes(): for a shared or pooled
+        // backing array that can include bytes outside this buffer's own 
slice, and it also exposes a reference
+        // to a buffer that may later be reused. ByteBufUtil.getBytes() copies 
exactly the readable bytes for
+        // every buffer kind (heap or direct, pooled or unpooled).
+        return ByteBufUtil.getBytes(buffer);
     }
 
     @Converter
diff --git 
a/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyConverterTest.java
 
b/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyConverterTest.java
index b68f146efd75..bff50bb17686 100644
--- 
a/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyConverterTest.java
+++ 
b/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyConverterTest.java
@@ -16,8 +16,11 @@
  */
 package org.apache.camel.component.netty;
 
+import java.nio.charset.StandardCharsets;
+
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.buffer.Unpooled;
 import org.apache.camel.support.DefaultExchange;
 import org.apache.camel.test.junit6.CamelTestSupport;
 import org.junit.jupiter.api.BeforeEach;
@@ -25,6 +28,7 @@ import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Utility test to verify netty type converter.
@@ -64,4 +68,31 @@ public class NettyConverterTest extends CamelTestSupport {
         assertEquals(PAYLOAD, result);
     }
 
+    /**
+     * A heap (array-backed) buffer whose backing array is larger than the 
readable region, and whose reader index has
+     * been advanced past a prefix, must convert to exactly the readable bytes 
- not the whole backing array. Converting
+     * via buffer.array() used to return the full backing array (prefix + 
payload + spare capacity).
+     */
+    @Test
+    public void testConversionHeapBufferReturnsOnlyReadableBytes() {
+        byte[] payload = PAYLOAD.getBytes(StandardCharsets.UTF_8);
+        byte[] prefix = "SKIP".getBytes(StandardCharsets.UTF_8);
+        // Heap buffer with spare capacity so its backing array is larger than 
the readable region
+        ByteBuf heap = Unpooled.buffer(prefix.length + payload.length + 32);
+        try {
+            heap.writeBytes(prefix);
+            heap.writeBytes(payload);
+            // Skip the prefix: only "payload" is readable now
+            heap.readerIndex(prefix.length);
+
+            assertTrue(heap.hasArray(), "expected an array-backed heap buffer 
for this test");
+
+            byte[] result = NettyConverter.toByteArray(heap, null);
+            assertEquals(payload.length, result.length);
+            assertEquals(PAYLOAD, new String(result, StandardCharsets.UTF_8));
+        } finally {
+            heap.release();
+        }
+    }
+
 }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 3bcd2615c9e2..6b12d19acaab 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -945,6 +945,20 @@ The same default is now also applied to the `ClientConfig` 
that Camel builds for
 endpoints, when neither a referenced `ClientConfig` nor `hazelcastConfigUri` 
is supplied. Client mode
 previously behaved differently from node mode for an otherwise identical 
endpoint configuration.
 
+=== camel-netty - NettyConverter.toByteArray returns a copy of the buffer's 
readable bytes
+
+The `ByteBuf` to `byte[]` type converter (`NettyConverter.toByteArray`, also 
used when converting a Netty
+HTTP response body and by `camel-hl7`, `camel-lumberjack` and `camel-syslog`) 
now always returns a copy of
+exactly the buffer's readable region (`readerIndex()`..`readableBytes()`).
+
+Previously, for an array-backed (heap) buffer it returned the buffer's whole 
backing array directly. That
+could include bytes outside the readable region and, for a pooled buffer, 
bytes belonging to other
+allocations; the returned array was also a live reference into a buffer that 
could later be recycled.
+
+If your code relied on mutating the returned `byte[]` to write through to the 
original `ByteBuf`, that no
+longer has any effect. The converter now behaves consistently for heap and 
direct, pooled and unpooled
+buffers.
+
 === camel-http, camel-http-common, camel-netty-http, camel-undertow, 
camel-vertx-http - property placeholders in HTTP URI override headers
 
 The HTTP producers no longer resolve property placeholders (`{{...}}`) in the 
message-supplied

Reply via email to