private static async Task WaitWithConnectionCancellationAsync(ValueTask task, HttpConnection connection, CancellationToken cancellationToken) { CancellationTokenRegistration ctr = connection.RegisterCancellation(cancellationToken); try { await task.ConfigureAwait(false); } finally { ctr.Dispose(); } }
public override async ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); HttpConnection connection = _connection; if (connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data return(0); } ValueTask <int> readTask = connection.ReadBufferedAsync(buffer); int bytesRead; if (readTask.IsCompletedSuccessfully) { bytesRead = readTask.Result; } else { CancellationTokenRegistration ctr = connection.RegisterCancellation(cancellationToken); try { bytesRead = await readTask.ConfigureAwait(false); } finally { ctr.Dispose(); } } if (bytesRead == 0) { // A cancellation request may have caused the EOF. cancellationToken.ThrowIfCancellationRequested(); // We cannot reuse this connection, so close it. _connection = null; connection.Dispose(); } return(bytesRead); }
private async Task CompleteCopyToAsync(Task copyTask, HttpConnection connection, CancellationToken cancellationToken) { CancellationTokenRegistration ctr = connection.RegisterCancellation(cancellationToken); try { await copyTask.ConfigureAwait(false); } finally { ctr.Dispose(); } // If cancellation is requested and tears down the connection, it could cause the copy // to end early but think it ended successfully. So we prioritize cancellation in this // race condition, and if we find after the copy has completed that cancellation has // been requested, we assume the copy completed due to cancellation and throw. cancellationToken.ThrowIfCancellationRequested(); Finish(connection); }