private async Task<WebSocketReceiveResult> HandleReceivedCloseAsync(
MessageHeader header, CancellationToken cancellationToken)
{
lock (StateUpdateLock)
{
_receivedCloseFrame = true;
if (_state < WebSocketState.CloseReceived)
{
_state = WebSocketState.CloseReceived;
}
}
WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure;
string closeStatusDescription = string.Empty;
// Handle any payload by parsing it into the close status and description.
if (header.PayloadLength == 1)
{
// The close payload length can be 0 or >= 2, but not 1.
await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false);
}
else if (header.PayloadLength >= 2)
{
if (_receiveBufferCount < header.PayloadLength)
{
await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false);
}
if (_isServer)
{
ApplyMask(_receiveBuffer, _receiveBufferOffset, header.Mask, 0, header.PayloadLength);
}
closeStatus = (WebSocketCloseStatus)(_receiveBuffer[_receiveBufferOffset] << 8 | _receiveBuffer[_receiveBufferOffset + 1]);
if (!IsValidCloseStatus(closeStatus))
{
await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false);
}
if (header.PayloadLength > 2)
{
try
{
closeStatusDescription = s_textEncoding.GetString(_receiveBuffer, _receiveBufferOffset + 2, (int)header.PayloadLength - 2);
}
catch (DecoderFallbackException exc)
{
await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken, exc).ConfigureAwait(false);
}
}
ConsumeFromBuffer((int)header.PayloadLength);
}
// Store the close status and description onto the instance.
_closeStatus = closeStatus;
_closeStatusDescription = closeStatusDescription;
// And return them as part of the result message.
return new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, closeStatus, closeStatusDescription);
}