< Summary

Information
Class: System.Net.Http.HttpClientHandler
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\HttpClientHandler.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 122
Coverable lines: 122
Total lines: 380
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 30
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
Dispose(...)0%440%
Send(...)100%110%
SendAsync(...)100%110%
ThrowForModifiedManagedSslOptionsIfStarted()100%110%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\HttpClientHandler.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.Globalization;
 5using System.Net.Security;
 6using System.Collections.Generic;
 7using System.Runtime.Versioning;
 8using System.Security.Authentication;
 9using System.Security.Cryptography.X509Certificates;
 10using System.Threading;
 11using System.Threading.Tasks;
 12using System.Diagnostics.Metrics;
 13#if TARGET_BROWSER
 14using System.Diagnostics;
 15using System.Net.Http.Metrics;
 16using HttpHandlerType = System.Net.Http.BrowserHttpHandler;
 17#else
 18using HttpHandlerType = System.Net.Http.SocketsHttpHandler;
 19#endif
 20
 21namespace System.Net.Http
 22{
 23    public partial class HttpClientHandler : HttpMessageHandler
 24    {
 25        private readonly HttpHandlerType _underlyingHandler;
 26
 27#if TARGET_BROWSER
 28        private IMeterFactory? _meterFactory;
 29        private HttpMessageHandler? _firstHandler; // DiagnosticsHandler or MetricsHandler, depending on global configur
 30
 31        private HttpMessageHandler Handler
 32        {
 33            get
 34            {
 35                if (_firstHandler != null)
 36                {
 37                    return _firstHandler;
 38                }
 39
 40                HttpMessageHandler handler = _underlyingHandler;
 41
 42                // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http
 43                // metric is recorded before stopping the request Activity. This is needed to make sure that our telemet
 44                // Since HttpClientHandler.Proxy is unsupported on most platforms, don't bother passing it to telemetry 
 45                if (GlobalHttpSettings.MetricsHandler.IsGloballyEnabled)
 46                {
 47                    handler = new MetricsHandler(handler, _meterFactory, proxy: null, out _);
 48                }
 49                if (GlobalHttpSettings.DiagnosticsHandler.EnableActivityPropagation)
 50                {
 51                    handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current, proxy: null);
 52                }
 53
 54                // Ensure a single handler is used for all requests.
 55                if (Interlocked.CompareExchange(ref _firstHandler, handler, null) != null)
 56                {
 57                    handler.Dispose();
 58                }
 59
 60                return _firstHandler;
 61            }
 62        }
 63#else
 064        private HttpHandlerType Handler => _underlyingHandler;
 65#endif
 66
 67        private volatile bool _disposed;
 68
 069        public HttpClientHandler()
 070        {
 071            _underlyingHandler = new HttpHandlerType();
 72
 073            ClientCertificateOptions = ClientCertificateOption.Manual;
 074        }
 75
 76        protected override void Dispose(bool disposing)
 077        {
 078            if (disposing && !_disposed)
 079            {
 080                _disposed = true;
 081                _underlyingHandler.Dispose();
 082            }
 83
 084            base.Dispose(disposing);
 085        }
 86
 087        public virtual bool SupportsAutomaticDecompression => HttpHandlerType.SupportsAutomaticDecompression;
 088        public virtual bool SupportsProxy => HttpHandlerType.SupportsProxy;
 089        public virtual bool SupportsRedirectConfiguration => HttpHandlerType.SupportsRedirectConfiguration;
 90
 91        /// <summary>
 92        /// Gets or sets the <see cref="IMeterFactory"/> to create a custom <see cref="Meter"/> for the <see cref="HttpC
 93        /// </summary>
 94        /// <remarks>
 95        /// When <see cref="MeterFactory"/> is set to a non-<see langword="null"/> value, all metrics emitted by the <se
 96        /// will be recorded using the <see cref="Meter"/> provided by the <see cref="IMeterFactory"/>.
 97        /// </remarks>
 98        [CLSCompliant(false)]
 99        public IMeterFactory? MeterFactory
 100        {
 101#if TARGET_BROWSER
 102            get => _meterFactory;
 103            set
 104            {
 105                ObjectDisposedException.ThrowIf(_disposed, this);
 106                if (_firstHandler != null)
 107                {
 108                    throw new InvalidOperationException(SR.net_http_operation_started);
 109                }
 110                _meterFactory = value;
 111            }
 112#else
 0113            get => _underlyingHandler.MeterFactory;
 0114            set => _underlyingHandler.MeterFactory = value;
 115#endif
 116        }
 117
 118        [UnsupportedOSPlatform("browser")]
 119        public bool UseCookies
 120        {
 0121            get => _underlyingHandler.UseCookies;
 0122            set => _underlyingHandler.UseCookies = value;
 123        }
 124
 125        [UnsupportedOSPlatform("browser")]
 126        public CookieContainer CookieContainer
 127        {
 0128            get => _underlyingHandler.CookieContainer;
 129            set
 0130            {
 0131                ArgumentNullException.ThrowIfNull(value);
 132
 0133                _underlyingHandler.CookieContainer = value;
 0134            }
 135        }
 136
 137        [UnsupportedOSPlatform("browser")]
 138        public DecompressionMethods AutomaticDecompression
 139        {
 0140            get => _underlyingHandler.AutomaticDecompression;
 0141            set => _underlyingHandler.AutomaticDecompression = value;
 142        }
 143
 144        [UnsupportedOSPlatform("browser")]
 145        public bool UseProxy
 146        {
 0147            get => _underlyingHandler.UseProxy;
 0148            set => _underlyingHandler.UseProxy = value;
 149        }
 150
 151        [UnsupportedOSPlatform("browser")]
 152        [UnsupportedOSPlatform("ios")]
 153        [UnsupportedOSPlatform("tvos")]
 154        public IWebProxy? Proxy
 155        {
 0156            get => _underlyingHandler.Proxy;
 0157            set => _underlyingHandler.Proxy = value;
 158        }
 159
 160        [UnsupportedOSPlatform("browser")]
 161        public ICredentials? DefaultProxyCredentials
 162        {
 0163            get => _underlyingHandler.DefaultProxyCredentials;
 0164            set => _underlyingHandler.DefaultProxyCredentials = value;
 165        }
 166
 167        [UnsupportedOSPlatform("browser")]
 168        public bool PreAuthenticate
 169        {
 0170            get => _underlyingHandler.PreAuthenticate;
 0171            set => _underlyingHandler.PreAuthenticate = value;
 172        }
 173
 174        [UnsupportedOSPlatform("browser")]
 175        public bool UseDefaultCredentials
 176        {
 177            // SocketsHttpHandler doesn't have a separate UseDefaultCredentials property.  There
 178            // is just a Credentials property.  So, we need to map the behavior.
 0179            get => _underlyingHandler.Credentials == CredentialCache.DefaultCredentials;
 180            set
 0181            {
 0182                if (value)
 0183                {
 0184                    _underlyingHandler.Credentials = CredentialCache.DefaultCredentials;
 0185                }
 186                else
 0187                {
 0188                    if (_underlyingHandler.Credentials == CredentialCache.DefaultCredentials)
 0189                    {
 190                        // Only clear out the Credentials property if it was a DefaultCredentials.
 0191                        _underlyingHandler.Credentials = null;
 0192                    }
 0193                }
 0194            }
 195        }
 196
 197        [UnsupportedOSPlatform("browser")]
 198        public ICredentials? Credentials
 199        {
 0200            get => _underlyingHandler.Credentials;
 0201            set => _underlyingHandler.Credentials = value;
 202        }
 203
 204        public bool AllowAutoRedirect
 205        {
 0206            get => _underlyingHandler.AllowAutoRedirect;
 0207            set => _underlyingHandler.AllowAutoRedirect = value;
 208        }
 209
 210        [UnsupportedOSPlatform("browser")]
 211        public int MaxAutomaticRedirections
 212        {
 0213            get => _underlyingHandler.MaxAutomaticRedirections;
 0214            set => _underlyingHandler.MaxAutomaticRedirections = value;
 215        }
 216
 217        [UnsupportedOSPlatform("browser")]
 218        public int MaxConnectionsPerServer
 219        {
 0220            get => _underlyingHandler.MaxConnectionsPerServer;
 0221            set => _underlyingHandler.MaxConnectionsPerServer = value;
 222        }
 223
 224        public long MaxRequestContentBufferSize
 225        {
 226            // This property is not supported. In the .NET Framework it was only used when the handler needed to
 227            // automatically buffer the request content. That only happened if neither 'Content-Length' nor
 228            // 'Transfer-Encoding: chunked' request headers were specified. So, the handler thus needed to buffer
 229            // in the request content to determine its length and then would choose 'Content-Length' semantics when
 230            // POST'ing. In .NET Core, the handler will resolve the ambiguity by always choosing
 231            // 'Transfer-Encoding: chunked'. The handler will never automatically buffer in the request content.
 232            get
 0233            {
 0234                return 0; // Returning zero is appropriate since in .NET Framework it means no limit.
 0235            }
 236
 237            set
 0238            {
 0239                ArgumentOutOfRangeException.ThrowIfNegative(value);
 240
 0241                if (value > HttpContent.MaxBufferSize)
 0242                {
 0243                    throw new ArgumentOutOfRangeException(nameof(value), value,
 0244                        SR.Format(CultureInfo.InvariantCulture, SR.net_http_content_buffersize_limit,
 0245                        HttpContent.MaxBufferSize));
 246                }
 247
 0248                ObjectDisposedException.ThrowIf(_disposed, this);
 249
 250                // No-op on property setter.
 0251            }
 252        }
 253
 254        [UnsupportedOSPlatform("browser")]
 255        public int MaxResponseHeadersLength
 256        {
 0257            get => _underlyingHandler.MaxResponseHeadersLength;
 0258            set => _underlyingHandler.MaxResponseHeadersLength = value;
 259        }
 260
 261        public ClientCertificateOption ClientCertificateOptions
 262        {
 0263            get => _underlyingHandler.ClientCertificateOptions;
 264            set
 0265            {
 0266                switch (value)
 267                {
 268                    case ClientCertificateOption.Manual:
 269#if !TARGET_BROWSER
 0270                        ThrowForModifiedManagedSslOptionsIfStarted();
 0271                        _underlyingHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCert
 272#endif
 0273                        break;
 274
 275                    case ClientCertificateOption.Automatic:
 276#if !TARGET_BROWSER
 0277                        ThrowForModifiedManagedSslOptionsIfStarted();
 0278                        _underlyingHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCert
 279#endif
 0280                        break;
 281
 282                    default:
 0283                        throw new ArgumentOutOfRangeException(nameof(value));
 284                }
 0285                _underlyingHandler.ClientCertificateOptions = value;
 0286            }
 287        }
 288
 289        [UnsupportedOSPlatform("browser")]
 290        public X509CertificateCollection ClientCertificates
 291        {
 292            get
 0293            {
 0294                if (ClientCertificateOptions != ClientCertificateOption.Manual)
 0295                {
 0296                    throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertifi
 297                }
 298
 0299                return _underlyingHandler.SslOptions.ClientCertificates ??
 0300                    (_underlyingHandler.SslOptions.ClientCertificates = new X509CertificateCollection());
 0301            }
 302        }
 303
 304        [UnsupportedOSPlatform("browser")]
 305        public Func<HttpRequestMessage, X509Certificate2?, X509Chain?, SslPolicyErrors, bool>? ServerCertificateCustomVa
 306        {
 307#if TARGET_BROWSER
 308            get => throw new PlatformNotSupportedException();
 309            set => throw new PlatformNotSupportedException();
 310#else
 0311            get => (_underlyingHandler.SslOptions.RemoteCertificateValidationCallback?.Target as ConnectHelper.Certifica
 312            set
 0313            {
 0314                ThrowForModifiedManagedSslOptionsIfStarted();
 0315                _underlyingHandler.SslOptions.RemoteCertificateValidationCallback = value != null ?
 0316                    new ConnectHelper.CertificateCallbackMapper(value).ForSocketsHttpHandler :
 0317                    null;
 0318            }
 319#endif
 320        }
 321
 322        [UnsupportedOSPlatform("browser")]
 323        public bool CheckCertificateRevocationList
 324        {
 0325            get => _underlyingHandler.SslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online;
 326            set
 0327            {
 0328                ThrowForModifiedManagedSslOptionsIfStarted();
 0329                _underlyingHandler.SslOptions.CertificateRevocationCheckMode = value ? X509RevocationMode.Online : X509R
 0330            }
 331        }
 332
 333        [UnsupportedOSPlatform("browser")]
 334        public SslProtocols SslProtocols
 335        {
 0336            get => _underlyingHandler.SslOptions.EnabledSslProtocols;
 337            set
 0338            {
 0339                ThrowForModifiedManagedSslOptionsIfStarted();
 0340                _underlyingHandler.SslOptions.EnabledSslProtocols = value;
 0341            }
 342        }
 343
 0344        public IDictionary<string, object?> Properties => _underlyingHandler.Properties;
 345
 346        [UnsupportedOSPlatform("android")]
 347        [UnsupportedOSPlatform("browser")]
 348        [UnsupportedOSPlatform("ios")]
 349        [UnsupportedOSPlatform("tvos")]
 350        protected internal override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationT
 0351        {
 352#if TARGET_BROWSER
 353            throw new PlatformNotSupportedException();
 354#else
 0355            ArgumentNullException.ThrowIfNull(request);
 0356            return Handler.Send(request, cancellationToken);
 357#endif
 0358        }
 359
 360        protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ca
 0361        {
 0362            ArgumentNullException.ThrowIfNull(request);
 0363            return Handler.SendAsync(request, cancellationToken);
 0364        }
 365
 366        // lazy-load the validator func so it can be trimmed by the ILLinker if it isn't used.
 367        [UnsupportedOSPlatform("browser")]
 368        public static Func<HttpRequestMessage, X509Certificate2?, X509Chain?, SslPolicyErrors, bool> DangerousAcceptAnyS
 0369            field ??
 0370            Interlocked.CompareExchange(ref field, delegate { return true; }, null) ??
 0371            field;
 372
 373        private void ThrowForModifiedManagedSslOptionsIfStarted()
 0374        {
 375            // Hack to trigger an InvalidOperationException if a property that's stored on
 376            // SslOptions is changed, since SslOptions itself does not do any such checks.
 0377            _underlyingHandler.SslOptions = _underlyingHandler.SslOptions;
 0378        }
 379    }
 380}

