diff --git a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.cs b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.cs
index 880d7a0af1..eb6ed265ad 100644
--- a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.cs
+++ b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.cs
@@ -820,6 +820,32 @@ namespace Opc.Ua.Bindings
return TakeSavedChunks();
}
+ ///
+ /// Whether a final chunk is a whole message by itself, which most are: no
+ /// chunks of the message are saved, the partial message is not closed and
+ /// the chunk is within the message limits. The caller then processes the
+ /// chunk directly instead of passing it to ,
+ /// and keeps owning its buffer.
+ ///
+ /// The body of the final chunk.
+ /// Whether the chunk is part of a request.
+ protected bool IsSingleChunkMessage(ArraySegment chunk, bool isServerContext)
+ {
+ if (chunk.Array == null)
+ {
+ return false;
+ }
+ lock (m_partialMessageLock)
+ {
+ if (m_partialMessageClosed || m_partialMessageChunks != null)
+ {
+ return false;
+ }
+ }
+ // a chunk over the limits takes the path that reports them.
+ return !MessageLimitsExceeded(isServerContext, chunk.Count, 1);
+ }
+
///
/// Detaches the chunks saved so far without offering another one. Used
/// where the final chunk has already been saved and only the collection
diff --git a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs
index 297e827beb..b39c58895d 100644
--- a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs
+++ b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryClientChannel.cs
@@ -2033,6 +2033,7 @@ namespace Opc.Ua.Bindings
}
BufferCollection? chunksToProcess = null;
+ ArraySegment singleChunk = default;
try
{
// check for an abort.
@@ -2062,11 +2063,18 @@ namespace Opc.Ua.Bindings
return true;
}
- // get the chunks to process.
- chunksToProcess = GetSavedChunks(requestId, messageBody, false, gateHeld: false);
-
- // get response.
- operation.MessageBody = ParseResponse(chunksToProcess);
+ // get response: a response in one chunk, which most are, is decoded
+ // from that chunk without a collection of the chunks.
+ if (IsSingleChunkMessage(messageBody, isServerContext: false))
+ {
+ singleChunk = messageBody;
+ operation.MessageBody = DecodeMessage(singleChunk, Quotas.MessageContext);
+ }
+ else
+ {
+ chunksToProcess = GetSavedChunks(requestId, messageBody, false, gateHeld: false);
+ operation.MessageBody = ParseResponse(chunksToProcess);
+ }
if (operation.MessageBody == null)
{
@@ -2095,6 +2103,7 @@ namespace Opc.Ua.Bindings
finally
{
chunksToProcess?.Release(BufferManager, "ProcessResponseMessage");
+ ReturnBuffer(singleChunk, "ProcessResponseMessage");
}
}