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: <code>boolean</code> 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: <code>boolean</code> 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.
*