Methods/Properties

Handler()
.ctor()
Dispose(System.Boolean)
SupportsAutomaticDecompression()
SupportsProxy()
SupportsRedirectConfiguration()
MeterFactory()
MeterFactory(System.Diagnostics.Metrics.IMeterFactory)
UseCookies()
UseCookies(System.Boolean)
CookieContainer()
CookieContainer(System.Net.CookieContainer)
AutomaticDecompression()
AutomaticDecompression(System.Net.DecompressionMethods)
UseProxy()
UseProxy(System.Boolean)
Proxy()
Proxy(System.Net.IWebProxy)
DefaultProxyCredentials()
DefaultProxyCredentials(System.Net.ICredentials)
PreAuthenticate()
PreAuthenticate(System.Boolean)
UseDefaultCredentials()
UseDefaultCredentials(System.Boolean)
Credentials()
Credentials(System.Net.ICredentials)
AllowAutoRedirect()
AllowAutoRedirect(System.Boolean)
MaxAutomaticRedirections()
MaxAutomaticRedirections(System.Int32)
MaxConnectionsPerServer()
MaxConnectionsPerServer(System.Int32)
MaxRequestContentBufferSize()
MaxRequestContentBufferSize(System.Int64)
MaxResponseHeadersLength()
MaxResponseHeadersLength(System.Int32)
ClientCertificateOptions()
ClientCertificateOptions(System.Net.Http.ClientCertificateOption)
ClientCertificates()
ServerCertificateCustomValidationCallback()
ServerCertificateCustomValidationCallback(System.Func`5<System.Net.Http.HttpRequestMessage,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Chain,System.Net.Security.SslPolicyErrors,System.Boolean>)
CheckCertificateRevocationList()
CheckCertificateRevocationList(System.Boolean)
SslProtocols()
SslProtocols(System.Security.Authentication.SslProtocols)
Properties()
Send(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)
SendAsync(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)
DangerousAcceptAnyServerCertificateValidator()
ThrowForModifiedManagedSslOptionsIfStarted()