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 31afb62070f0 CAMEL-26508: camel-netty - with transferExchange the 
consumer keeps its own connection headers (#28991)
31afb62070f0 is described below

commit 31afb62070f07ee8240914ad8e70c742a8a220dc
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Nov 3 07:28:08 2026 +0100

    CAMEL-26508: camel-netty - with transferExchange the consumer keeps its own 
connection headers (#28991)
    
    * CAMEL-26508: camel-netty - with transferExchange the consumer keeps i…
    
    …ts own connection headers
    
    With transferExchange=true the consumer set the headers it derives from the
    connection (CamelNettyRemoteAddress, CamelNettyLocalAddress, the SSL 
session and
    the CamelNettySSLClientCert* headers) and then unmarshalled the received
    exchange, which replaced all headers with the ones of the transferred 
exchange.
    
    The connection it accepted is the source of truth: the connection headers 
and
    properties set before unmarshalling are now set again afterwards, and the 
ones in
    the transferred exchange are not kept, also when the consumer has no value 
for
    them. The producer receiving a transferExchange reply does the same. The
    transferExchange option description and the upgrade guide say so.
    
    * Merge remote-tracking branch 'origin/main' into CAMEL-26508-netty-tra…
    
    …nsfer-exchange-headers
    
    
    # Conflicts:
    #       docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
    
    * CAMEL-26508: camel-netty - address review comments
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../camel/catalog/components/netty-http.json       |   4 +-
 .../org/apache/camel/catalog/components/netty.json |   4 +-
 .../camel/component/netty/http/netty-http.json     |   4 +-
 .../org/apache/camel/component/netty/netty.json    |   4 +-
 .../camel/component/netty/NettyConfiguration.java  |  11 +-
 .../camel/component/netty/NettyPayloadHelper.java  |  53 ++++++-
 ...NettyTransferExchangeConnectionHeadersTest.java | 157 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  10 ++
 .../dsl/NettyComponentBuilderFactory.java          |   8 +-
 .../dsl/NettyHttpComponentBuilderFactory.java      |   8 +-
 .../endpoint/dsl/NettyEndpointBuilderFactory.java  |  48 ++++++-
 .../dsl/NettyHttpEndpointBuilderFactory.java       |  48 ++++++-
 12 files changed, 331 insertions(+), 28 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json
index 226aa49cc714..f80cea968801 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty-http.json
@@ -77,7 +77,7 @@
     "receiveBufferSizePredictor": { "index": 49, "kind": "property", 
"displayName": "Receive Buffer Size Predictor", "group": "advanced", "label": 
"advanced", "required": false, "type": "integer", "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Configures the buffer size predictor. See 
details at Jetty documentation and this mail [...]
     "sendBufferSize": { "index": 50, "kind": "property", "displayName": "Send 
Buffer Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 65536, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "The TCP\/UDP buffer sizes to be used during 
outbound communication. Size is bytes." },
     "shutdownTimeout": { "index": 51, "kind": "property", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Shutdown await timeout in milliseconds" },
-    "transferExchange": { "index": 52, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
+    "transferExchange": { "index": 52, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
     "udpByteArrayCodec": { "index": 53, "kind": "property", "displayName": 
"Udp Byte Array Codec", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, 
"configurationClass": "org.apache.camel.component.netty.NettyConfiguration", 
"configurationField": "configuration", "description": "For UDP only. If enabled 
the using byte array codec instead of Java serializa [...]
     "unixDomainSocketPath": { "index": 54, "kind": "property", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Path to unix domain socket to use instead of 
inet socket. Host and port parameters wil [...]
     "workerCount": { "index": 55, "kind": "property", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "When netty works on nio mode, it uses default 
workerCount parameter from Netty (which is cpu_core_threads x 2). User c [...]
@@ -207,7 +207,7 @@
     "shutdownTimeout": { "index": 66, "kind": "parameter", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Shutdown await timeout 
in milliseconds" },
     "synchronous": { "index": 67, "kind": "parameter", "displayName": 
"Synchronous", "group": "advanced", "label": "advanced", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Sets whether synchronous 
processing should be strictly used" },
     "transferException": { "index": 68, "kind": "parameter", "displayName": 
"Transfer Exception", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "If enabled and an 
Exchange fail [...]
-    "transferExchange": { "index": 69, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Only used for TCP. You 
can transf [...]
+    "transferExchange": { "index": 69, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Only used for TCP. You 
can transf [...]
     "unixDomainSocketPath": { "index": 70, "kind": "parameter", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Path to unix domain 
socket to use instead of inet socket. Host and port para [...]
     "workerCount": { "index": 71, "kind": "parameter", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "When netty works on nio 
mode, it uses default workerCount parameter from Netty (which is 
cpu_core_threads x  [...]
     "workerGroup": { "index": 72, "kind": "parameter", "displayName": "Worker 
Group", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "io.netty.channel.EventLoopGroup", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "To use a explicit 
EventLoopGroup as the boss thread pool. For example to share a  [...]
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json
index 8212556f4fa2..88538fe4a404 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/netty.json
@@ -74,7 +74,7 @@
     "receiveBufferSizePredictor": { "index": 47, "kind": "property", 
"displayName": "Receive Buffer Size Predictor", "group": "advanced", "label": 
"advanced", "required": false, "type": "integer", "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Configures the buffer size predictor. See 
details at Jetty documentation and this mail [...]
     "sendBufferSize": { "index": 48, "kind": "property", "displayName": "Send 
Buffer Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 65536, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "The TCP\/UDP buffer sizes to be used during 
outbound communication. Size is bytes." },
     "shutdownTimeout": { "index": 49, "kind": "property", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Shutdown await timeout in milliseconds" },
-    "transferExchange": { "index": 50, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
+    "transferExchange": { "index": 50, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
     "udpByteArrayCodec": { "index": 51, "kind": "property", "displayName": 
"Udp Byte Array Codec", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, 
"configurationClass": "org.apache.camel.component.netty.NettyConfiguration", 
"configurationField": "configuration", "description": "For UDP only. If enabled 
the using byte array codec instead of Java serializa [...]
     "unixDomainSocketPath": { "index": 52, "kind": "property", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Path to unix domain socket to use instead of 
inet socket. Host and port parameters wil [...]
     "workerCount": { "index": 53, "kind": "property", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "When netty works on nio mode, it uses default 
workerCount parameter from Netty (which is cpu_core_threads x 2). User c [...]
@@ -175,7 +175,7 @@
     "sendBufferSize": { "index": 50, "kind": "parameter", "displayName": "Send 
Buffer Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 65536, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "The TCP\/UDP buffer sizes to be used during 
outbound communication. Size is bytes." },
     "shutdownTimeout": { "index": 51, "kind": "parameter", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Shutdown await timeout in milliseconds" },
     "synchronous": { "index": 52, "kind": "parameter", "displayName": 
"Synchronous", "group": "advanced", "label": "advanced", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "description": "Sets whether 
synchronous processing should be strictly used" },
-    "transferExchange": { "index": 53, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the ex 
[...]
+    "transferExchange": { "index": 53, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the ex 
[...]
     "udpByteArrayCodec": { "index": 54, "kind": "parameter", "displayName": 
"Udp Byte Array Codec", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, 
"configurationClass": "org.apache.camel.component.netty.NettyConfiguration", 
"configurationField": "configuration", "description": "For UDP only. If enabled 
the using byte array codec instead of Java serializ [...]
     "unixDomainSocketPath": { "index": 55, "kind": "parameter", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Path to unix domain socket to use instead of 
inet socket. Host and port parameters wi [...]
     "workerCount": { "index": 56, "kind": "parameter", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "When netty works on nio mode, it uses default 
workerCount parameter from Netty (which is cpu_core_threads x 2). User  [...]
diff --git 
a/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json
 
b/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json
index 226aa49cc714..f80cea968801 100644
--- 
a/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json
+++ 
b/components/camel-netty-http/src/generated/resources/META-INF/org/apache/camel/component/netty/http/netty-http.json
@@ -77,7 +77,7 @@
     "receiveBufferSizePredictor": { "index": 49, "kind": "property", 
"displayName": "Receive Buffer Size Predictor", "group": "advanced", "label": 
"advanced", "required": false, "type": "integer", "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Configures the buffer size predictor. See 
details at Jetty documentation and this mail [...]
     "sendBufferSize": { "index": 50, "kind": "property", "displayName": "Send 
Buffer Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 65536, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "The TCP\/UDP buffer sizes to be used during 
outbound communication. Size is bytes." },
     "shutdownTimeout": { "index": 51, "kind": "property", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Shutdown await timeout in milliseconds" },
-    "transferExchange": { "index": 52, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
+    "transferExchange": { "index": 52, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
     "udpByteArrayCodec": { "index": 53, "kind": "property", "displayName": 
"Udp Byte Array Codec", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, 
"configurationClass": "org.apache.camel.component.netty.NettyConfiguration", 
"configurationField": "configuration", "description": "For UDP only. If enabled 
the using byte array codec instead of Java serializa [...]
     "unixDomainSocketPath": { "index": 54, "kind": "property", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Path to unix domain socket to use instead of 
inet socket. Host and port parameters wil [...]
     "workerCount": { "index": 55, "kind": "property", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "When netty works on nio mode, it uses default 
workerCount parameter from Netty (which is cpu_core_threads x 2). User c [...]
@@ -207,7 +207,7 @@
     "shutdownTimeout": { "index": 66, "kind": "parameter", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Shutdown await timeout 
in milliseconds" },
     "synchronous": { "index": 67, "kind": "parameter", "displayName": 
"Synchronous", "group": "advanced", "label": "advanced", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Sets whether synchronous 
processing should be strictly used" },
     "transferException": { "index": 68, "kind": "parameter", "displayName": 
"Transfer Exception", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "If enabled and an 
Exchange fail [...]
-    "transferExchange": { "index": 69, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Only used for TCP. You 
can transf [...]
+    "transferExchange": { "index": 69, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Only used for TCP. You 
can transf [...]
     "unixDomainSocketPath": { "index": 70, "kind": "parameter", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "Path to unix domain 
socket to use instead of inet socket. Host and port para [...]
     "workerCount": { "index": 71, "kind": "parameter", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "When netty works on nio 
mode, it uses default workerCount parameter from Netty (which is 
cpu_core_threads x  [...]
     "workerGroup": { "index": 72, "kind": "parameter", "displayName": "Worker 
Group", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "io.netty.channel.EventLoopGroup", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.http.NettyHttpConfiguration", 
"configurationField": "configuration", "description": "To use a explicit 
EventLoopGroup as the boss thread pool. For example to share a  [...]
diff --git 
a/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json
 
b/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json
index 8212556f4fa2..88538fe4a404 100644
--- 
a/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json
+++ 
b/components/camel-netty/src/generated/resources/META-INF/org/apache/camel/component/netty/netty.json
@@ -74,7 +74,7 @@
     "receiveBufferSizePredictor": { "index": 47, "kind": "property", 
"displayName": "Receive Buffer Size Predictor", "group": "advanced", "label": 
"advanced", "required": false, "type": "integer", "javaType": "int", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Configures the buffer size predictor. See 
details at Jetty documentation and this mail [...]
     "sendBufferSize": { "index": 48, "kind": "property", "displayName": "Send 
Buffer Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 65536, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "The TCP\/UDP buffer sizes to be used during 
outbound communication. Size is bytes." },
     "shutdownTimeout": { "index": 49, "kind": "property", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Shutdown await timeout in milliseconds" },
-    "transferExchange": { "index": 50, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
+    "transferExchange": { "index": 50, "kind": "property", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the exc 
[...]
     "udpByteArrayCodec": { "index": 51, "kind": "property", "displayName": 
"Udp Byte Array Codec", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, 
"configurationClass": "org.apache.camel.component.netty.NettyConfiguration", 
"configurationField": "configuration", "description": "For UDP only. If enabled 
the using byte array codec instead of Java serializa [...]
     "unixDomainSocketPath": { "index": 52, "kind": "property", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Path to unix domain socket to use instead of 
inet socket. Host and port parameters wil [...]
     "workerCount": { "index": 53, "kind": "property", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "When netty works on nio mode, it uses default 
workerCount parameter from Netty (which is cpu_core_threads x 2). User c [...]
@@ -175,7 +175,7 @@
     "sendBufferSize": { "index": 50, "kind": "parameter", "displayName": "Send 
Buffer Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 65536, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "The TCP\/UDP buffer sizes to be used during 
outbound communication. Size is bytes." },
     "shutdownTimeout": { "index": 51, "kind": "parameter", "displayName": 
"Shutdown Timeout", "group": "advanced", "label": "advanced", "required": 
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 100, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Shutdown await timeout in milliseconds" },
     "synchronous": { "index": 52, "kind": "parameter", "displayName": 
"Synchronous", "group": "advanced", "label": "advanced", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "description": "Sets whether 
synchronous processing should be strictly used" },
-    "transferExchange": { "index": 53, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the ex 
[...]
+    "transferExchange": { "index": 53, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "security": "insecure:serialization", 
"defaultValue": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Only used for TCP. You can transfer the ex 
[...]
     "udpByteArrayCodec": { "index": 54, "kind": "parameter", "displayName": 
"Udp Byte Array Codec", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, 
"configurationClass": "org.apache.camel.component.netty.NettyConfiguration", 
"configurationField": "configuration", "description": "For UDP only. If enabled 
the using byte array codec instead of Java serializ [...]
     "unixDomainSocketPath": { "index": 55, "kind": "parameter", "displayName": 
"Unix Domain Socket Path", "group": "advanced", "label": "advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "Path to unix domain socket to use instead of 
inet socket. Host and port parameters wi [...]
     "workerCount": { "index": 56, "kind": "parameter", "displayName": "Worker 
Count", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.netty.NettyConfiguration", "configurationField": 
"configuration", "description": "When netty works on nio mode, it uses default 
workerCount parameter from Netty (which is cpu_core_threads x 2). User  [...]
diff --git 
a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConfiguration.java
 
b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConfiguration.java
index 0533043928d9..a6a3ecb3a87a 100644
--- 
a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConfiguration.java
+++ 
b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyConfiguration.java
@@ -97,7 +97,11 @@ public class NettyConfiguration extends 
NettyServerBootstrapConfiguration implem
               description = "Only used for TCP. You can transfer the exchange 
over the wire instead of just the body. The following fields are"
                             + " transferred: In body, Out body, fault body, In 
headers, Out headers, fault headers, exchange properties, exchange"
                             + " exception. This requires that the objects are 
serializable. Camel will exclude any non-serializable objects and"
-                            + " log it at WARN level.")
+                            + " log it at WARN level. The connection headers 
(CamelNettyRemoteAddress, CamelNettyLocalAddress,"
+                            + " CamelNettyChannelHandlerContext, 
CamelNettySSLSession and the CamelNettySSLClientCert headers) and the"
+                            + " CamelNettyRemoteAddress and CamelNettyChannel 
exchange properties are always the ones of the receiving"
+                            + " side: the connection it accepted is the source 
of truth, and these values are never taken from the"
+                            + " transferred exchange.")
     private boolean transferExchange;
     @UriParam(label = "advanced", security = "insecure:serialization",
               description = "Only used for TCP when transferExchange is true. 
When set to true, serializable objects in headers and properties"
@@ -581,7 +585,10 @@ public class NettyConfiguration extends 
NettyServerBootstrapConfiguration implem
      * Only used for TCP. You can transfer the exchange over the wire instead 
of just the body. The following fields are
      * transferred: In body, Out body, fault body, In headers, Out headers, 
fault headers, exchange properties, exchange
      * exception. This requires that the objects are serializable. Camel will 
exclude any non-serializable objects and
-     * log it at WARN level.
+     * log it at WARN level. The connection headers (CamelNettyRemoteAddress, 
CamelNettyLocalAddress,
+     * CamelNettyChannelHandlerContext, CamelNettySSLSession and the 
CamelNettySSLClientCert headers) and the
+     * CamelNettyRemoteAddress and CamelNettyChannel exchange properties are 
always the ones of the receiving side: the
+     * connection it accepted is the source of truth, and these values are 
never taken from the transferred exchange.
      */
     public void setTransferExchange(boolean transferExchange) {
         this.transferExchange = transferExchange;
diff --git 
a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyPayloadHelper.java
 
b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyPayloadHelper.java
index eb3a0b7ca9f6..8585789e0e8d 100644
--- 
a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyPayloadHelper.java
+++ 
b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyPayloadHelper.java
@@ -17,6 +17,8 @@
 package org.apache.camel.component.netty;
 
 import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.AddressedEnvelope;
@@ -108,13 +110,13 @@ public final class NettyPayloadHelper {
 
     public static void setIn(Exchange exchange, Object payload) {
         if (payload instanceof DefaultExchangeHolder defaultExchangeHolder) {
-            DefaultExchangeHolder.unmarshal(exchange, defaultExchangeHolder);
+            unmarshal(exchange, defaultExchangeHolder);
         } else if (payload instanceof AddressedEnvelope) {
             @SuppressWarnings("unchecked")
             AddressedEnvelope<Object, InetSocketAddress> dp = 
(AddressedEnvelope<Object, InetSocketAddress>) payload;
             // need to check if the content is ExchangeHolder
             if (dp.content() instanceof DefaultExchangeHolder 
defaultExchangeHolder) {
-                DefaultExchangeHolder.unmarshal(exchange, 
defaultExchangeHolder);
+                unmarshal(exchange, defaultExchangeHolder);
             } else {
                 // need to take out the payload here
                 exchange.getIn().setBody(dp.content());
@@ -131,13 +133,13 @@ public final class NettyPayloadHelper {
 
     public static void setOut(Exchange exchange, Object payload) {
         if (payload instanceof DefaultExchangeHolder defaultExchangeHolder) {
-            DefaultExchangeHolder.unmarshal(exchange, defaultExchangeHolder);
+            unmarshal(exchange, defaultExchangeHolder);
         } else if (payload instanceof AddressedEnvelope) {
             @SuppressWarnings("unchecked")
             AddressedEnvelope<Object, InetSocketAddress> dp = 
(AddressedEnvelope<Object, InetSocketAddress>) payload;
             // need to check if the content is ExchangeHolder
             if (dp.content() instanceof DefaultExchangeHolder 
defaultExchangeHolder) {
-                DefaultExchangeHolder.unmarshal(exchange, 
defaultExchangeHolder);
+                unmarshal(exchange, defaultExchangeHolder);
             } else {
                 // need to take out the payload here
                 exchange.getOut().setBody(dp.content());
@@ -151,4 +153,47 @@ public final class NettyPayloadHelper {
         }
     }
 
+    /**
+     * The headers and exchange properties that describe the Netty connection 
of this side.
+     */
+    private static final String[] CONNECTION_KEYS = {
+            NettyConstants.NETTY_CHANNEL_HANDLER_CONTEXT, 
NettyConstants.NETTY_REMOTE_ADDRESS,
+            NettyConstants.NETTY_LOCAL_ADDRESS, NettyConstants.NETTY_CHANNEL,
+            NettyConstants.NETTY_SSL_SESSION, 
NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME,
+            NettyConstants.NETTY_SSL_CLIENT_CERT_ISSUER_NAME, 
NettyConstants.NETTY_SSL_CLIENT_CERT_SERIAL_NO,
+            NettyConstants.NETTY_SSL_CLIENT_CERT_NOT_BEFORE, 
NettyConstants.NETTY_SSL_CLIENT_CERT_NOT_AFTER };
+
+    /**
+     * Unmarshals the transferred exchange into the exchange, but keeps the 
connection headers and exchange properties
+     * of this side: the connection this side accepted (or opened) is the 
source of truth for them. A connection header
+     * or property in the transferred exchange is never used, also when this 
side has no value for it (for example the
+     * SSL client certificate headers when the connection has no client 
certificate).
+     */
+    private static void unmarshal(Exchange exchange, DefaultExchangeHolder 
holder) {
+        Map<String, Object> headers = new HashMap<>();
+        Map<String, Object> properties = new HashMap<>();
+        for (String key : CONNECTION_KEYS) {
+            Object value = exchange.getIn().getHeader(key);
+            if (value != null) {
+                headers.put(key, value);
+            }
+            value = exchange.getProperty(key);
+            if (value != null) {
+                properties.put(key, value);
+            }
+        }
+
+        DefaultExchangeHolder.unmarshal(exchange, holder);
+
+        for (String key : CONNECTION_KEYS) {
+            exchange.getIn().removeHeader(key);
+            if (exchange.hasOut()) {
+                exchange.getOut().removeHeader(key);
+            }
+            exchange.removeProperty(key);
+        }
+        headers.forEach(exchange.getIn()::setHeader);
+        properties.forEach(exchange::setProperty);
+    }
+
 }
diff --git 
a/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyTransferExchangeConnectionHeadersTest.java
 
b/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyTransferExchangeConnectionHeadersTest.java
new file mode 100644
index 000000000000..360185c2913f
--- /dev/null
+++ 
b/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyTransferExchangeConnectionHeadersTest.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.netty;
+
+import java.io.File;
+import java.net.InetSocketAddress;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.handler.codec.serialization.ClassResolvers;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.netty.codec.ObjectDecoder;
+import org.apache.camel.component.netty.codec.ObjectEncoder;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * With transferExchange the consumer keeps its own connection headers: the 
connection it accepted is the source of
+ * truth, so the connection headers and properties in the transferred exchange 
are not used.
+ */
+@DisabledIfSystemProperty(named = "java.vendor", matches = ".*ibm.*")
+public class NettyTransferExchangeConnectionHeadersTest extends BaseNettyTest {
+
+    private static final String CLIENT_CERT_SUBJECT
+            = "SERIALNUMBER=1234567890, CN=CommonName, OU=Unit, O=Org, L=Loc, 
ST=State, C=US";
+    private static final String CODECS = 
"&encoders=#encoder&decoders=#decoder";
+    private static final String SSL_OPTIONS = 
"&ssl=true&passphrase=changeit&keyStoreResource=#ksf&trustStoreResource=#tsf";
+
+    @RegisterExtension
+    AvailablePortFinder.Port sslPort = AvailablePortFinder.find();
+
+    @BindToRegistry("ksf")
+    public File loadKeystoreKsf() {
+        return new File("src/test/resources/keystore.jks");
+    }
+
+    @BindToRegistry("tsf")
+    public File loadKeystoreTsf() {
+        return new File("src/test/resources/keystore.jks");
+    }
+
+    @BindToRegistry("encoder")
+    public ChannelHandler getEncoder() {
+        return new ShareableChannelHandlerFactory(new ObjectEncoder());
+    }
+
+    @BindToRegistry("decoder")
+    public ChannelHandler getDecoder() {
+        return new DefaultChannelHandlerFactory() {
+            @Override
+            public ChannelHandler newChannelHandler() {
+                return new 
ObjectDecoder(ClassResolvers.weakCachingResolver(null));
+            }
+        };
+    }
+
+    @Test
+    public void testConsumerKeepsItsConnectionHeaders() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:plain");
+        mock.expectedBodiesReceived("Hello World");
+        mock.expectedHeaderReceived("cheese", "gouda");
+
+        Exchange reply = 
template.request("netty:tcp://localhost:{{port}}?sync=true&transferExchange=true"
 + CODECS, e -> {
+            e.getIn().setBody("Hello World");
+            e.getIn().setHeader("cheese", "gouda");
+            e.getIn().setHeader(NettyConstants.NETTY_REMOTE_ADDRESS, 
"10.1.2.3:4567");
+            e.getIn().setHeader(NettyConstants.NETTY_LOCAL_ADDRESS, 
"10.1.2.3:8910");
+            
e.getIn().setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME, 
"CN=Sender");
+            
e.getIn().setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SERIAL_NO, "42");
+            e.setProperty(NettyConstants.NETTY_REMOTE_ADDRESS, 
"10.1.2.3:4567");
+        });
+        assertNull(reply.getException());
+
+        MockEndpoint.assertIsSatisfied(context);
+
+        Exchange received = mock.getReceivedExchanges().get(0);
+        Message in = received.getIn();
+        // the addresses of the connection the consumer accepted
+        assertInstanceOf(InetSocketAddress.class, 
in.getHeader(NettyConstants.NETTY_REMOTE_ADDRESS));
+        InetSocketAddress local = assertInstanceOf(InetSocketAddress.class, 
in.getHeader(NettyConstants.NETTY_LOCAL_ADDRESS));
+        assertEquals(getPort(), local.getPort());
+        // no client certificate on this connection, so no client certificate 
headers
+        
assertNull(in.getHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME));
+        
assertNull(in.getHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SERIAL_NO));
+        assertNull(received.getProperty(NettyConstants.NETTY_REMOTE_ADDRESS));
+
+        // the producer keeps its own connection headers too: the reply has 
none from the consumer
+        Message message = reply.getMessage();
+        assertEquals("Bye World", message.getBody());
+        assertEquals("cheddar", message.getHeader("cheese"));
+        
assertNull(message.getHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME));
+        assertNull(message.getHeader(NettyConstants.NETTY_REMOTE_ADDRESS));
+    }
+
+    @Test
+    public void testConsumerKeepsItsClientCertHeaders() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:ssl");
+        mock.expectedBodiesReceived("Hello World");
+        
mock.expectedHeaderReceived(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME, 
CLIENT_CERT_SUBJECT);
+        
mock.expectedHeaderReceived(NettyConstants.NETTY_SSL_CLIENT_CERT_ISSUER_NAME, 
CLIENT_CERT_SUBJECT);
+        
mock.expectedHeaderReceived(NettyConstants.NETTY_SSL_CLIENT_CERT_SERIAL_NO, 
"1234567890");
+
+        Exchange reply = template.request(
+                "netty:tcp://localhost:" + sslPort.getPort() + 
"?sync=true&transferExchange=true" + CODECS + SSL_OPTIONS, e -> {
+                    e.getIn().setBody("Hello World");
+                    
e.getIn().setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME, 
"CN=Sender");
+                    
e.getIn().setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_ISSUER_NAME, 
"CN=Sender CA");
+                    
e.getIn().setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SERIAL_NO, "42");
+                });
+        assertNull(reply.getException());
+        assertEquals("Bye World", reply.getMessage().getBody());
+
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("netty:tcp://localhost:{{port}}?sync=true&transferExchange=true" + CODECS)
+                        .to("mock:plain")
+                        .setHeader("cheese", constant("cheddar"))
+                        
.setHeader(NettyConstants.NETTY_SSL_CLIENT_CERT_SUBJECT_NAME, 
constant("CN=Consumer"))
+                        .transform().constant("Bye World");
+
+                from("netty:tcp://localhost:" + sslPort.getPort() + 
"?sync=true&transferExchange=true" + CODECS + SSL_OPTIONS
+                     + "&needClientAuth=true&sslClientCertHeaders=true")
+                        .to("mock:ssl")
+                        .transform().constant("Bye World");
+            }
+        };
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 10f5a47c1b89..f31bdcef0c23 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -1938,6 +1938,16 @@ with `allowSerializedHeaders=true`, the socket address 
headers (`java.net.InetSo
 default deserialization filter of `ObjectDecoder`, which rejects `java.net` 
classes, made the other side fail to decode
 the message unless the route removed them.
 
+=== camel-netty - with transferExchange the consumer keeps its own connection 
headers
+
+With `transferExchange=true` the connection headers `CamelNettyRemoteAddress`, 
`CamelNettyLocalAddress`,
+`CamelNettyChannelHandlerContext`, `CamelNettySSLSession` and the 
`CamelNettySSLClientCert*` headers (and the
+`CamelNettyRemoteAddress` and `CamelNettyChannel` exchange properties) are now 
always the ones of the receiving side:
+the connection it accepted is the source of truth. Before, the headers of the 
transferred exchange replaced them. Such
+a header in the transferred exchange is no longer used, also when the 
receiving side has no value for it (for example
+the `CamelNettySSLClientCert*` headers on a connection without a client 
certificate). This also applies to the reply
+the producer receives. Send any such value of the sender under a header name 
of your own.
+
 === camel-netty-http - a response that cannot be built
 
 When no HTTP response can be built from the reply of the route (for example 
the body cannot be converted), the consumer
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyComponentBuilderFactory.java
index cdf2d4149756..0777bc5cd231 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyComponentBuilderFactory.java
@@ -1013,7 +1013,13 @@ public interface NettyComponentBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
          * 
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyHttpComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyHttpComponentBuilderFactory.java
index 7f7827923079..89c70c7e5674 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyHttpComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/NettyHttpComponentBuilderFactory.java
@@ -1049,7 +1049,13 @@ public interface NettyHttpComponentBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
          * 
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyEndpointBuilderFactory.java
index 5a030ee0db58..6b43702e3a2a 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyEndpointBuilderFactory.java
@@ -1727,7 +1727,13 @@ public interface NettyEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -1747,7 +1753,13 @@ public interface NettyEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
@@ -3447,7 +3459,13 @@ public interface NettyEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -3467,7 +3485,13 @@ public interface NettyEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
@@ -4617,7 +4641,13 @@ public interface NettyEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -4637,7 +4667,13 @@ public interface NettyEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyHttpEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyHttpEndpointBuilderFactory.java
index 70d5c635d5db..babd707ab4a8 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyHttpEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/NettyHttpEndpointBuilderFactory.java
@@ -2178,7 +2178,13 @@ public interface NettyHttpEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -2198,7 +2204,13 @@ public interface NettyHttpEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
@@ -3929,7 +3941,13 @@ public interface NettyHttpEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -3949,7 +3967,13 @@ public interface NettyHttpEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
@@ -5138,7 +5162,13 @@ public interface NettyHttpEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -5158,7 +5188,13 @@ public interface NettyHttpEndpointBuilderFactory {
          * body, Out body, fault body, In headers, Out headers, fault headers,
          * exchange properties, exchange exception. This requires that the
          * objects are serializable. Camel will exclude any non-serializable
-         * objects and log it at WARN level.
+         * objects and log it at WARN level. The connection headers
+         * (CamelNettyRemoteAddress, CamelNettyLocalAddress,
+         * CamelNettyChannelHandlerContext, CamelNettySSLSession and the
+         * CamelNettySSLClientCert headers) and the CamelNettyRemoteAddress and
+         * CamelNettyChannel exchange properties are always the ones of the
+         * receiving side: the connection it accepted is the source of truth,
+         * and these values are never taken from the transferred exchange.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 

Reply via email to