public async override Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken)
{
ThrowIfDisposed();
ThrowIfInputClosed();
ValidateSegment(buffer);
// TODO: InvalidOperationException if any receives are currently in progress.
// No active frame. Loop because we may be discarding ping/pong frames.
while (_frameInProgress == null)
{
await ReadNextFrameAsync(cancellationToken);
}
int opCode = _frameInProgress.OpCode;
if (opCode == Constants.OpCodes.CloseFrame)
{
return await ProcessCloseFrameAsync(cancellationToken);
}
// Handle fragmentation, remember the first frame type
if (opCode == Constants.OpCodes.ContinuationFrame)
{
if (!_firstDataOpCode.HasValue)
{
await SendErrorAbortAndThrow(WebSocketCloseStatus.ProtocolError, "Invalid continuation frame", cancellationToken);
}
opCode = _firstDataOpCode.Value;
}
else
{
_firstDataOpCode = opCode;
}
// Make sure there's at least some data in the buffer
int bytesToBuffer = (int)Math.Min((long)_receiveBuffer.Length, _frameBytesRemaining);
await EnsureDataAvailableOrReadAsync(bytesToBuffer, cancellationToken);
// Copy buffered data to the users buffer
int bytesToRead = (int)Math.Min((long)buffer.Count, _frameBytesRemaining);
int bytesToCopy = Math.Min(bytesToRead, _receiveBufferBytes);
Array.Copy(_receiveBuffer, _receiveBufferOffset, buffer.Array, buffer.Offset, bytesToCopy);
if (_unmaskInput)
{
// _frameInProgress.Masked == _unmaskInput already verified
Utilities.MaskInPlace(_frameInProgress.MaskKey, ref _dataUnmaskOffset, new ArraySegment<byte>(buffer.Array, buffer.Offset, bytesToCopy));
}
WebSocketReceiveResult result;
WebSocketMessageType messageType = Utilities.GetMessageType(opCode);
if (messageType == WebSocketMessageType.Text
&& !Utilities.TryValidateUtf8(new ArraySegment<byte>(buffer.Array, buffer.Offset, bytesToCopy), _frameInProgress.Fin, _incomingUtf8MessageState))
{
await SendErrorAbortAndThrow(WebSocketCloseStatus.InvalidPayloadData, "Invalid UTF-8", cancellationToken);
}
if (bytesToCopy == _frameBytesRemaining)
{
result = new WebSocketReceiveResult(bytesToCopy, messageType, _frameInProgress.Fin);
if (_frameInProgress.Fin)
{
_firstDataOpCode = null;
}
_frameInProgress = null;
_dataUnmaskOffset = 0;
}
else
{
result = new WebSocketReceiveResult(bytesToCopy, messageType, false);
}
_frameBytesRemaining -= bytesToCopy;
_receiveBufferBytes -= bytesToCopy;
_receiveBufferOffset += bytesToCopy;
return result;
}