< Summary

Information
Class: System.Net.Http.HttpClient
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\HttpClient.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 418
Coverable lines: 418
Total lines: 829
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 102
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
.ctor(...)100%110%
.ctor()100%110%
.ctor(...)100%110%
GetStringAsync(...)100%110%
GetStringAsync(...)100%110%
GetStringAsync(...)100%110%
GetStringAsync(...)100%110%
GetStringAsyncCore()0%660%
GetByteArrayAsync(...)100%110%
GetByteArrayAsync(...)100%110%
GetByteArrayAsync(...)100%110%
GetByteArrayAsync(...)100%110%
GetByteArrayAsyncCore()0%660%
GetStreamAsync(...)100%110%
GetStreamAsync(...)100%110%
GetStreamAsync(...)100%110%
GetStreamAsync(...)100%110%
GetStreamAsyncCore()0%220%
GetAsync(...)100%110%
GetAsync(...)100%110%
GetAsync(...)100%110%
GetAsync(...)100%110%
GetAsync(...)100%110%
GetAsync(...)100%110%
GetAsync(...)100%110%
GetAsync(...)100%110%
PostAsync(...)100%110%
PostAsync(...)100%110%
PostAsync(...)100%110%
PostAsync(...)100%110%
PutAsync(...)100%110%
PutAsync(...)100%110%
PutAsync(...)100%110%
PutAsync(...)100%110%
PatchAsync(...)100%110%
PatchAsync(...)100%110%
PatchAsync(...)100%110%
PatchAsync(...)100%110%
DeleteAsync(...)100%110%
DeleteAsync(...)100%110%
DeleteAsync(...)100%110%
DeleteAsync(...)100%110%
Send(...)100%110%
Send(...)100%110%
Send(...)100%110%
Send(...)0%440%
SendAsync(...)100%110%
SendAsync(...)100%110%
SendAsync(...)100%110%
SendAsync(...)100%110%
Core()0%440%
CheckRequestBeforeSend(...)100%110%
ThrowForNullResponse(...)0%220%
ShouldBufferResponse(...)0%220%
HandleFailure(...)0%24240%
StartSend(...)0%220%
FinishSend(...)0%660%
CancelPendingRequests()100%110%
Dispose(...)0%440%
SetOperationStarted()0%220%
CheckDisposedOrStarted()0%220%
CheckRequestMessage(...)0%220%
PrepareRequestMessage(...)0%14140%
PrepareCancellationTokenSource(...)0%660%
CreateUri(...)0%220%
CreateRequestMessage(...)100%110%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\HttpClient.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.Diagnostics.CodeAnalysis;
 6using System.IO;
 7using System.Net.Http.Headers;
 8using System.Runtime.Versioning;
 9using System.Threading;
 10using System.Threading.Tasks;
 11
 12namespace System.Net.Http
 13{
 14    public partial class HttpClient : HttpMessageInvoker
 15    {
 16        #region Fields
 17
 18        private static IWebProxy? s_defaultProxy;
 019        private static readonly TimeSpan s_defaultTimeout = TimeSpan.FromSeconds(100);
 020        private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
 021        private static readonly TimeSpan s_infiniteTimeout = Threading.Timeout.InfiniteTimeSpan;
 22        private const HttpCompletionOption DefaultCompletionOption = HttpCompletionOption.ResponseContentRead;
 23
 24        private volatile bool _operationStarted;
 25        private volatile bool _disposed;
 26
 27        private CancellationTokenSource _pendingRequestsCts;
 28        private HttpRequestHeaders? _defaultRequestHeaders;
 029        private Version _defaultRequestVersion = HttpRequestMessage.DefaultRequestVersion;
 030        private HttpVersionPolicy _defaultVersionPolicy = HttpRequestMessage.DefaultVersionPolicy;
 31
 32        private Uri? _baseAddress;
 33        private TimeSpan _timeout;
 34        private int _maxResponseContentBufferSize;
 35
 36        #endregion Fields
 37
 38        #region Properties
 39        public static IWebProxy DefaultProxy
 40        {
 041            get => LazyInitializer.EnsureInitialized(ref s_defaultProxy, () => SystemProxyInfo.Proxy);
 42            set
 043            {
 044                ArgumentNullException.ThrowIfNull(value);
 045                s_defaultProxy = value;
 046            }
 47        }
 48
 49        public HttpRequestHeaders DefaultRequestHeaders =>
 050            _defaultRequestHeaders ??= new HttpRequestHeaders();
 51
 52        public Version DefaultRequestVersion
 53        {
 054            get => _defaultRequestVersion;
 55            set
 056            {
 057                CheckDisposedOrStarted();
 058                ArgumentNullException.ThrowIfNull(value);
 059                _defaultRequestVersion = value;
 060            }
 61        }
 62
 63        /// <summary>
 64        /// Gets or sets the default value of <see cref="HttpRequestMessage.VersionPolicy" /> for implicitly created req
 65        /// e.g.: <see cref="GetAsync(string?)" />, <see cref="PostAsync(string?, HttpContent)" />.
 66        /// </summary>
 67        /// <remarks>
 68        /// Note that this property has no effect on any of the <see cref="Send(HttpRequestMessage)" /> and <see cref="S
 69        /// since they accept fully initialized <see cref="HttpRequestMessage" />.
 70        /// </remarks>
 71        public HttpVersionPolicy DefaultVersionPolicy
 72        {
 073            get => _defaultVersionPolicy;
 74            set
 075            {
 076                CheckDisposedOrStarted();
 077                _defaultVersionPolicy = value;
 078            }
 79        }
 80
 81        public Uri? BaseAddress
 82        {
 083            get => _baseAddress;
 84            set
 085            {
 86                // It's OK to not have a base address specified, but if one is, it needs to be absolute.
 087                if (value is not null && !value.IsAbsoluteUri)
 088                {
 089                    throw new ArgumentException(SR.net_http_client_absolute_baseaddress_required, nameof(value));
 90                }
 91
 092                CheckDisposedOrStarted();
 93
 094                if (NetEventSource.Log.IsEnabled()) NetEventSource.UriBaseAddress(this, value);
 95
 096                _baseAddress = value;
 097            }
 98        }
 99
 100        public TimeSpan Timeout
 101        {
 0102            get => _timeout;
 103            set
 0104            {
 0105                if (value != s_infiniteTimeout)
 0106                {
 0107                    ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(value, TimeSpan.Zero);
 0108                    ArgumentOutOfRangeException.ThrowIfGreaterThan(value, s_maxTimeout);
 0109                }
 0110                CheckDisposedOrStarted();
 0111                _timeout = value;
 0112            }
 113        }
 114
 115        public long MaxResponseContentBufferSize
 116        {
 0117            get => _maxResponseContentBufferSize;
 118            set
 0119            {
 0120                ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
 0121                if (value > HttpContent.MaxBufferSize)
 0122                {
 0123                    throw new ArgumentOutOfRangeException(nameof(value), value,
 0124                        SR.Format(System.Globalization.CultureInfo.InvariantCulture,
 0125                        SR.net_http_content_buffersize_limit, HttpContent.MaxBufferSize));
 126                }
 0127                CheckDisposedOrStarted();
 128
 0129                Debug.Assert(HttpContent.MaxBufferSize <= int.MaxValue);
 0130                _maxResponseContentBufferSize = (int)value;
 0131            }
 132        }
 133
 134        #endregion Properties
 135
 136        #region Constructors
 137
 0138        public HttpClient() : this(new HttpClientHandler())
 0139        {
 0140        }
 141
 0142        public HttpClient(HttpMessageHandler handler) : this(handler, true)
 0143        {
 0144        }
 145
 0146        public HttpClient(HttpMessageHandler handler, bool disposeHandler) : base(handler, disposeHandler)
 0147        {
 0148            _timeout = s_defaultTimeout;
 0149            _maxResponseContentBufferSize = HttpContent.MaxBufferSize;
 0150            _pendingRequestsCts = new CancellationTokenSource();
 0151        }
 152
 153        #endregion Constructors
 154
 155        #region Public Send
 156
 157        #region Simple Get Overloads
 158
 159        public Task<string> GetStringAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri) =>
 0160            GetStringAsync(CreateUri(requestUri));
 161
 162        public Task<string> GetStringAsync(Uri? requestUri) =>
 0163            GetStringAsync(requestUri, CancellationToken.None);
 164
 165        public Task<string> GetStringAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, CancellationTok
 0166            GetStringAsync(CreateUri(requestUri), cancellationToken);
 167
 168        public Task<string> GetStringAsync(Uri? requestUri, CancellationToken cancellationToken)
 0169        {
 0170            HttpRequestMessage request = CreateRequestMessage(HttpMethod.Get, requestUri);
 171
 172            // Called outside of async state machine to propagate certain exception even without awaiting the returned t
 0173            CheckRequestBeforeSend(request);
 174
 0175            return GetStringAsyncCore(request, cancellationToken);
 0176        }
 177
 178        private async Task<string> GetStringAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
 0179        {
 0180            bool telemetryStarted = StartSend(request);
 0181            bool responseContentTelemetryStarted = false;
 182
 0183            (CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts) = PrepareCancella
 0184            HttpResponseMessage? response = null;
 185            try
 0186            {
 187                // Wait for the response message and make sure it completed successfully.
 0188                response = await base.SendAsync(request, cts.Token).ConfigureAwait(false);
 0189                ThrowForNullResponse(response);
 0190                response.EnsureSuccessStatusCode();
 191
 192                // Get the response content.
 0193                HttpContent c = response.Content;
 0194                if (HttpTelemetry.Log.IsEnabled() && telemetryStarted)
 0195                {
 0196                    HttpTelemetry.Log.ResponseContentStart();
 0197                    responseContentTelemetryStarted = true;
 0198                }
 199
 200                // Since the underlying byte[] will never be exposed, we use an ArrayPool-backed
 201                // stream to which we copy all of the data from the response.
 0202                using var buffer = new HttpContent.LimitArrayPoolWriteStream(
 0203                    _maxResponseContentBufferSize,
 0204                    c.Headers.ContentLength.GetValueOrDefault(),
 0205                    getFinalSizeFromPool: true);
 206
 0207                using Stream responseStream = c.TryReadAsStream() ?? await c.ReadAsStreamAsync(cts.Token).ConfigureAwait
 208                try
 0209                {
 0210                    await responseStream.CopyToAsync(buffer, cts.Token).ConfigureAwait(false);
 0211                }
 0212                catch (Exception e) when (HttpContent.StreamCopyExceptionNeedsWrapping(e))
 0213                {
 0214                    throw HttpContent.WrapStreamCopyException(e);
 215                }
 216
 217                // Decode and return the data from the buffer.
 0218                return HttpContent.ReadBufferAsString(buffer, c.Headers);
 219            }
 0220            catch (Exception e)
 0221            {
 0222                HandleFailure(e, telemetryStarted, response, cts, cancellationToken, pendingRequestsCts);
 0223                throw;
 224            }
 225            finally
 0226            {
 0227                FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted);
 0228            }
 0229        }
 230
 231        public Task<byte[]> GetByteArrayAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri) =>
 0232            GetByteArrayAsync(CreateUri(requestUri));
 233
 234        public Task<byte[]> GetByteArrayAsync(Uri? requestUri) =>
 0235            GetByteArrayAsync(requestUri, CancellationToken.None);
 236
 237        public Task<byte[]> GetByteArrayAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Cancellation
 0238            GetByteArrayAsync(CreateUri(requestUri), cancellationToken);
 239
 240        public Task<byte[]> GetByteArrayAsync(Uri? requestUri, CancellationToken cancellationToken)
 0241        {
 0242            HttpRequestMessage request = CreateRequestMessage(HttpMethod.Get, requestUri);
 243
 244            // Called outside of async state machine to propagate certain exception even without awaiting the returned t
 0245            CheckRequestBeforeSend(request);
 246
 0247            return GetByteArrayAsyncCore(request, cancellationToken);
 0248        }
 249
 250        private async Task<byte[]> GetByteArrayAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken
 0251        {
 0252            bool telemetryStarted = StartSend(request);
 0253            bool responseContentTelemetryStarted = false;
 254
 0255            (CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts) = PrepareCancella
 0256            HttpResponseMessage? response = null;
 257            try
 0258            {
 259                // Wait for the response message and make sure it completed successfully.
 0260                response = await base.SendAsync(request, cts.Token).ConfigureAwait(false);
 0261                ThrowForNullResponse(response);
 0262                response.EnsureSuccessStatusCode();
 263
 264                // Get the response content.
 0265                HttpContent c = response.Content;
 0266                if (HttpTelemetry.Log.IsEnabled() && telemetryStarted)
 0267                {
 0268                    HttpTelemetry.Log.ResponseContentStart();
 0269                    responseContentTelemetryStarted = true;
 0270                }
 271
 272                // If we got a content length, then we assume that it's correct. If that's the case,
 273                // we can opportunistically allocate the exact-sized buffer while buffering the content.
 274                // If we didn't get a content length, then we assume we're going to have to grow
 275                // the buffer potentially several times and that it's unlikely the underlying buffer
 276                // at the end will be the exact size needed, in which case it's more beneficial to use
 277                // ArrayPool buffers and copy out to a new array at the end.
 0278                using var buffer = new HttpContent.LimitArrayPoolWriteStream(
 0279                    _maxResponseContentBufferSize,
 0280                    c.Headers.ContentLength.GetValueOrDefault(),
 0281                    getFinalSizeFromPool: false);
 282
 0283                using Stream responseStream = c.TryReadAsStream() ?? await c.ReadAsStreamAsync(cts.Token).ConfigureAwait
 284                try
 0285                {
 0286                    await responseStream.CopyToAsync(buffer, cts.Token).ConfigureAwait(false);
 0287                }
 0288                catch (Exception e) when (HttpContent.StreamCopyExceptionNeedsWrapping(e))
 0289                {
 0290                    throw HttpContent.WrapStreamCopyException(e);
 291                }
 292
 0293                return buffer.ToArray();
 294            }
 0295            catch (Exception e)
 0296            {
 0297                HandleFailure(e, telemetryStarted, response, cts, cancellationToken, pendingRequestsCts);
 0298                throw;
 299            }
 300            finally
 0301            {
 0302                FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted);
 0303            }
 0304        }
 305
 306        public Task<Stream> GetStreamAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri) =>
 0307            GetStreamAsync(CreateUri(requestUri));
 308
 309        public Task<Stream> GetStreamAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, CancellationTok
 0310            GetStreamAsync(CreateUri(requestUri), cancellationToken);
 311
 312        public Task<Stream> GetStreamAsync(Uri? requestUri) =>
 0313            GetStreamAsync(requestUri, CancellationToken.None);
 314
 315        public Task<Stream> GetStreamAsync(Uri? requestUri, CancellationToken cancellationToken)
 0316        {
 0317            HttpRequestMessage request = CreateRequestMessage(HttpMethod.Get, requestUri);
 318
 319            // Called outside of async state machine to propagate certain exception even without awaiting the returned t
 0320            CheckRequestBeforeSend(request);
 321
 0322            return GetStreamAsyncCore(request, cancellationToken);
 0323        }
 324
 325        private async Task<Stream> GetStreamAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
 0326        {
 0327            bool telemetryStarted = StartSend(request);
 328
 0329            (CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts) = PrepareCancella
 0330            HttpResponseMessage? response = null;
 331            try
 0332            {
 333                // Wait for the response message and make sure it completed successfully.
 0334                response = await base.SendAsync(request, cts.Token).ConfigureAwait(false);
 0335                ThrowForNullResponse(response);
 0336                response.EnsureSuccessStatusCode();
 337
 0338                HttpContent c = response.Content;
 0339                return c.TryReadAsStream() ?? await c.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
 340            }
 0341            catch (Exception e)
 0342            {
 0343                HandleFailure(e, telemetryStarted, response, cts, cancellationToken, pendingRequestsCts);
 0344                throw;
 345            }
 346            finally
 0347            {
 0348                FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted: false);
 0349            }
 0350        }
 351
 352        #endregion Simple Get Overloads
 353
 354        #region REST Send Overloads
 355
 356        public Task<HttpResponseMessage> GetAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri) =>
 0357            GetAsync(CreateUri(requestUri));
 358
 359        public Task<HttpResponseMessage> GetAsync(Uri? requestUri) =>
 0360            GetAsync(requestUri, DefaultCompletionOption);
 361
 362        public Task<HttpResponseMessage> GetAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpComp
 0363            GetAsync(CreateUri(requestUri), completionOption);
 364
 365        public Task<HttpResponseMessage> GetAsync(Uri? requestUri, HttpCompletionOption completionOption) =>
 0366            GetAsync(requestUri, completionOption, CancellationToken.None);
 367
 368        public Task<HttpResponseMessage> GetAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Cancella
 0369            GetAsync(CreateUri(requestUri), cancellationToken);
 370
 371        public Task<HttpResponseMessage> GetAsync(Uri? requestUri, CancellationToken cancellationToken) =>
 0372            GetAsync(requestUri, DefaultCompletionOption, cancellationToken);
 373
 374        public Task<HttpResponseMessage> GetAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpComp
 0375            GetAsync(CreateUri(requestUri), completionOption, cancellationToken);
 376
 377        public Task<HttpResponseMessage> GetAsync(Uri? requestUri, HttpCompletionOption completionOption, CancellationTo
 0378            SendAsync(CreateRequestMessage(HttpMethod.Get, requestUri), completionOption, cancellationToken);
 379
 380        public Task<HttpResponseMessage> PostAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpCon
 0381            PostAsync(CreateUri(requestUri), content);
 382
 383        public Task<HttpResponseMessage> PostAsync(Uri? requestUri, HttpContent? content) =>
 0384            PostAsync(requestUri, content, CancellationToken.None);
 385
 386        public Task<HttpResponseMessage> PostAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpCon
 0387            PostAsync(CreateUri(requestUri), content, cancellationToken);
 388
 389        public Task<HttpResponseMessage> PostAsync(Uri? requestUri, HttpContent? content, CancellationToken cancellation
 0390        {
 0391            HttpRequestMessage request = CreateRequestMessage(HttpMethod.Post, requestUri);
 0392            request.Content = content;
 0393            return SendAsync(request, cancellationToken);
 0394        }
 395
 396        public Task<HttpResponseMessage> PutAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpCont
 0397            PutAsync(CreateUri(requestUri), content);
 398
 399        public Task<HttpResponseMessage> PutAsync(Uri? requestUri, HttpContent? content) =>
 0400            PutAsync(requestUri, content, CancellationToken.None);
 401
 402        public Task<HttpResponseMessage> PutAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpCont
 0403            PutAsync(CreateUri(requestUri), content, cancellationToken);
 404
 405        public Task<HttpResponseMessage> PutAsync(Uri? requestUri, HttpContent? content, CancellationToken cancellationT
 0406        {
 0407            HttpRequestMessage request = CreateRequestMessage(HttpMethod.Put, requestUri);
 0408            request.Content = content;
 0409            return SendAsync(request, cancellationToken);
 0410        }
 411
 412        public Task<HttpResponseMessage> PatchAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpCo
 0413            PatchAsync(CreateUri(requestUri), content);
 414
 415        public Task<HttpResponseMessage> PatchAsync(Uri? requestUri, HttpContent? content) =>
 0416            PatchAsync(requestUri, content, CancellationToken.None);
 417
 418        public Task<HttpResponseMessage> PatchAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, HttpCo
 0419            PatchAsync(CreateUri(requestUri), content, cancellationToken);
 420
 421        public Task<HttpResponseMessage> PatchAsync(Uri? requestUri, HttpContent? content, CancellationToken cancellatio
 0422        {
 0423            HttpRequestMessage request = CreateRequestMessage(HttpMethod.Patch, requestUri);
 0424            request.Content = content;
 0425            return SendAsync(request, cancellationToken);
 0426        }
 427
 428        public Task<HttpResponseMessage> DeleteAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri) =>
 0429            DeleteAsync(CreateUri(requestUri));
 430
 431        public Task<HttpResponseMessage> DeleteAsync(Uri? requestUri) =>
 0432            DeleteAsync(requestUri, CancellationToken.None);
 433
 434        public Task<HttpResponseMessage> DeleteAsync([StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri, Cance
 0435            DeleteAsync(CreateUri(requestUri), cancellationToken);
 436
 437        public Task<HttpResponseMessage> DeleteAsync(Uri? requestUri, CancellationToken cancellationToken) =>
 0438            SendAsync(CreateRequestMessage(HttpMethod.Delete, requestUri), cancellationToken);
 439
 440        #endregion REST Send Overloads
 441
 442        #region Advanced Send Overloads
 443
 444        [UnsupportedOSPlatform("android")]
 445        [UnsupportedOSPlatform("browser")]
 446        [UnsupportedOSPlatform("ios")]
 447        [UnsupportedOSPlatform("tvos")]
 448        public HttpResponseMessage Send(HttpRequestMessage request) =>
 0449            Send(request, DefaultCompletionOption, cancellationToken: default);
 450
 451        [UnsupportedOSPlatform("android")]
 452        [UnsupportedOSPlatform("browser")]
 453        [UnsupportedOSPlatform("ios")]
 454        [UnsupportedOSPlatform("tvos")]
 455        public HttpResponseMessage Send(HttpRequestMessage request, HttpCompletionOption completionOption) =>
 0456            Send(request, completionOption, cancellationToken: default);
 457
 458        [UnsupportedOSPlatform("android")]
 459        [UnsupportedOSPlatform("browser")]
 460        [UnsupportedOSPlatform("ios")]
 461        [UnsupportedOSPlatform("tvos")]
 462        public override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) =>
 0463            Send(request, DefaultCompletionOption, cancellationToken);
 464
 465        [UnsupportedOSPlatform("android")]
 466        [UnsupportedOSPlatform("browser")]
 467        [UnsupportedOSPlatform("ios")]
 468        [UnsupportedOSPlatform("tvos")]
 469        public HttpResponseMessage Send(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationT
 0470        {
 0471            CheckRequestBeforeSend(request);
 0472            (CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts) = PrepareCancella
 473
 0474            bool telemetryStarted = StartSend(request);
 0475            bool responseContentTelemetryStarted = false;
 0476            HttpResponseMessage? response = null;
 477            try
 0478            {
 479                // Wait for the send request to complete, getting back the response.
 0480                response = base.Send(request, cts.Token);
 0481                ThrowForNullResponse(response);
 482
 483                // Buffer the response content if we've been asked to.
 0484                if (ShouldBufferResponse(completionOption, request))
 0485                {
 0486                    if (HttpTelemetry.Log.IsEnabled() && telemetryStarted)
 0487                    {
 0488                        HttpTelemetry.Log.ResponseContentStart();
 0489                        responseContentTelemetryStarted = true;
 0490                    }
 491
 0492                    response.Content.LoadIntoBuffer(_maxResponseContentBufferSize, cts.Token);
 0493                }
 494
 0495                return response;
 496            }
 0497            catch (Exception e)
 0498            {
 0499                HandleFailure(e, telemetryStarted, response, cts, cancellationToken, pendingRequestsCts);
 0500                throw;
 501            }
 502            finally
 0503            {
 0504                FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted);
 0505            }
 0506        }
 507
 508        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request) =>
 0509            SendAsync(request, DefaultCompletionOption, CancellationToken.None);
 510
 511        public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationTo
 0512            SendAsync(request, DefaultCompletionOption, cancellationToken);
 513
 514        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption) =>
 0515            SendAsync(request, completionOption, CancellationToken.None);
 516
 517        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, Ca
 0518        {
 519            // Called outside of async state machine to propagate certain exception even without awaiting the returned t
 0520            CheckRequestBeforeSend(request);
 0521            (CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts) = PrepareCancella
 522
 0523            return Core(request, completionOption, cts, disposeCts, pendingRequestsCts, cancellationToken);
 524
 525            async Task<HttpResponseMessage> Core(
 526                HttpRequestMessage request, HttpCompletionOption completionOption,
 527                CancellationTokenSource cts, bool disposeCts, CancellationTokenSource pendingRequestsCts, CancellationTo
 0528            {
 0529                bool telemetryStarted = StartSend(request);
 0530                bool responseContentTelemetryStarted = false;
 0531                HttpResponseMessage? response = null;
 532                try
 0533                {
 534                    // Wait for the send request to complete, getting back the response.
 0535                    response = await base.SendAsync(request, cts.Token).ConfigureAwait(false);
 0536                    ThrowForNullResponse(response);
 537
 538                    // Buffer the response content if we've been asked to.
 0539                    if (ShouldBufferResponse(completionOption, request))
 0540                    {
 0541                        if (HttpTelemetry.Log.IsEnabled() && telemetryStarted)
 0542                        {
 0543                            HttpTelemetry.Log.ResponseContentStart();
 0544                            responseContentTelemetryStarted = true;
 0545                        }
 546
 0547                        await response.Content.LoadIntoBufferAsync(_maxResponseContentBufferSize, cts.Token).ConfigureAw
 0548                    }
 549
 0550                    return response;
 551                }
 0552                catch (Exception e)
 0553                {
 0554                    HandleFailure(e, telemetryStarted, response, cts, originalCancellationToken, pendingRequestsCts);
 0555                    throw;
 556                }
 557                finally
 0558                {
 0559                    FinishSend(response, cts, disposeCts, telemetryStarted, responseContentTelemetryStarted);
 0560                }
 0561            }
 0562        }
 563
 564        private void CheckRequestBeforeSend(HttpRequestMessage request)
 0565        {
 0566            ArgumentNullException.ThrowIfNull(request);
 567
 0568            ObjectDisposedException.ThrowIf(_disposed, this);
 0569            CheckRequestMessage(request);
 570
 0571            SetOperationStarted();
 572
 573            // PrepareRequestMessage will resolve the request address against the base address.
 0574            PrepareRequestMessage(request);
 0575        }
 576
 577        private static void ThrowForNullResponse([NotNull] HttpResponseMessage? response)
 0578        {
 0579            if (response is null)
 0580            {
 0581                throw new InvalidOperationException(SR.net_http_handler_noresponse);
 582            }
 0583        }
 584
 585        private static bool ShouldBufferResponse(HttpCompletionOption completionOption, HttpRequestMessage request) =>
 0586            completionOption == HttpCompletionOption.ResponseContentRead &&
 0587            !string.Equals(request.Method.Method, "HEAD", StringComparison.OrdinalIgnoreCase);
 588
 589        private void HandleFailure(Exception e, bool telemetryStarted, HttpResponseMessage? response, CancellationTokenS
 0590        {
 0591            response?.Dispose();
 592
 0593            Exception? toThrow = null;
 594
 0595            if (e is OperationCanceledException oce)
 0596            {
 0597                if (cancellationToken.IsCancellationRequested)
 0598                {
 0599                    if (oce.CancellationToken != cancellationToken)
 0600                    {
 601                        // We got a cancellation exception, and the caller requested cancellation, but the exception doe
 602                        // Massage things so that the cancellation exception we propagate appropriately contains the cal
 603                        // multiple things caused cancellation, in which case we can attribute it to the caller's token,
 604                        // exception contains the linked token source, in which case that token isn't meaningful to the 
 0605                        e = toThrow = new TaskCanceledException(oce.Message, oce, cancellationToken);
 0606                    }
 0607                }
 0608                else if (cts.IsCancellationRequested && !pendingRequestsCts.IsCancellationRequested)
 0609                {
 610                    // If the linked cancellation token source was canceled, but cancellation wasn't requested, either b
 611                    // the only other cause could be a timeout.  Treat it as such.
 612
 613                    // cancellationToken could have been triggered right after we checked it, but before we checked the 
 614                    // We must check it again to avoid reporting a timeout when one did not occur.
 0615                    if (!cancellationToken.IsCancellationRequested)
 0616                    {
 0617                        Debug.Assert(_timeout.TotalSeconds > 0);
 0618                        e = toThrow = new TaskCanceledException(SR.Format(SR.net_http_request_timedout, _timeout.TotalSe
 0619                    }
 0620                }
 0621            }
 0622            else if (e is HttpRequestException && cts.IsCancellationRequested) // if cancellationToken is canceled, cts 
 0623            {
 624                // If the cancellation token source was canceled, race conditions abound, and we consider the failure to
 625                // caused by the cancellation (e.g. WebException when reading from canceled response stream).
 0626                e = toThrow = CancellationHelper.CreateOperationCanceledException(e, cancellationToken.IsCancellationReq
 0627            }
 628
 0629            LogRequestFailed(e, telemetryStarted);
 630
 0631            if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(this, e);
 632
 0633            if (toThrow != null)
 0634            {
 0635                throw toThrow;
 636            }
 0637        }
 638
 639        private static bool StartSend(HttpRequestMessage request)
 0640        {
 0641            if (HttpTelemetry.Log.IsEnabled())
 0642            {
 0643                HttpTelemetry.Log.RequestStart(request);
 0644                return true;
 645            }
 646
 0647            return false;
 0648        }
 649
 650        private static void FinishSend(HttpResponseMessage? response, CancellationTokenSource cts, bool disposeCts, bool
 0651        {
 652            // Log completion.
 0653            if (HttpTelemetry.Log.IsEnabled() && telemetryStarted)
 0654            {
 0655                if (responseContentTelemetryStarted)
 0656                {
 0657                    HttpTelemetry.Log.ResponseContentStop();
 0658                }
 659
 0660                HttpTelemetry.Log.RequestStop(response);
 0661            }
 662
 663            // Dispose of the CancellationTokenSource if it was created specially for this request
 664            // rather than being used across multiple requests.
 0665            if (disposeCts)
 0666            {
 0667                cts.Dispose();
 0668            }
 669
 670            // This method used to also dispose of the request content, e.g.:
 671            //     request.Content?.Dispose();
 672            // This has multiple problems:
 673            //   1. It prevents code from reusing request content objects for subsequent requests,
 674            //      as disposing of the object likely invalidates it for further use.
 675            //   2. It prevents the possibility of partial or full duplex communication, even if supported
 676            //      by the handler, as the request content may still be in use even if the response
 677            //      (or response headers) has been received.
 678            // By changing this to not dispose of the request content, disposal may end up being
 679            // left for the finalizer to handle, or the developer can explicitly dispose of the
 680            // content when they're done with it.  But it allows request content to be reused,
 681            // and more importantly it enables handlers that allow receiving of the response before
 682            // fully sending the request.  Prior to this change, a handler that supported duplex communication
 683            // would fail trying to access certain sites, if the site sent its response before it had
 684            // completely received the request: CurlHandler might then find that the request content
 685            // was disposed of while it still needed to read from it.
 0686        }
 687
 688        public void CancelPendingRequests()
 0689        {
 0690            ObjectDisposedException.ThrowIf(_disposed, this);
 691
 692            // With every request we link this cancellation token source.
 0693            CancellationTokenSource currentCts = Interlocked.Exchange(ref _pendingRequestsCts, new CancellationTokenSour
 694
 0695            currentCts.Cancel();
 0696            currentCts.Dispose();
 0697        }
 698
 699        #endregion Advanced Send Overloads
 700
 701        #endregion Public Send
 702
 703        #region IDisposable Members
 704
 705        protected override void Dispose(bool disposing)
 0706        {
 0707            if (disposing && !_disposed)
 0708            {
 0709                _disposed = true;
 710
 711                // Cancel all pending requests (if any). Note that we don't call CancelPendingRequests() but cancel
 712                // the CTS directly. The reason is that CancelPendingRequests() would cancel the current CTS and create
 713                // a new CTS. We don't want a new CTS in this case.
 0714                _pendingRequestsCts.Cancel();
 0715                _pendingRequestsCts.Dispose();
 0716            }
 717
 0718            base.Dispose(disposing);
 0719        }
 720
 721        #endregion
 722
 723        #region Private Helpers
 724
 725        private void SetOperationStarted()
 0726        {
 727            // This method flags the HttpClient instances as "active". I.e. we executed at least one request (or are
 728            // in the process of doing so). This information is used to lock-down all property setters. Once a
 729            // Send/SendAsync operation started, no property can be changed.
 0730            if (!_operationStarted)
 0731            {
 0732                _operationStarted = true;
 0733            }
 0734        }
 735
 736        private void CheckDisposedOrStarted()
 0737        {
 0738            ObjectDisposedException.ThrowIf(_disposed, this);
 0739            if (_operationStarted)
 0740            {
 0741                throw new InvalidOperationException(SR.net_http_operation_started);
 742            }
 0743        }
 744
 745        private static void CheckRequestMessage(HttpRequestMessage request)
 0746        {
 0747            if (!request.MarkAsSent())
 0748            {
 0749                throw new InvalidOperationException(SR.net_http_client_request_already_sent);
 750            }
 0751        }
 752
 753        private void PrepareRequestMessage(HttpRequestMessage request)
 0754        {
 0755            Uri? requestUri = null;
 0756            if ((request.RequestUri == null) && (_baseAddress == null))
 0757            {
 0758                throw new InvalidOperationException(SR.net_http_client_invalid_requesturi);
 759            }
 0760            if (request.RequestUri == null)
 0761            {
 0762                requestUri = _baseAddress;
 0763            }
 764            else
 0765            {
 766                // If the request Uri is an absolute Uri, just use it. Otherwise try to combine it with the base Uri.
 0767                if (!request.RequestUri.IsAbsoluteUri)
 0768                {
 0769                    if (_baseAddress == null)
 0770                    {
 0771                        throw new InvalidOperationException(SR.net_http_client_invalid_requesturi);
 772                    }
 773                    else
 0774                    {
 0775                        requestUri = new Uri(_baseAddress, request.RequestUri);
 0776                    }
 0777                }
 0778            }
 779
 780            // We modified the original request Uri. Assign the new Uri to the request message.
 0781            if (requestUri != null)
 0782            {
 0783                request.RequestUri = requestUri;
 0784            }
 785
 786            // Add default headers
 0787            if (_defaultRequestHeaders != null)
 0788            {
 0789                request.Headers.AddHeaders(_defaultRequestHeaders);
 0790            }
 0791        }
 792
 793        private (CancellationTokenSource TokenSource, bool DisposeTokenSource, CancellationTokenSource PendingRequestsCt
 0794        {
 795            // We need a CancellationTokenSource to use with the request.  We always have the global
 796            // _pendingRequestsCts to use, plus we may have a token provided by the caller, and we may
 797            // have a timeout.  If we have a timeout or a caller-provided token, we need to create a new
 798            // CTS (we can't, for example, timeout the pending requests CTS, as that could cancel other
 799            // unrelated operations).  Otherwise, we can use the pending requests CTS directly.
 800
 801            // Snapshot the current pending requests cancellation source. It can change concurrently due to cancellation
 802            // and it being replaced, and we need a stable view of it: if cancellation occurs and the caller's token has
 803            // it's either due to this source or due to the timeout, and checking whether this source is the culprit is 
 804            // it's more approximate checking elapsed time.
 0805            CancellationTokenSource pendingRequestsCts = _pendingRequestsCts;
 806
 0807            bool hasTimeout = _timeout != s_infiniteTimeout;
 0808            if (hasTimeout || cancellationToken.CanBeCanceled)
 0809            {
 0810                CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, pending
 0811                if (hasTimeout)
 0812                {
 0813                    cts.CancelAfter(_timeout);
 0814                }
 815
 0816                return (cts, DisposeTokenSource: true, pendingRequestsCts);
 817            }
 818
 0819            return (pendingRequestsCts, DisposeTokenSource: false, pendingRequestsCts);
 0820        }
 821
 822        private static Uri? CreateUri(string? uri) =>
 0823            string.IsNullOrEmpty(uri) ? null : new Uri(uri, UriKind.RelativeOrAbsolute);
 824
 825        private HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri? uri) =>
 0826            new HttpRequestMessage(method, uri) { Version = _defaultRequestVersion, VersionPolicy = _defaultVersionPolic
 827        #endregion Private Helpers
 828    }
 829}

Methods/Properties

.cctor()
.ctor(System.Net.Http.HttpMessageHandler,System.Boolean)
DefaultProxy()
DefaultProxy(System.Net.IWebProxy)
DefaultRequestHeaders()
DefaultRequestVersion()
DefaultRequestVersion(System.Version)
DefaultVersionPolicy()
DefaultVersionPolicy(System.Net.Http.HttpVersionPolicy)
BaseAddress()
BaseAddress(System.Uri)
Timeout()
Timeout(System.TimeSpan)
MaxResponseContentBufferSize()
MaxResponseContentBufferSize(System.Int64)
.ctor()
.ctor(System.Net.Http.HttpMessageHandler)
GetStringAsync(System.String)
GetStringAsync(System.Uri)
GetStringAsync(System.String,System.Threading.CancellationToken)
GetStringAsync(System.Uri,System.Threading.CancellationToken)
GetStringAsyncCore()
GetByteArrayAsync(System.String)
GetByteArrayAsync(System.Uri)
GetByteArrayAsync(System.String,System.Threading.CancellationToken)
GetByteArrayAsync(System.Uri,System.Threading.CancellationToken)
GetByteArrayAsyncCore()
GetStreamAsync(System.String)
GetStreamAsync(System.String,System.Threading.CancellationToken)
GetStreamAsync(System.Uri)
GetStreamAsync(System.Uri,System.Threading.CancellationToken)
GetStreamAsyncCore()
GetAsync(System.String)
GetAsync(System.Uri)
GetAsync(System.String,System.Net.Http.HttpCompletionOption)
GetAsync(System.Uri,System.Net.Http.HttpCompletionOption)
GetAsync(System.String,System.Threading.CancellationToken)
GetAsync(System.Uri,System.Threading.CancellationToken)
GetAsync(System.String,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken)
GetAsync(System.Uri,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken)
PostAsync(System.String,System.Net.Http.HttpContent)
PostAsync(System.Uri,System.Net.Http.HttpContent)
PostAsync(System.String,System.Net.Http.HttpContent,System.Threading.CancellationToken)
PostAsync(System.Uri,System.Net.Http.HttpContent,System.Threading.CancellationToken)
PutAsync(System.String,System.Net.Http.HttpContent)
PutAsync(System.Uri,System.Net.Http.HttpContent)
PutAsync(System.String,System.Net.Http.HttpContent,System.Threading.CancellationToken)
PutAsync(System.Uri,System.Net.Http.HttpContent,System.Threading.CancellationToken)
PatchAsync(System.String,System.Net.Http.HttpContent)
PatchAsync(System.Uri,System.Net.Http.HttpContent)
PatchAsync(System.String,System.Net.Http.HttpContent,System.Threading.CancellationToken)
PatchAsync(System.Uri,System.Net.Http.HttpContent,System.Threading.CancellationToken)
DeleteAsync(System.String)
DeleteAsync(System.Uri)
DeleteAsync(System.String,System.Threading.CancellationToken)
DeleteAsync(System.Uri,System.Threading.CancellationToken)
Send(System.Net.Http.HttpRequestMessage)
Send(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption)
Send(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)
Send(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken)
SendAsync(System.Net.Http.HttpRequestMessage)
SendAsync(System.Net.Http.HttpRequestMessage,System.Threading.CancellationToken)
SendAsync(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption)
SendAsync(System.Net.Http.HttpRequestMessage,System.Net.Http.HttpCompletionOption,System.Threading.CancellationToken)
Core()
CheckRequestBeforeSend(System.Net.Http.HttpRequestMessage)
ThrowForNullResponse(System.Net.Http.HttpResponseMessage)
ShouldBufferResponse(System.Net.Http.HttpCompletionOption,System.Net.Http.HttpRequestMessage)
HandleFailure(System.Exception,System.Boolean,System.Net.Http.HttpResponseMessage,System.Threading.CancellationTokenSource,System.Threading.CancellationToken,System.Threading.CancellationTokenSource)
StartSend(System.Net.Http.HttpRequestMessage)
FinishSend(System.Net.Http.HttpResponseMessage,System.Threading.CancellationTokenSource,System.Boolean,System.Boolean,System.Boolean)
CancelPendingRequests()
Dispose(System.Boolean)
SetOperationStarted()
CheckDisposedOrStarted()
CheckRequestMessage(System.Net.Http.HttpRequestMessage)
PrepareRequestMessage(System.Net.Http.HttpRequestMessage)
PrepareCancellationTokenSource(System.Threading.CancellationToken)
CreateUri(System.String)
CreateRequestMessage(System.Net.Http.HttpMethod,System.Uri)