private async Task EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken, bool throwOnPrematureClosure = true)
{
Debug.Assert(minimumRequiredBytes <= _receiveBuffer.Length, $"Requested number of bytes {minimumRequiredBytes} must not exceed {_receiveBuffer.Length}");
// If we don't have enough data in the buffer to satisfy the minimum required, read some more.
if (_receiveBufferCount < minimumRequiredBytes)
{
// If there's any data in the buffer, shift it down.
if (_receiveBufferCount > 0)
{
Buffer.BlockCopy(_receiveBuffer, _receiveBufferOffset, _receiveBuffer, 0, _receiveBufferCount);
}
_receiveBufferOffset = 0;
// While we don't have enough data, read more.
while (_receiveBufferCount < minimumRequiredBytes)
{
int numRead = await _stream.ReadAsync(_receiveBuffer, _receiveBufferCount, _receiveBuffer.Length - _receiveBufferCount, cancellationToken).ConfigureAwait(false);
Debug.Assert(numRead >= 0, $"Expected non-negative bytes read, got {numRead}");
_receiveBufferCount += numRead;
if (numRead == 0)
{
// The connection closed before we were able to read everything we needed.
// If it was due to use being disposed, fail. If it was due to the connection
// being closed and it wasn't expected, fail. If it was due to the connection
// being closed and that was expected, exit gracefully.
if (_disposed)
{
throw new ObjectDisposedException(nameof(ClientWebSocket));
}
else if (throwOnPrematureClosure)
{
throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely);
}
break;
}
}
}
}