< Summary

Information
Class: System.Net.Http.HttpConnectionWaiter<T>
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\ConnectionPool\HttpConnectionWaiter.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 77
Coverable lines: 77
Total lines: 125
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 48
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
WaitForConnectionAsync(...)0%12120%
WaitForConnectionWithTelemetryAsync()0%12120%
TrySignal(...)0%880%
SetTimeoutToPendingConnectionAttempt(...)0%16160%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\ConnectionPool\HttpConnectionWaiter.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Threading;
 6using System.Threading.Tasks;
 7
 8namespace System.Net.Http
 9{
 10    internal sealed class HttpConnectionWaiter<T> : TaskCompletionSourceWithCancellation<T>
 11        where T : HttpConnectionBase?
 12    {
 13        // When a connection attempt is pending, reference the connection's CTS, so we can tear it down if the initiatin
 14        // or completes on a different connection.
 15        public CancellationTokenSource? ConnectionCancellationTokenSource;
 16
 17        // Distinguish connection cancellation that happens because the initiating request is cancelled or completed on 
 018        public bool CancelledByOriginatingRequestCompletion { get; set; }
 19
 20        public ValueTask<T> WaitForConnectionAsync(HttpRequestMessage request, HttpConnectionPool pool, bool async, Canc
 021        {
 022            bool withTelemetry = HttpTelemetry.Log.IsEnabled()
 023                                || (GlobalHttpSettings.MetricsHandler.IsGloballyEnabled && pool.Settings._metrics!.Reque
 024                                || (GlobalHttpSettings.DiagnosticsHandler.EnableActivityPropagation && Activity.Current?
 025            return withTelemetry
 026                ? WaitForConnectionWithTelemetryAsync(request, pool, async, requestCancellationToken)
 027                : WaitWithCancellationAsync(async, requestCancellationToken);
 028        }
 29
 30        private async ValueTask<T> WaitForConnectionWithTelemetryAsync(HttpRequestMessage request, HttpConnectionPool po
 031        {
 32            // The HTTP/3 connection waiting span should include the time spent waiting for an available QUIC stream, th
 033            Debug.Assert(typeof(T) == typeof(HttpConnection) || typeof(T) == typeof(Http2Connection));
 34
 035            long startingTimestamp = Stopwatch.GetTimestamp();
 36
 037            using Activity? waitForConnectionActivity = ConnectionSetupDistributedTracing.StartWaitForConnectionActivity
 38            try
 039            {
 040                return await WaitWithCancellationAsync(async, requestCancellationToken).ConfigureAwait(false);
 41            }
 042            catch (Exception ex) when (waitForConnectionActivity is not null)
 043            {
 044                ConnectionSetupDistributedTracing.ReportError(waitForConnectionActivity, ex);
 045                throw;
 46            }
 47            finally
 048            {
 049                if (HttpTelemetry.Log.IsEnabled() || GlobalHttpSettings.MetricsHandler.IsGloballyEnabled)
 050                {
 051                    TimeSpan duration = Stopwatch.GetElapsedTime(startingTimestamp);
 052                    int versionMajor = typeof(T) == typeof(HttpConnection) ? 1 : 2;
 053                    if (GlobalHttpSettings.MetricsHandler.IsGloballyEnabled)
 054                    {
 055                        pool.Settings._metrics!.RequestLeftQueue(request, pool, duration, versionMajor);
 056                    }
 57
 058                    if (HttpTelemetry.Log.IsEnabled())
 059                    {
 060                        HttpTelemetry.Log.RequestLeftQueue(versionMajor, duration);
 061                    }
 062                }
 063            }
 064        }
 65
 66        public bool TrySignal(T connection)
 067        {
 068            Debug.Assert(connection is not null);
 69
 070            if (TrySetResult(connection))
 071            {
 072                if (NetEventSource.Log.IsEnabled()) connection.Trace("Dequeued waiting request.");
 073                return true;
 74            }
 75            else
 076            {
 077                if (NetEventSource.Log.IsEnabled())
 078                {
 079                    connection.Trace(Task.IsCanceled
 080                        ? "Discarding canceled request from queue."
 081                        : "Discarding signaled request waiter from queue.");
 082                }
 083                return false;
 84            }
 085        }
 86
 87        public void SetTimeoutToPendingConnectionAttempt(HttpConnectionPool pool, bool requestCancelled)
 088        {
 089            int timeout = GlobalHttpSettings.SocketsHttpHandler.PendingConnectionTimeoutOnRequestCompletion;
 090            if (ConnectionCancellationTokenSource is null ||
 091                timeout == Timeout.Infinite ||
 092                pool.Settings._connectTimeout != Timeout.InfiniteTimeSpan && timeout > (int)pool.Settings._connectTimeou
 093            {
 094                return;
 95            }
 96
 097            lock (this)
 098            {
 099                if (ConnectionCancellationTokenSource is null)
 0100                {
 0101                    return;
 102                }
 103
 0104                if (NetEventSource.Log.IsEnabled())
 0105                {
 0106                    pool.Trace($"Initiating cancellation of a pending connection attempt with delay of {timeout} ms, " +
 0107                        $"Reason: {(requestCancelled ? "Request cancelled" : "Request served by another connection")}.")
 0108                }
 109
 0110                CancelledByOriginatingRequestCompletion = true;
 0111                if (timeout > 0)
 0112                {
 113                    // Cancel after the specified timeout. This cancellation will not fire if the connection
 114                    // succeeds within the delay and the CTS becomes disposed.
 0115                    ConnectionCancellationTokenSource.CancelAfter(timeout);
 0116                }
 117                else
 0118                {
 119                    // Cancel immediately if no timeout specified.
 0120                    ConnectionCancellationTokenSource.Cancel();
 0121                }
 0122            }
 0123        }
 124    }
 125}