System.Net.Http.WinHttpResponseStream.CopyToAsyncCore C# (CSharp) Method

CopyToAsyncCore() private method

private CopyToAsyncCore ( Stream destination, byte buffer, CancellationToken cancellationToken ) : Task
destination System.IO.Stream
buffer byte
cancellationToken System.Threading.CancellationToken
return Task
        private async Task CopyToAsyncCore(Stream destination, byte[] buffer, CancellationToken cancellationToken)
        {
            _state.PinReceiveBuffer(buffer);
            CancellationTokenRegistration ctr = cancellationToken.Register(s => ((WinHttpResponseStream)s).CancelPendingResponseStreamReadOperation(), this);
            _state.AsyncReadInProgress = true;
            try
            {
                // Loop until there's no more data to be read
                while (true)
                {
                    // Query for data available
                    lock (_state.Lock)
                    {
                        if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero))
                        {
                            throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
                        }
                    }
                    int bytesAvailable = await _state.LifecycleAwaitable;
                    if (bytesAvailable == 0)
                    {
                        break;
                    }
                    Debug.Assert(bytesAvailable > 0);

                    // Read the available data
                    cancellationToken.ThrowIfCancellationRequested();
                    lock (_state.Lock)
                    {
                        if (!Interop.WinHttp.WinHttpReadData(_requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), (uint)Math.Min(bytesAvailable, buffer.Length), IntPtr.Zero))
                        {
                            throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
                        }
                    }
                    int bytesRead = await _state.LifecycleAwaitable;
                    if (bytesRead == 0)
                    {
                        break;
                    }
                    Debug.Assert(bytesRead > 0);

                    // Write that data out to the output stream
                    await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
                }
            }
            finally
            {
                _state.AsyncReadInProgress = false;
                ctr.Dispose();
                ArrayPool<byte>.Shared.Return(buffer);
            }

            // Leaving buffer pinned as it is in ReadAsync.  It'll get unpinned when another read
            // request is made with a different buffer or when the state is cleared.
        }