< Summary

Information
Class: System.Net.Http.SocketsHttpHandler
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\SocketsHttpHandler.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 316
Coverable lines: 316
Total lines: 692
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 118
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%
CheckDisposedOrStarted()0%220%
Dispose(...)0%660%
SetupHandlerChain()0%12120%
EnsureDecompressionHandlerFactory()0%220%
Send(...)0%880%
SendAsync(...)0%660%
CreateHandlerAndSendAsync()0%220%
ValidateAndNormalizeRequest(...)0%34340%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\SocketsHttpHandler.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.Collections.Generic;
 5using System.Diagnostics;
 6using System.Diagnostics.CodeAnalysis;
 7using System.Diagnostics.Metrics;
 8using System.IO;
 9using System.Net.Http.Metrics;
 10using System.Net.Security;
 11using System.Runtime.ExceptionServices;
 12using System.Runtime.Versioning;
 13using System.Text;
 14using System.Threading;
 15using System.Threading.Tasks;
 16
 17namespace System.Net.Http
 18{
 19    [UnsupportedOSPlatform("browser")]
 20    public sealed class SocketsHttpHandler : HttpMessageHandler
 21    {
 022        private readonly HttpConnectionSettings _settings = new HttpConnectionSettings();
 23        private HttpMessageHandlerStage? _handler;
 24        private Task<HttpMessageHandlerStage>? _handlerChainSetupTask;
 25        private Func<HttpConnectionSettings, HttpMessageHandlerStage, HttpMessageHandlerStage>? _decompressionHandlerFac
 26        private bool _disposed;
 27
 28        // Accessed via UnsafeAccessor from HttpWebRequest.
 029        internal HttpConnectionSettings Settings => _settings;
 30
 31        private void CheckDisposedOrStarted()
 032        {
 033            ObjectDisposedException.ThrowIf(_disposed, this);
 034            if (_handler != null)
 035            {
 036                throw new InvalidOperationException(SR.net_http_operation_started);
 37            }
 038        }
 39
 40        /// <summary>
 41        /// Gets a value that indicates whether the handler is supported on the current platform.
 42        /// </summary>
 43        [UnsupportedOSPlatformGuard("browser")]
 044        public static bool IsSupported => !OperatingSystem.IsBrowser() && !OperatingSystem.IsWasi();
 45
 46        public bool UseCookies
 47        {
 048            get => _settings._useCookies;
 49            set
 050            {
 051                CheckDisposedOrStarted();
 052                _settings._useCookies = value;
 053            }
 54        }
 55
 56        [AllowNull]
 57        public CookieContainer CookieContainer
 58        {
 059            get => _settings._cookieContainer ??= new CookieContainer();
 60            set
 061            {
 062                CheckDisposedOrStarted();
 063                _settings._cookieContainer = value;
 064            }
 65        }
 66
 67        public DecompressionMethods AutomaticDecompression
 68        {
 069            get => _settings._automaticDecompression;
 70            set
 071            {
 072                CheckDisposedOrStarted();
 073                EnsureDecompressionHandlerFactory();
 074                _settings._automaticDecompression = value;
 075            }
 76        }
 77
 78        public bool UseProxy
 79        {
 080            get => _settings._useProxy;
 81            set
 082            {
 083                CheckDisposedOrStarted();
 084                _settings._useProxy = value;
 085            }
 86        }
 87
 88        public IWebProxy? Proxy
 89        {
 090            get => _settings._proxy;
 91            set
 092            {
 093                CheckDisposedOrStarted();
 094                _settings._proxy = value;
 095            }
 96        }
 97
 98        public ICredentials? DefaultProxyCredentials
 99        {
 0100            get => _settings._defaultProxyCredentials;
 101            set
 0102            {
 0103                CheckDisposedOrStarted();
 0104                _settings._defaultProxyCredentials = value;
 0105            }
 106        }
 107
 108        public bool PreAuthenticate
 109        {
 0110            get => _settings._preAuthenticate;
 111            set
 0112            {
 0113                CheckDisposedOrStarted();
 0114                _settings._preAuthenticate = value;
 0115            }
 116        }
 117
 118        public ICredentials? Credentials
 119        {
 0120            get => _settings._credentials;
 121            set
 0122            {
 0123                CheckDisposedOrStarted();
 0124                _settings._credentials = value;
 0125            }
 126        }
 127
 128        public bool AllowAutoRedirect
 129        {
 0130            get => _settings._allowAutoRedirect;
 131            set
 0132            {
 0133                CheckDisposedOrStarted();
 0134                _settings._allowAutoRedirect = value;
 0135            }
 136        }
 137
 138        public int MaxAutomaticRedirections
 139        {
 0140            get => _settings._maxAutomaticRedirections;
 141            set
 0142            {
 0143                ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
 144
 0145                CheckDisposedOrStarted();
 0146                _settings._maxAutomaticRedirections = value;
 0147            }
 148        }
 149
 150        public int MaxConnectionsPerServer
 151        {
 0152            get => _settings._maxConnectionsPerServer;
 153            set
 0154            {
 0155                ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
 156
 0157                CheckDisposedOrStarted();
 0158                _settings._maxConnectionsPerServer = value;
 0159            }
 160        }
 161
 162        public int MaxResponseDrainSize
 163        {
 0164            get => _settings._maxResponseDrainSize;
 165            set
 0166            {
 0167                ArgumentOutOfRangeException.ThrowIfNegative(value);
 168
 0169                CheckDisposedOrStarted();
 0170                _settings._maxResponseDrainSize = value;
 0171            }
 172        }
 173
 174        public TimeSpan ResponseDrainTimeout
 175        {
 0176            get => _settings._maxResponseDrainTime;
 177            set
 0178            {
 0179                if ((value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) ||
 0180                    (value.TotalMilliseconds > int.MaxValue))
 0181                {
 0182                    throw new ArgumentOutOfRangeException(nameof(value));
 183                }
 184
 0185                CheckDisposedOrStarted();
 0186                _settings._maxResponseDrainTime = value;
 0187            }
 188        }
 189
 190        public int MaxResponseHeadersLength
 191        {
 0192            get => _settings._maxResponseHeadersLength;
 193            set
 0194            {
 0195                ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
 196
 0197                CheckDisposedOrStarted();
 0198                _settings._maxResponseHeadersLength = value;
 0199            }
 200        }
 201
 202        [AllowNull]
 203        public SslClientAuthenticationOptions SslOptions
 204        {
 0205            get => _settings._sslOptions ??= new SslClientAuthenticationOptions();
 206            set
 0207            {
 0208                CheckDisposedOrStarted();
 0209                _settings._sslOptions = value;
 0210            }
 211        }
 212
 213        public TimeSpan PooledConnectionLifetime
 214        {
 0215            get => _settings._pooledConnectionLifetime;
 216            set
 0217            {
 0218                if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
 0219                {
 0220                    throw new ArgumentOutOfRangeException(nameof(value));
 221                }
 222
 0223                CheckDisposedOrStarted();
 0224                _settings._pooledConnectionLifetime = value;
 0225            }
 226        }
 227
 228        public TimeSpan PooledConnectionIdleTimeout
 229        {
 0230            get => _settings._pooledConnectionIdleTimeout;
 231            set
 0232            {
 0233                if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
 0234                {
 0235                    throw new ArgumentOutOfRangeException(nameof(value));
 236                }
 237
 0238                CheckDisposedOrStarted();
 0239                _settings._pooledConnectionIdleTimeout = value;
 0240            }
 241        }
 242
 243        public TimeSpan ConnectTimeout
 244        {
 0245            get => _settings._connectTimeout;
 246            set
 0247            {
 0248                if ((value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) ||
 0249                    (value.TotalMilliseconds > int.MaxValue))
 0250                {
 0251                    throw new ArgumentOutOfRangeException(nameof(value));
 252                }
 253
 0254                CheckDisposedOrStarted();
 0255                _settings._connectTimeout = value;
 0256            }
 257        }
 258
 259        public TimeSpan Expect100ContinueTimeout
 260        {
 0261            get => _settings._expect100ContinueTimeout;
 262            set
 0263            {
 0264                if ((value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) ||
 0265                    (value.TotalMilliseconds > int.MaxValue))
 0266                {
 0267                    throw new ArgumentOutOfRangeException(nameof(value));
 268                }
 269
 0270                CheckDisposedOrStarted();
 0271                _settings._expect100ContinueTimeout = value;
 0272            }
 273        }
 274
 275        /// <summary>
 276        /// Defines the initial HTTP2 stream receive window size for all connections opened by the this <see cref="Socke
 277        /// </summary>
 278        /// <remarks>
 279        /// Larger the values may lead to faster download speed, but potentially higher memory footprint.
 280        /// The property must be set to a value between 65535 and the configured maximum window size, which is 16777216 
 281        /// </remarks>
 282        public int InitialHttp2StreamWindowSize
 283        {
 0284            get => _settings._initialHttp2StreamWindowSize;
 285            set
 0286            {
 0287                if (value < HttpHandlerDefaults.DefaultInitialHttp2StreamWindowSize || value > GlobalHttpSettings.Socket
 0288                {
 0289                    string message = SR.Format(
 0290                        SR.net_http_http2_invalidinitialstreamwindowsize,
 0291                        HttpHandlerDefaults.DefaultInitialHttp2StreamWindowSize,
 0292                        GlobalHttpSettings.SocketsHttpHandler.MaxHttp2StreamWindowSize);
 293
 0294                    throw new ArgumentOutOfRangeException(nameof(InitialHttp2StreamWindowSize), message);
 295                }
 0296                CheckDisposedOrStarted();
 0297                _settings._initialHttp2StreamWindowSize = value;
 0298            }
 299        }
 300
 301        /// <summary>
 302        /// Gets or sets the keep alive ping delay. The client will send a keep alive ping to the server if it
 303        /// doesn't receive any frames on a connection for this period of time. This property is used together with
 304        /// <see cref="SocketsHttpHandler.KeepAlivePingTimeout"/> to close broken connections.
 305        /// <para>
 306        /// Delay value must be greater than or equal to 1 second. Set to <see cref="Timeout.InfiniteTimeSpan"/> to
 307        /// disable the keep alive ping.
 308        /// Defaults to <see cref="Timeout.InfiniteTimeSpan"/>.
 309        /// </para>
 310        /// </summary>
 311        public TimeSpan KeepAlivePingDelay
 312        {
 0313            get => _settings._keepAlivePingDelay;
 314            set
 0315            {
 0316                if (value.Ticks < TimeSpan.TicksPerSecond && value != Timeout.InfiniteTimeSpan)
 0317                {
 0318                    throw new ArgumentOutOfRangeException(nameof(value), value, SR.Format(SR.net_http_value_must_be_grea
 319                }
 320
 0321                CheckDisposedOrStarted();
 0322                _settings._keepAlivePingDelay = value;
 0323            }
 324        }
 325
 326        /// <summary>
 327        /// Gets or sets the keep alive ping timeout. Keep alive pings are sent when a period of inactivity exceeds
 328        /// the configured <see cref="KeepAlivePingDelay"/> value. The client will close the connection if it
 329        /// doesn't receive any frames within the timeout.
 330        /// <para>
 331        /// Timeout must be greater than or equal to 1 second. Set to <see cref="Timeout.InfiniteTimeSpan"/> to
 332        /// disable the keep alive ping timeout.
 333        /// Defaults to 20 seconds.
 334        /// </para>
 335        /// </summary>
 336        public TimeSpan KeepAlivePingTimeout
 337        {
 0338            get => _settings._keepAlivePingTimeout;
 339            set
 0340            {
 0341                if (value.Ticks < TimeSpan.TicksPerSecond && value != Timeout.InfiniteTimeSpan)
 0342                {
 0343                    throw new ArgumentOutOfRangeException(nameof(value), value, SR.Format(SR.net_http_value_must_be_grea
 344                }
 345
 0346                CheckDisposedOrStarted();
 0347                _settings._keepAlivePingTimeout = value;
 0348            }
 349        }
 350
 351        /// <summary>
 352        /// Gets or sets the keep alive ping behaviour. Keep alive pings are sent when a period of inactivity exceeds
 353        /// the configured <see cref="KeepAlivePingDelay"/> value.
 354        /// </summary>
 355        public HttpKeepAlivePingPolicy KeepAlivePingPolicy
 356        {
 0357            get => _settings._keepAlivePingPolicy;
 358            set
 0359            {
 0360                CheckDisposedOrStarted();
 0361                _settings._keepAlivePingPolicy = value;
 0362            }
 363        }
 364
 365        /// <summary>
 366        /// Gets or sets a value that indicates whether additional HTTP/2 connections can be established to the same ser
 367        /// </summary>
 368        /// <remarks>
 369        /// Enabling multiple connections to the same server explicitly goes against <see href="https://www.rfc-editor.o
 370        /// </remarks>
 371        public bool EnableMultipleHttp2Connections
 372        {
 0373            get => _settings._enableMultipleHttp2Connections;
 374            set
 0375            {
 0376                CheckDisposedOrStarted();
 377
 0378                _settings._enableMultipleHttp2Connections = value;
 0379            }
 380        }
 381
 382        /// <summary>
 383        /// Gets or sets a value that indicates whether additional HTTP/3 connections can be established to the same ser
 384        /// </summary>
 385        /// <remarks>
 386        /// Enabling multiple connections to the same server explicitly goes against <see href="https://www.rfc-editor.o
 387        /// </remarks>
 388        public bool EnableMultipleHttp3Connections
 389        {
 0390            get => _settings._enableMultipleHttp3Connections;
 391            set
 0392            {
 0393                CheckDisposedOrStarted();
 394
 0395                _settings._enableMultipleHttp3Connections = value;
 0396            }
 397        }
 398
 399        internal const bool SupportsAutomaticDecompression = true;
 400        internal const bool SupportsProxy = true;
 401        internal const bool SupportsRedirectConfiguration = true;
 402
 403        /// <summary>
 404        /// When non-null, a custom callback used to open new connections.
 405        /// </summary>
 406        public Func<SocketsHttpConnectionContext, CancellationToken, ValueTask<Stream>>? ConnectCallback
 407        {
 0408            get => _settings._connectCallback;
 409            set
 0410            {
 0411                CheckDisposedOrStarted();
 0412                _settings._connectCallback = value;
 0413            }
 414        }
 415
 416        /// <summary>
 417        /// Gets or sets a custom callback that provides access to the plaintext HTTP protocol stream.
 418        /// </summary>
 419        public Func<SocketsHttpPlaintextStreamFilterContext, CancellationToken, ValueTask<Stream>>? PlaintextStreamFilte
 420        {
 0421            get => _settings._plaintextStreamFilter;
 422            set
 0423            {
 0424                CheckDisposedOrStarted();
 0425                _settings._plaintextStreamFilter = value;
 0426            }
 427        }
 428
 429        /// <summary>
 430        /// Gets a writable dictionary (that is, a map) of custom properties for the HttpClient requests. The dictionary
 431        /// </summary>
 432        public IDictionary<string, object?> Properties =>
 0433            _settings._properties ??= new Dictionary<string, object?>();
 434
 435        /// <summary>
 436        /// Gets or sets a callback that returns the <see cref="Encoding"/> to encode the value for the specified reques
 437        /// or <see langword="null"/> to use the default behavior.
 438        /// </summary>
 439        public HeaderEncodingSelector<HttpRequestMessage>? RequestHeaderEncodingSelector
 440        {
 0441            get => _settings._requestHeaderEncodingSelector;
 442            set
 0443            {
 0444                CheckDisposedOrStarted();
 0445                _settings._requestHeaderEncodingSelector = value;
 0446            }
 447        }
 448
 449        /// <summary>
 450        /// Gets or sets a callback that returns the <see cref="Encoding"/> to decode the value for the specified respon
 451        /// or <see langword="null"/> to use the default behavior.
 452        /// </summary>
 453        public HeaderEncodingSelector<HttpRequestMessage>? ResponseHeaderEncodingSelector
 454        {
 0455            get => _settings._responseHeaderEncodingSelector;
 456            set
 0457            {
 0458                CheckDisposedOrStarted();
 0459                _settings._responseHeaderEncodingSelector = value;
 0460            }
 461        }
 462
 463        /// <summary>
 464        /// Gets or sets the <see cref="DistributedContextPropagator"/> to use when propagating the distributed trace an
 465        /// Use <see langword="null"/> to disable propagation.
 466        /// Defaults to <see cref="DistributedContextPropagator.Current"/>.
 467        /// </summary>
 468        [CLSCompliant(false)]
 469        public DistributedContextPropagator? ActivityHeadersPropagator
 470        {
 0471            get => _settings._activityHeadersPropagator;
 472            set
 0473            {
 0474                CheckDisposedOrStarted();
 0475                _settings._activityHeadersPropagator = value;
 0476            }
 477        }
 478
 479        /// <summary>
 480        /// Gets or sets the <see cref="IMeterFactory"/> to create a custom <see cref="Meter"/> for the <see cref="Socke
 481        /// </summary>
 482        /// <remarks>
 483        /// When <see cref="MeterFactory"/> is set to a non-<see langword="null"/> value, all metrics emitted by the <se
 484        /// will be recorded using the <see cref="Meter"/> provided by the <see cref="IMeterFactory"/>.
 485        /// </remarks>
 486        [CLSCompliant(false)]
 487        public IMeterFactory? MeterFactory
 488        {
 0489            get => _settings._meterFactory;
 490            set
 0491            {
 0492                CheckDisposedOrStarted();
 0493                _settings._meterFactory = value;
 0494            }
 495        }
 496
 497        internal ClientCertificateOption ClientCertificateOptions
 498        {
 0499            get => _settings._clientCertificateOptions;
 500            set
 0501            {
 0502                CheckDisposedOrStarted();
 0503                _settings._clientCertificateOptions = value;
 0504            }
 505        }
 506
 507        protected override void Dispose(bool disposing)
 0508        {
 0509            if (disposing && !_disposed)
 0510            {
 0511                _disposed = true;
 0512                _handler?.Dispose();
 0513            }
 514
 0515            base.Dispose(disposing);
 0516        }
 517
 518        private HttpMessageHandlerStage SetupHandlerChain()
 0519        {
 520            // Clone the settings to get a relatively consistent view that won't change after this point.
 521            // (This isn't entirely complete, as some of the collections it contains aren't currently deeply cloned.)
 0522            HttpConnectionSettings settings = _settings.CloneAndNormalize();
 523
 0524            HttpConnectionPoolManager poolManager = new HttpConnectionPoolManager(settings);
 0525            HttpMessageHandlerStage handler = new HttpConnectionHandler(poolManager, doRequestAuth: settings._credential
 526
 527            // MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.req
 528            // metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry s
 0529            if (GlobalHttpSettings.MetricsHandler.IsGloballyEnabled)
 0530            {
 0531                handler = new MetricsHandler(handler, settings._meterFactory, settings._proxy, out Meter meter);
 0532                settings._metrics = new SocketsHttpHandlerMetrics(meter);
 0533            }
 534
 535            // DiagnosticsHandler is inserted before RedirectHandler so that trace propagation is done on redirects as w
 0536            if (GlobalHttpSettings.DiagnosticsHandler.EnableActivityPropagation && settings._activityHeadersPropagator i
 0537            {
 0538                handler = new DiagnosticsHandler(handler, propagator, settings._proxy, settings._allowAutoRedirect);
 0539            }
 540
 0541            if (settings._allowAutoRedirect)
 0542            {
 543                // Just as with WinHttpHandler, for security reasons, we do not support authentication on redirects
 544                // if the credential is anything other than a CredentialCache.
 545                // We allow credentials in a CredentialCache since they are specifically tied to URIs.
 0546                handler = new RedirectHandler(settings._maxAutomaticRedirections, handler, disableAuthOnRedirect: settin
 0547            }
 548
 0549            if ((settings._automaticDecompression & SupportedDecompressionMethods) != DecompressionMethods.None)
 0550            {
 0551                Debug.Assert(_decompressionHandlerFactory is not null);
 0552                handler = _decompressionHandlerFactory(settings, handler);
 0553            }
 554
 555            // Ensure a single handler is used for all requests.
 0556            if (Interlocked.CompareExchange(ref _handler, handler, null) != null)
 0557            {
 0558                handler.Dispose();
 0559            }
 560
 0561            return _handler;
 0562        }
 563
 564        // Allows for DecompressionHandler (and its compression dependencies) to be trimmed when
 565        // AutomaticDecompression is not being used.
 566        private void EnsureDecompressionHandlerFactory()
 0567        {
 0568            _decompressionHandlerFactory ??= (settings, handler) => new DecompressionHandler(settings._automaticDecompre
 0569        }
 570
 571        // Not stored as a constant on the DecompressionHandler to allow it to get trimmed.
 572        private const DecompressionMethods SupportedDecompressionMethods = DecompressionMethods.GZip | DecompressionMeth
 573
 574        protected internal override HttpResponseMessage Send(HttpRequestMessage request,
 575            CancellationToken cancellationToken)
 0576        {
 0577            ArgumentNullException.ThrowIfNull(request);
 578
 0579            if (request.Version.Major >= 2)
 0580            {
 0581                throw new NotSupportedException(SR.Format(SR.net_http_http2_sync_not_supported, GetType()));
 582            }
 583
 584            // Do not allow upgrades for synchronous requests, that might lead to asynchronous code-paths.
 0585            if (request.VersionPolicy == HttpVersionPolicy.RequestVersionOrHigher)
 0586            {
 0587                throw new NotSupportedException(SR.Format(SR.net_http_upgrade_not_enabled_sync, nameof(Send), request.Ve
 588            }
 589
 0590            ObjectDisposedException.ThrowIf(_disposed, this);
 591
 0592            cancellationToken.ThrowIfCancellationRequested();
 593
 0594            Exception? error = ValidateAndNormalizeRequest(request);
 0595            if (error != null)
 0596            {
 0597                throw error;
 598            }
 599
 0600            HttpMessageHandlerStage handler = _handler ?? SetupHandlerChain();
 601
 0602            return handler.Send(request, cancellationToken);
 0603        }
 604
 605        protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ca
 0606        {
 0607            ArgumentNullException.ThrowIfNull(request);
 608
 0609            ObjectDisposedException.ThrowIf(_disposed, this);
 610
 0611            if (cancellationToken.IsCancellationRequested)
 0612            {
 0613                return Task.FromCanceled<HttpResponseMessage>(cancellationToken);
 614            }
 615
 0616            Exception? error = ValidateAndNormalizeRequest(request);
 0617            if (error != null)
 0618            {
 0619                return Task.FromException<HttpResponseMessage>(error);
 620            }
 621
 0622            return _handler is { } handler
 0623                ? handler.SendAsync(request, cancellationToken)
 0624                : CreateHandlerAndSendAsync(request, cancellationToken);
 625
 626            // SetupHandlerChain may block for a few seconds in some environments.
 627            // E.g. during the first access of HttpClient.DefaultProxy - https://github.com/dotnet/runtime/issues/115301
 628            // The setup procedure is enqueued to thread pool to prevent the caller from blocking.
 629            async Task<HttpResponseMessage> CreateHandlerAndSendAsync(HttpRequestMessage request, CancellationToken canc
 0630            {
 0631                _handlerChainSetupTask ??= Task.Run(SetupHandlerChain);
 0632                HttpMessageHandlerStage handler = await _handlerChainSetupTask.ConfigureAwait(false);
 0633                return await handler.SendAsync(request, cancellationToken).ConfigureAwait(false);
 0634            }
 0635        }
 636
 637        private static Exception? ValidateAndNormalizeRequest(HttpRequestMessage request)
 0638        {
 0639            if (request.Version != HttpVersion.Version10 && request.Version != HttpVersion.Version11 && request.Version 
 0640            {
 0641                return ExceptionDispatchInfo.SetCurrentStackTrace(new NotSupportedException(SR.net_http_unsupported_vers
 642            }
 643
 644            // Add headers to define content transfer, if not present
 0645            if (request.HasHeaders && request.Headers.TransferEncodingChunked.GetValueOrDefault())
 0646            {
 0647                if (request.Content == null)
 0648                {
 0649                    return ExceptionDispatchInfo.SetCurrentStackTrace(new HttpRequestException(SR.net_http_client_execut
 0650                        ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationException(SR.net_http_chunked_not
 651                }
 652
 653                // Since the user explicitly set TransferEncodingChunked to true, we need to remove
 654                // the Content-Length header if present, as sending both is invalid.
 0655                request.Content.Headers.ContentLength = null;
 0656            }
 0657            else if (request.Content != null && request.Content.Headers.ContentLength == null)
 0658            {
 659                // We have content, but neither Transfer-Encoding nor Content-Length is set.
 0660                request.Headers.TransferEncodingChunked = true;
 0661            }
 662
 0663            if (request.Version.Minor == 0 && request.Version.Major == 1 && request.HasHeaders)
 0664            {
 665                // HTTP 1.0 does not support chunking
 0666                if (request.Headers.TransferEncodingChunked == true)
 0667                {
 0668                    return ExceptionDispatchInfo.SetCurrentStackTrace(new NotSupportedException(SR.net_http_unsupported_
 669                }
 670
 671                // HTTP 1.0 does not support Expect: 100-continue; just disable it.
 0672                if (request.Headers.ExpectContinue == true)
 0673                {
 0674                    request.Headers.ExpectContinue = false;
 0675                }
 0676            }
 677
 0678            Uri? requestUri = request.RequestUri;
 0679            if (requestUri is null || !requestUri.IsAbsoluteUri)
 0680            {
 0681                return ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationException(SR.net_http_client_inval
 682            }
 683
 0684            if (!HttpUtilities.IsSupportedScheme(requestUri.Scheme))
 0685            {
 0686                return ExceptionDispatchInfo.SetCurrentStackTrace(new NotSupportedException(SR.Format(SR.net_http_unsupp
 687            }
 688
 0689            return null;
 0690        }
 691    }
 692}

Methods/Properties

.ctor()
Settings()
CheckDisposedOrStarted()
IsSupported()
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)
Credentials()
Credentials(System.Net.ICredentials)
AllowAutoRedirect()
AllowAutoRedirect(System.Boolean)
MaxAutomaticRedirections()
MaxAutomaticRedirections(System.Int32)
MaxConnectionsPerServer()
MaxConnectionsPerServer(System.Int32)
MaxResponseDrainSize()
MaxResponseDrainSize(System.Int32)
ResponseDrainTimeout()
ResponseDrainTimeout(System.TimeSpan)
MaxResponseHeadersLength()
MaxResponseHeadersLength(System.Int32)
SslOptions()
SslOptions(System.Net.Security.SslClientAuthenticationOptions)
PooledConnectionLifetime()
PooledConnectionLifetime(System.TimeSpan)
PooledConnectionIdleTimeout()
PooledConnectionIdleTimeout(System.TimeSpan)
ConnectTimeout()
ConnectTimeout(System.TimeSpan)
Expect100ContinueTimeout()
Expect100ContinueTimeout(System.TimeSpan)
InitialHttp2StreamWindowSize()
InitialHttp2StreamWindowSize(System.Int32)
KeepAlivePingDelay()
KeepAlivePingDelay(System.TimeSpan)
KeepAlivePingTimeout()
KeepAlivePingTimeout(System.TimeSpan)
KeepAlivePingPolicy()
KeepAlivePingPolicy(System.Net.Http.HttpKeepAlivePingPolicy)
EnableMultipleHttp2Connections()
EnableMultipleHttp2Connections(System.Boolean)
EnableMultipleHttp3Connections()
EnableMultipleHttp3Connections(System.Boolean)
ConnectCallback()
ConnectCallback(System.Func`3<System.Net.Http.SocketsHttpConnectionContext,System.Threading.CancellationToken,System.Threading.Tasks.ValueTask`1<System.IO.Stream>>)
PlaintextStreamFilter()
PlaintextStreamFilter(System.Func`3<System.Net.Http.SocketsHttpPlaintextStreamFilterContext,System.Threading.CancellationToken,System.Threading.Tasks.ValueTask`1<System.IO.Stream>>)
Properties()
RequestHeaderEncodingSelector()
RequestHeaderEncodingSelector(System.Net.Http.HeaderEncodingSelector`1<System.Net.Http.HttpRequestMessage>)
ResponseHeaderEncodingSelector()
ResponseHeaderEncodingSelector(System.Net.Http.HeaderEncodingSelector`1<System.Net.Http.HttpRequestMessage>)
ActivityHeadersPropagator()
ActivityHeadersPropagator(System.Diagnostics.DistributedContextPropagator)
MeterFactory()
MeterFactory(System.Diagnostics.Metrics.IMeterFactory)
ClientCertificateOptions()
ClientCertificateOptions(System.Net.Http.ClientCertificateOption)
Dispose(System.Boolean)
SetupHandlerChain()
EnsureDecompressionHandlerFactory()
Send(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)
SendAsync(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)
CreateHandlerAndSendAsync()
ValidateAndNormalizeRequest(System.Net.Http.HttpRequestMessage)