< Summary

Information
Class: System.Net.Http.MessageProcessingHandler
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\MessageProcessingHandler.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 89
Coverable lines: 89
Total lines: 150
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
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%
.ctor(...)100%110%
Send(...)100%110%
SendAsync(...)0%660%
HandleCanceledOperations(...)0%440%
.ctor(...)100%110%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\MessageProcessingHandler.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;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Runtime.ExceptionServices;
 8using System.Text;
 9using System.Threading;
 10using System.Threading.Tasks;
 11
 12namespace System.Net.Http
 13{
 14    public abstract class MessageProcessingHandler : DelegatingHandler
 15    {
 016        protected MessageProcessingHandler()
 017        {
 018        }
 19
 20        protected MessageProcessingHandler(HttpMessageHandler innerHandler)
 021            : base(innerHandler)
 022        {
 023        }
 24
 25        protected abstract HttpRequestMessage ProcessRequest(HttpRequestMessage request,
 26            CancellationToken cancellationToken);
 27        protected abstract HttpResponseMessage ProcessResponse(HttpResponseMessage response,
 28            CancellationToken cancellationToken);
 29
 30        protected internal sealed override HttpResponseMessage Send(HttpRequestMessage request,
 31            CancellationToken cancellationToken)
 032        {
 033            ArgumentNullException.ThrowIfNull(request);
 34
 35            // Since most of the SendAsync code is just Task handling, there's no reason to share the code.
 036            HttpRequestMessage newRequestMessage = ProcessRequest(request, cancellationToken);
 037            HttpResponseMessage response = base.Send(newRequestMessage, cancellationToken);
 038            HttpResponseMessage newResponseMessage = ProcessResponse(response, cancellationToken);
 039            return newResponseMessage;
 040        }
 41
 42        protected internal sealed override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
 43            CancellationToken cancellationToken)
 044        {
 045            ArgumentNullException.ThrowIfNull(request);
 46
 47            // ProcessRequest() and ProcessResponse() are supposed to be fast, so we call ProcessRequest() on the same
 48            // thread SendAsync() was invoked to avoid context switches. However, if ProcessRequest() throws, we have
 49            // to catch the exception since the caller doesn't expect exceptions when calling SendAsync(): The
 50            // expectation is that the returned task will get faulted on errors, but the async call to SendAsync()
 51            // should complete.
 052            var tcs = new SendState(this, cancellationToken);
 53            try
 054            {
 055                HttpRequestMessage newRequestMessage = ProcessRequest(request, cancellationToken);
 056                Task<HttpResponseMessage> sendAsyncTask = base.SendAsync(newRequestMessage, cancellationToken);
 57
 58                // We schedule a continuation task once the inner handler completes in order to trigger the response
 59                // processing method. ProcessResponse() is only called if the task wasn't canceled before.
 060                sendAsyncTask.ContinueWith(static (task, state) =>
 061                {
 062                    var sendState = (SendState)state!;
 063                    MessageProcessingHandler self = sendState._handler;
 064                    CancellationToken token = sendState._token;
 065
 066                    if (task.IsFaulted)
 067                    {
 068                        sendState.TrySetException(task.Exception!.GetBaseException());
 069                        return;
 070                    }
 071
 072                    if (task.IsCanceled)
 073                    {
 074                        sendState.TrySetCanceled(token);
 075                        return;
 076                    }
 077
 078                    if (task.Result == null)
 079                    {
 080                        sendState.TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationExcepti
 081                        return;
 082                    }
 083
 084                    try
 085                    {
 086                        HttpResponseMessage responseMessage = self.ProcessResponse(task.Result, token);
 087                        sendState.TrySetResult(responseMessage);
 088                    }
 089                    catch (OperationCanceledException e)
 090                    {
 091                        // If ProcessResponse() throws an OperationCanceledException check whether it is related to
 092                        // the cancellation token we received from the user. If so, cancel the Task.
 093                        HandleCanceledOperations(token, sendState, e);
 094                    }
 095                    catch (Exception e)
 096                    {
 097                        sendState.TrySetException(e);
 098                    }
 099                    // We don't pass the cancellation token to the continuation task, since we want to get called even
 0100                    // if the operation was canceled: We'll set the Task returned to the user to canceled. Passing the
 0101                    // cancellation token here would result in the continuation task to not be called at all. I.e. we
 0102                    // would never complete the task returned to the caller of SendAsync().
 0103                }, tcs, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
 0104            }
 0105            catch (OperationCanceledException e)
 0106            {
 0107                HandleCanceledOperations(cancellationToken, tcs, e);
 0108            }
 0109            catch (Exception e)
 0110            {
 0111                tcs.TrySetException(e);
 0112            }
 113
 0114            return tcs.Task;
 0115        }
 116
 117        private static void HandleCanceledOperations(CancellationToken cancellationToken,
 118            TaskCompletionSource<HttpResponseMessage> tcs, OperationCanceledException e)
 0119        {
 120            // Check if the exception was due to a cancellation. If so, check if the OperationCanceledException is
 121            // related to our CancellationToken. If it was indeed caused due to our cancellation token being
 122            // canceled, set the Task as canceled. Set it to faulted otherwise, since the OperationCanceledException
 123            // is not related to our cancellation token.
 0124            if (cancellationToken.IsCancellationRequested && (e.CancellationToken == cancellationToken))
 0125            {
 0126                tcs.TrySetCanceled(cancellationToken);
 0127            }
 128            else
 0129            {
 0130                tcs.TrySetException(e);
 0131            }
 0132        }
 133
 134        // Private class used to capture the SendAsync state in
 135        // a closure, while simultaneously avoiding a tuple allocation.
 136        private sealed class SendState : TaskCompletionSource<HttpResponseMessage>
 137        {
 138            internal readonly MessageProcessingHandler _handler;
 139            internal readonly CancellationToken _token;
 140
 0141            public SendState(MessageProcessingHandler handler, CancellationToken token)
 0142            {
 0143                Debug.Assert(handler != null);
 144
 0145                _handler = handler;
 0146                _token = token;
 0147            }
 148        }
 149    }
 150}