private async Task GetCancelableWaiterTask(CancellationToken cancellationToken) { using (cancellationToken.UnsafeRegister(s => { var thisRef = (Http2Stream)s; bool signalWaiter; lock (thisRef.SyncObject) { signalWaiter = thisRef._hasWaiter; thisRef._hasWaiter = false; } if (signalWaiter) { // Wake up the wait. It will then immediately check whether cancellation was requested and throw if it was. thisRef._waitSource.SetResult(true); } }, this)) { await new ValueTask(this, _waitSource.Version).ConfigureAwait(false); } CancellationHelper.ThrowIfCancellationRequested(cancellationToken); }
private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancellationToken) { CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { await copyTask.ConfigureAwait(false); } #if MONOTOUCH_WATCH catch (Exception exc) { if (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } throw; } #else catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } #endif finally { ctr.Dispose(); } Finish(); }
public int ReadData(Span <byte> buffer, CancellationToken cancellationToken) { if (buffer.Length == 0) { return(0); } (bool wait, int bytesRead) = TryReadFromBuffer(buffer); if (wait) { // Synchronously block waiting for data to be produced. Debug.Assert(bytesRead == 0); GetWaiterTask(cancellationToken).GetAwaiter().GetResult(); CancellationHelper.ThrowIfCancellationRequested(cancellationToken); (wait, bytesRead) = TryReadFromBuffer(buffer); Debug.Assert(!wait); } if (bytesRead != 0) { ExtendWindow(bytesRead); _connection.ExtendWindow(bytesRead); } return(bytesRead); }
public static async ValueTask <(Socket, Stream)> ConnectAsync(string host, int port, CancellationToken cancellationToken) { // Rather than creating a new Socket and calling ConnectAsync on it, we use the static // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync // to cancel it if needed. Rent or allocate one. ConnectEventArgs saea; if (!s_connectEventArgs.TryDequeue(out saea)) { saea = new ConnectEventArgs(); } try { saea.Initialize(cancellationToken); // Configure which server to which to connect. saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ? (EndPoint) new IPEndPoint(address, port) : new DnsEndPoint(host, port); // Initiate the connection. if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea)) { // Connect completing asynchronously. Enable it to be canceled and wait for it. using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea)) { await saea.Builder.Task.ConfigureAwait(false); } } else if (saea.SocketError != SocketError.Success) { // Connect completed synchronously but unsuccessfully. throw new SocketException((int)saea.SocketError); } Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}."); Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket"); // Configure the socket and return a stream for it. Socket socket = saea.ConnectSocket; socket.NoDelay = true; return(socket, new NetworkStream(socket, ownsSocket: true)); } catch (Exception error) { throw CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ? CancellationHelper.CreateOperationCanceledException(error, cancellationToken) : new HttpRequestException(error.Message, error); } finally { // Pool the event args, or if the pool is full, dispose of it. saea.Clear(); if (!s_connectEventArgs.TryEnqueue(saea)) { saea.Dispose(); } } }
private static Stream Connect(string host, int port, CancellationToken cancellationToken) { // For synchronous connections, we can just create a socket and make the connection. cancellationToken.ThrowIfCancellationRequested(); var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); try { socket.NoDelay = true; using (cancellationToken.UnsafeRegister(s => ((Socket)s !).Dispose(), socket)) { socket.Connect(new DnsEndPoint(host, port)); } } catch (Exception e) { socket.Dispose(); if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken); } throw; } return(new NetworkStream(socket, ownsSocket: true)); }
private async Task CopyToAsyncCore(Stream destination, CancellationToken cancellationToken) { CancellationTokenRegistration ctr = _connection !.RegisterCancellation(cancellationToken); try { while (true) { while (true) { if (ReadChunkFromConnectionBuffer(int.MaxValue, ctr) is not ReadOnlyMemory <byte> bytesRead || bytesRead.Length == 0) { break; } await destination.WriteAsync(bytesRead, cancellationToken).ConfigureAwait(false); } if (_connection == null) { // Fully consumed the response. return; } await _connection.FillAsync(async : true).ConfigureAwait(false); } } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } }
private static async ValueTask <SslStream> EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) { SslStream sslStream = new SslStream(stream); try { await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false); } catch (Exception e) { sslStream.Dispose(); if (e is OperationCanceledException) { throw; } if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken); } throw new HttpRequestException(SR.net_http_ssl_connection_failed, e); } // Handle race condition if cancellation happens after SSL auth completes but before the registration is disposed if (cancellationToken.IsCancellationRequested) { sslStream.Dispose(); throw CancellationHelper.CreateOperationCanceledException(null, cancellationToken); } return(sslStream); }
private async Task CompleteCopyToAsync(Task copyTask, HttpConnection connection, CancellationToken cancellationToken) { CancellationTokenRegistration ctr = connection.RegisterCancellation(cancellationToken); try { await copyTask.ConfigureAwait(false); } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } 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. CancellationHelper.ThrowIfCancellationRequested(cancellationToken); Finish(connection); }
public override async ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken) { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); 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); } #if MONOTOUCH_WATCH catch (Exception exc) { if (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } throw; } #else catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } #endif finally { ctr.Dispose(); } } if (bytesRead == 0) { // A cancellation request may have caused the EOF. CancellationHelper.ThrowIfCancellationRequested(cancellationToken); // We cannot reuse this connection, so close it. _connection.Dispose(); _connection = null; return(0); } return(bytesRead); }
public override async ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken) { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); 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.ReadAsync(buffer); int bytesRead; if (readTask.IsCompletedSuccessfully) { bytesRead = readTask.Result; } else { CancellationTokenRegistration ctr = connection.RegisterCancellation(cancellationToken); try { bytesRead = await readTask.ConfigureAwait(false); } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } } if (bytesRead == 0) { // If cancellation is requested and tears down the connection, it could cause the read // to return 0, which would otherwise signal the end of the data, but that would lead // the caller to think that it actually received all of the data, rather than it ending // early due to cancellation. So we prioritize cancellation in this race condition, and // if we read 0 bytes and then find that cancellation has requested, we assume cancellation // was the cause and throw. CancellationHelper.ThrowIfCancellationRequested(cancellationToken); // We cannot reuse this connection, so close it. if (HttpTelemetry.IsEnabled) { LogRequestStop(); } _connection = null; connection.Dispose(); } return(bytesRead); }
public static async ValueTask <Stream> ConnectAsync(Func <SocketsHttpConnectionContext, CancellationToken, ValueTask <Stream> > callback, DnsEndPoint endPoint, HttpRequestMessage requestMessage, CancellationToken cancellationToken) { try { return(await callback(new SocketsHttpConnectionContext(endPoint, requestMessage), cancellationToken).ConfigureAwait(false)); } catch (OperationCanceledException ex) when(ex.CancellationToken == cancellationToken) { throw CancellationHelper.CreateOperationCanceledException(innerException: null, cancellationToken); } catch (Exception ex) { throw CreateWrappedException(ex, endPoint.Host, endPoint.Port, cancellationToken); } }
public static async ValueTask <Connection> ConnectAsync(ConnectionFactory factory, DnsEndPoint endPoint, IConnectionProperties?options, CancellationToken cancellationToken) { try { return(await factory.ConnectAsync(endPoint, options, cancellationToken).ConfigureAwait(false)); } catch (OperationCanceledException ex) when(ex.CancellationToken == cancellationToken) { throw CancellationHelper.CreateOperationCanceledException(innerException: null, cancellationToken); } catch (Exception ex) { throw CreateWrappedException(ex, endPoint.Host, endPoint.Port, cancellationToken); } }
public override async ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken) { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); HttpConnection?connection = _connection; if (connection == null) { // Response body fully consumed 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); } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } } if (bytesRead == 0 && buffer.Length != 0) { // A cancellation request may have caused the EOF. CancellationHelper.ThrowIfCancellationRequested(cancellationToken); // We cannot reuse this connection, so close it. _connection = null; connection.Dispose(); } return(bytesRead); }
public static async ValueTask <Stream> ConnectAsync(string host, int port, CancellationToken cancellationToken) { // Rather than creating a new Socket and calling ConnectAsync on it, we use the static // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync // to cancel it if needed. var saea = new ConnectEventArgs(); try { saea.Initialize(cancellationToken); // Configure which server to which to connect. saea.RemoteEndPoint = new DnsEndPoint(host, port); // Initiate the connection. if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea)) { // Connect completing asynchronously. Enable it to be canceled and wait for it. using (cancellationToken.UnsafeRegister(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea)) { await saea.Builder.Task.ConfigureAwait(false); } } else if (saea.SocketError != SocketError.Success) { // Connect completed synchronously but unsuccessfully. throw new SocketException((int)saea.SocketError); } Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}."); Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket"); // Configure the socket and return a stream for it. Socket socket = saea.ConnectSocket; socket.NoDelay = true; return(new ExposedSocketNetworkStream(socket, ownsSocket: true)); } catch (Exception error) when(!(error is OperationCanceledException)) { throw CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ? CancellationHelper.CreateOperationCanceledException(error, cancellationToken) : new HttpRequestException(error.Message, error, RequestRetryType.RetryOnNextProxy); } finally { saea.Dispose(); } }
private async Task WaitWithConnectionCancellationAsync(Task task, CancellationToken cancellationToken) { CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { await task.ConfigureAwait(false); } catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } }
private ValueTask GetWaiterTask(CancellationToken cancellationToken) { // No locking is required here to access _waitSource. To be here, we've already updated _hasWaiter (while holding the lock) // to indicate that we would be creating this waiter, and at that point the only code that could be await'ing _waitSource or // Reset'ing it is this code here. It's possible for this to race with the _waitSource being completed, but that's ok and is // handled by _waitSource as one of its primary purposes. We can't assert _hasWaiter here, though, as once we released the // lock, a producer could have seen _hasWaiter as true and both set it to false and signaled _waitSource. // With HttpClient, the supplied cancellation token will always be cancelable, as HttpClient supplies a token that // will have cancellation requested if CancelPendingRequests is called (or when a non-infinite Timeout expires). // However, this could still be non-cancelable if HttpMessageInvoker was used, at which point this will only be // cancelable if the caller's token was cancelable. To avoid the extra allocation here in such a case, we make // this pay-for-play: if the token isn't cancelable, return a ValueTask wrapping this object directly, and only // if it is cancelable, then register for the cancellation callback, allocate a task for the asynchronously // completing case, etc. return(cancellationToken.CanBeCanceled ? new ValueTask(GetWaiterTaskCore()) : new ValueTask(this, _waitSource.Version)); async Task GetWaiterTaskCore() { using (cancellationToken.UnsafeRegister(s => { var thisRef = (Http2Stream)s; bool signalWaiter; lock (thisRef.SyncObject) { signalWaiter = thisRef._hasWaiter; thisRef._hasWaiter = false; } if (signalWaiter) { // Wake up the wait. It will then immediately check whether cancellation was requested and throw if it was. thisRef._waitSource.SetResult(true); } }, this)) { await new ValueTask(this, _waitSource.Version).ConfigureAwait(false); } CancellationHelper.ThrowIfCancellationRequested(cancellationToken); } }
private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancellationToken) { Debug.Assert(_connection != null); CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { await copyTask.ConfigureAwait(false); } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } Finish(); }
public static async ValueTask <T> CancelationHelper <T>(Task <T> promise, CancellationToken cancellationToken, JSObject?abortController = null, JSObject?fetchResponse = null) { if (promise.IsCompletedSuccessfully) { return(promise.Result); } try { using (var operationRegistration = cancellationToken.Register(() => { CancelablePromise.CancelPromise(promise); if (abortController != null) { AbortRequest(abortController); } if (fetchResponse != null) { AbortResponse(fetchResponse); } })) { return(await promise.ConfigureAwait(true)); } } catch (OperationCanceledException oce) when(cancellationToken.IsCancellationRequested) { throw CancellationHelper.CreateOperationCanceledException(oce, cancellationToken); } catch (JSException jse) { if (jse.Message.StartsWith("AbortError", StringComparison.Ordinal)) { throw CancellationHelper.CreateOperationCanceledException(jse, CancellationToken.None); } if (cancellationToken.IsCancellationRequested) { throw CancellationHelper.CreateOperationCanceledException(jse, cancellationToken); } throw new HttpRequestException(jse.Message, jse); } }
protected override void OnCompleted(SocketAsyncEventArgs _) { switch (SocketError) { case SocketError.Success: Builder.SetResult(); break; case SocketError.OperationAborted: case SocketError.ConnectionAborted: if (CancellationToken.IsCancellationRequested) { Builder.SetException(CancellationHelper.CreateOperationCanceledException(null, CancellationToken)); break; } goto default; default: Builder.SetException(new SocketException((int)SocketError)); break; } }
private async Task GetWaiterTask(CancellationToken cancellationToken) { var vt = new ValueTask(this, _waitSource.Version).AsTask(); using (cancellationToken.Register(s => { Http2Stream stream = (Http2Stream)s; bool signalWaiter; lock (stream.SyncObject) { signalWaiter = stream._hasWaiter; stream._hasWaiter = false; } if (signalWaiter) { stream._waitSource.SetException(new OperationCanceledException()); } }, this)) { await vt.ConfigureAwait(false); } CancellationHelper.ThrowIfCancellationRequested(cancellationToken); }
private static async ValueTask <SslStream> EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) { SslStream sslStream = new SslStream(stream); // TODO #25206 and #24430: Register/IsCancellationRequested should be removable once SslStream auth and sockets respect cancellation. CancellationTokenRegistration ctr = cancellationToken.Register(s => ((Stream)s).Dispose(), stream); try { await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false); } catch (Exception e) { sslStream.Dispose(); if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken); } throw new HttpRequestException(SR.net_http_ssl_connection_failed, e); } finally { ctr.Dispose(); } // Handle race condition if cancellation happens after SSL auth completes but before the registration is disposed if (cancellationToken.IsCancellationRequested) { sslStream.Dispose(); throw CancellationHelper.CreateOperationCanceledException(null, cancellationToken); } return(sslStream); }
private async ValueTask <int> ReadAsyncCore(Memory <byte> buffer, CancellationToken cancellationToken) { // Should only be called if ReadChunksFromConnectionBuffer returned 0. Debug.Assert(_connection != null); Debug.Assert(buffer.Length > 0); CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { while (true) { if (_connection == null) { // Fully consumed the response in ReadChunksFromConnectionBuffer. return(0); } if (_state == ParsingState.ExpectChunkData && buffer.Length >= _connection.ReadBufferSize && _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize) { // As an optimization, we skip going through the connection's read buffer if both // the remaining chunk data and the buffer are both at least as large // as the connection buffer. That avoids an unnecessary copy while still reading // the maximum amount we'd otherwise read at a time. Debug.Assert(_connection.RemainingBuffer.Length == 0); int bytesRead = await _connection.ReadAsync(buffer.Slice(0, (int)Math.Min((ulong)buffer.Length, _chunkBytesRemaining))).ConfigureAwait(false); if (bytesRead == 0) { throw new IOException(SR.Format(SR.net_http_invalid_response_premature_eof_bytecount, _chunkBytesRemaining)); } _chunkBytesRemaining -= (ulong)bytesRead; if (_chunkBytesRemaining == 0) { _state = ParsingState.ExpectChunkTerminator; } return(bytesRead); } // We're only here if we need more data to make forward progress. await _connection.FillAsync().ConfigureAwait(false); // Now that we have more, see if we can get any response data, and if // we can we're done. int bytesCopied = ReadChunksFromConnectionBuffer(buffer.Span, ctr); if (bytesCopied > 0) { return(bytesCopied); } } } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } }
private async ValueTask <int> ReadAsyncCore(Memory <byte> buffer, CancellationToken cancellationToken) { // Should only be called if ReadChunksFromConnectionBuffer returned 0. Debug.Assert(_connection != null); CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { while (true) { if (_connection == null) { // Fully consumed the response in ReadChunksFromConnectionBuffer. return(0); } if (_state == ParsingState.ExpectChunkData && buffer.Length >= _connection.ReadBufferSize && _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize) { // As an optimization, we skip going through the connection's read buffer if both // the remaining chunk data and the buffer are both at least as large // as the connection buffer. That avoids an unnecessary copy while still reading // the maximum amount we'd otherwise read at a time. Debug.Assert(_connection.RemainingBuffer.Length == 0); Debug.Assert(buffer.Length != 0); int bytesRead = await _connection.ReadAsync(buffer.Slice(0, (int)Math.Min((ulong)buffer.Length, _chunkBytesRemaining))).ConfigureAwait(false); if (bytesRead == 0) { throw new IOException(SR.Format(SR.net_http_invalid_response_premature_eof_bytecount, _chunkBytesRemaining)); } _chunkBytesRemaining -= (ulong)bytesRead; if (_chunkBytesRemaining == 0) { _state = ParsingState.ExpectChunkTerminator; } return(bytesRead); } if (buffer.Length == 0) { // User requested a zero-byte read, and we have no data available in the buffer for processing. // This zero-byte read indicates their desire to trade off the extra cost of a zero-byte read // for reduced memory consumption when data is not immediately available. // So, we will issue our own zero-byte read against the underlying stream to allow it to make use of // optimizations, such as deferring buffer allocation until data is actually available. await _connection.ReadAsync(buffer).ConfigureAwait(false); } // We're only here if we need more data to make forward progress. await _connection.FillAsync(async : true).ConfigureAwait(false); // Now that we have more, see if we can get any response data, and if // we can we're done. if (buffer.Length == 0) { if (PeekChunkFromConnectionBuffer()) { return(0); } } else { int bytesCopied = ReadChunksFromConnectionBuffer(buffer.Span, ctr); if (bytesCopied > 0) { return(bytesCopied); } } } } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } }
public override async ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken) { CancellationHelper.ThrowIfCancellationRequested(cancellationToken); if (_connection == null || buffer.Length == 0) { // Response body fully consumed or the caller didn't ask for any data return(0); } Debug.Assert(_contentBytesRemaining > 0); if ((ulong)buffer.Length > _contentBytesRemaining) { buffer = buffer.Slice(0, (int)_contentBytesRemaining); } ValueTask <int> readTask = _connection.ReadAsync(buffer); int bytesRead; if (readTask.IsCompletedSuccessfully) { bytesRead = readTask.Result; } else { CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken); try { bytesRead = await readTask.ConfigureAwait(false); } catch (Exception exc) when(CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken)) { throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken); } finally { ctr.Dispose(); } } if (bytesRead <= 0) { // A cancellation request may have caused the EOF. CancellationHelper.ThrowIfCancellationRequested(cancellationToken); // Unexpected end of response stream. throw new IOException(SR.Format(SR.net_http_invalid_response_premature_eof_bytecount, _contentBytesRemaining)); } Debug.Assert((ulong)bytesRead <= _contentBytesRemaining); _contentBytesRemaining -= (ulong)bytesRead; if (_contentBytesRemaining == 0) { // End of response body _connection.CompleteResponse(); _connection = null; } return(bytesRead); }
private static Exception CreateWrappedException(Exception error, string host, int port, CancellationToken cancellationToken) { return(CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ? CancellationHelper.CreateOperationCanceledException(error, cancellationToken) : new HttpRequestException($"{error.Message} ({host}:{port})", error, RequestRetryType.RetryOnNextProxy)); }
private static Exception CreateWrappedException(Exception error, CancellationToken cancellationToken) { return(CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ? CancellationHelper.CreateOperationCanceledException(error, cancellationToken) : new HttpRequestException(error.Message, error, RequestRetryType.RetryOnNextProxy)); }
public static async ValueTask <(Socket, Stream)> ConnectAsync(string host, int port, CancellationToken cancellationToken) { try { // Rather than creating a new Socket and calling ConnectAsync on it, we use the static // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync // to cancel it if needed. using (var saea = new BuilderAndCancellationTokenSocketAsyncEventArgs(cancellationToken)) { // Configure which server to which to connect. saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ? (EndPoint) new IPEndPoint(address, port) : new DnsEndPoint(host, port); // Hook up a callback that'll complete the Task when the operation completes. saea.Completed += (s, e) => { var csaea = (BuilderAndCancellationTokenSocketAsyncEventArgs)e; switch (e.SocketError) { case SocketError.Success: csaea.Builder.SetResult(); break; case SocketError.OperationAborted: case SocketError.ConnectionAborted: if (csaea.CancellationToken.IsCancellationRequested) { csaea.Builder.SetException(CancellationHelper.CreateOperationCanceledException(null, csaea.CancellationToken)); break; } goto default; default: csaea.Builder.SetException(new SocketException((int)e.SocketError)); break; } }; // Initiate the connection. if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea)) { // Connect completing asynchronously. Enable it to be canceled and wait for it. using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea)) { await saea.Builder.Task.ConfigureAwait(false); } } else if (saea.SocketError != SocketError.Success) { // Connect completed synchronously but unsuccessfully. throw new SocketException((int)saea.SocketError); } Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}."); Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket"); // Configure the socket and return a stream for it. Socket socket = saea.ConnectSocket; socket.NoDelay = true; return(socket, new NetworkStream(socket, ownsSocket: true)); } } catch (Exception error) { throw CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ? CancellationHelper.CreateOperationCanceledException(error, cancellationToken) : new HttpRequestException(error.Message, error); } }