mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-27 21:55:54 +08:00
Client channel: decode a single-chunk response without a chunk collection
A final chunk was saved into a new BufferCollection and taken back out even when it was the whole response. When no chunks of the message are saved, the partial message is open and the chunk is within the limits, the response is now decoded from the chunk directly and its buffer returned afterwards; anything else takes the saved-chunks path as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2135f7d7f9
commit
70655ffa07
@@ -820,6 +820,32 @@ namespace Opc.Ua.Bindings
|
|||||||
return TakeSavedChunks();
|
return TakeSavedChunks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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 <see cref="GetSavedChunks"/>,
|
||||||
|
/// and keeps owning its buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunk">The body of the final chunk.</param>
|
||||||
|
/// <param name="isServerContext">Whether the chunk is part of a request.</param>
|
||||||
|
protected bool IsSingleChunkMessage(ArraySegment<byte> 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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Detaches the chunks saved so far without offering another one. Used
|
/// Detaches the chunks saved so far without offering another one. Used
|
||||||
/// where the final chunk has already been saved and only the collection
|
/// where the final chunk has already been saved and only the collection
|
||||||
|
|||||||
@@ -2033,6 +2033,7 @@ namespace Opc.Ua.Bindings
|
|||||||
}
|
}
|
||||||
|
|
||||||
BufferCollection? chunksToProcess = null;
|
BufferCollection? chunksToProcess = null;
|
||||||
|
ArraySegment<byte> singleChunk = default;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// check for an abort.
|
// check for an abort.
|
||||||
@@ -2062,11 +2063,18 @@ namespace Opc.Ua.Bindings
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the chunks to process.
|
// get response: a response in one chunk, which most are, is decoded
|
||||||
chunksToProcess = GetSavedChunks(requestId, messageBody, false, gateHeld: false);
|
// from that chunk without a collection of the chunks.
|
||||||
|
if (IsSingleChunkMessage(messageBody, isServerContext: false))
|
||||||
// get response.
|
{
|
||||||
operation.MessageBody = ParseResponse(chunksToProcess);
|
singleChunk = messageBody;
|
||||||
|
operation.MessageBody = DecodeMessage<IServiceResponse>(singleChunk, Quotas.MessageContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chunksToProcess = GetSavedChunks(requestId, messageBody, false, gateHeld: false);
|
||||||
|
operation.MessageBody = ParseResponse(chunksToProcess);
|
||||||
|
}
|
||||||
|
|
||||||
if (operation.MessageBody == null)
|
if (operation.MessageBody == null)
|
||||||
{
|
{
|
||||||
@@ -2095,6 +2103,7 @@ namespace Opc.Ua.Bindings
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
chunksToProcess?.Release(BufferManager, "ProcessResponseMessage");
|
chunksToProcess?.Release(BufferManager, "ProcessResponseMessage");
|
||||||
|
ReturnBuffer(singleChunk, "ProcessResponseMessage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user