< Summary

Class:Azure.Core.Pipeline.ResponseBodyPolicy
Assembly:Azure.Core
File(s):C:\Git\azure-sdk-for-net\sdk\core\Azure.Core\src\Pipeline\Internal\ResponseBodyPolicy.cs
Covered lines:54
Uncovered lines:3
Coverable lines:57
Total lines:144
Line coverage:94.7% (54 of 57)
Covered branches:19
Total branches:20
Branch coverage:95% (19 of 20)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-100%100%
ProcessAsync()-100%100%
Process(...)-100%100%
ProcessAsync()-90%93.75%
CopyToAsync()-100%100%
CopyTo(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\core\Azure.Core\src\Pipeline\Internal\ResponseBodyPolicy.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Buffers;
 6using System.IO;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using Azure.Core.Buffers;
 10
 11namespace Azure.Core.Pipeline
 12{
 13    /// <summary>
 14    /// Pipeline policy to buffer response content or add a timeout to response content managed by the client
 15    /// </summary>
 16    internal class ResponseBodyPolicy : HttpPipelinePolicy
 17    {
 18        // Same value as Stream.CopyTo uses by default
 19        private const int DefaultCopyBufferSize = 81920;
 20
 21        private readonly TimeSpan _networkTimeout;
 22
 6423        public ResponseBodyPolicy(TimeSpan networkTimeout)
 24        {
 6425            _networkTimeout = networkTimeout;
 6426        }
 27
 28        public override async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
 29        {
 105230            await ProcessAsync(message, pipeline, true).ConfigureAwait(false);
 104031        }
 32
 33        public override void Process(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline)
 34        {
 103435            ProcessAsync(message, pipeline, false).EnsureCompleted();
 102236        }
 37
 38        private async ValueTask ProcessAsync(HttpMessage message, ReadOnlyMemory<HttpPipelinePolicy> pipeline, bool asyn
 39        {
 208640            CancellationToken oldToken = message.CancellationToken;
 208641            using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(oldToken);
 42
 208643            cts.CancelAfter(_networkTimeout);
 44            try
 45            {
 208646                message.CancellationToken = cts.Token;
 208647                if (async)
 48                {
 105249                    await ProcessNextAsync(message, pipeline).ConfigureAwait(false);
 50                }
 51                else
 52                {
 103453                    ProcessNext(message, pipeline);
 54                }
 207455            }
 56            finally
 57            {
 208658                message.CancellationToken = oldToken;
 208659                cts.CancelAfter(Timeout.Infinite);
 60            }
 61
 207462            Stream? responseContentStream = message.Response.ContentStream;
 207463            if (responseContentStream == null || responseContentStream.CanSeek)
 64            {
 2265                return;
 66            }
 67
 205268            if (message.BufferResponse)
 69            {
 42870                if (_networkTimeout != Timeout.InfiniteTimeSpan)
 71                {
 41672                    cts.Token.Register(state => ((Stream)state)?.Dispose(), responseContentStream);
 73                }
 74
 75                try
 76                {
 42877                    var bufferedStream = new MemoryStream();
 42878                    if (async)
 79                    {
 21480                        await CopyToAsync(responseContentStream, bufferedStream, cts).ConfigureAwait(false);
 81                    }
 82                    else
 83                    {
 21484                        CopyTo(responseContentStream, bufferedStream, cts);
 85                    }
 86
 41687                    responseContentStream.Dispose();
 41688                    bufferedStream.Position = 0;
 41689                    message.Response.ContentStream = bufferedStream;
 41690                }
 91                // We dispose stream on timeout so catch and check if cancellation token was cancelled
 092                catch (ObjectDisposedException)
 93                {
 094                    cts.Token.ThrowIfCancellationRequested();
 095                    throw;
 96                }
 97            }
 162498            else if (_networkTimeout != Timeout.InfiniteTimeSpan)
 99            {
 1620100                message.Response.ContentStream = new ReadTimeoutStream(responseContentStream, _networkTimeout);
 101            }
 2062102        }
 103
 104        private async Task CopyToAsync(Stream source, Stream destination, CancellationTokenSource cancellationTokenSourc
 105        {
 214106            byte[] buffer = ArrayPool<byte>.Shared.Rent(DefaultCopyBufferSize);
 107            try
 108            {
 2474109                while (true)
 110                {
 2688111                    cancellationTokenSource.CancelAfter(_networkTimeout);
 2688112                    int bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token).Conf
 2682113                    if (bytesRead == 0) break;
 2474114                    await destination.WriteAsync(new ReadOnlyMemory<byte>(buffer, 0, bytesRead), cancellationTokenSource
 115                }
 208116            }
 117            finally
 118            {
 214119                cancellationTokenSource.CancelAfter(Timeout.InfiniteTimeSpan);
 214120                ArrayPool<byte>.Shared.Return(buffer);
 121            }
 208122        }
 123
 124        private void CopyTo(Stream source, Stream destination, CancellationTokenSource cancellationTokenSource)
 125        {
 214126            byte[] buffer = ArrayPool<byte>.Shared.Rent(DefaultCopyBufferSize);
 127            try
 128            {
 129                int read;
 1054130                while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
 131                {
 842132                    cancellationTokenSource.Token.ThrowIfCancellationRequested();
 840133                    cancellationTokenSource.CancelAfter(_networkTimeout);
 840134                    destination.Write(buffer, 0, read);
 135                }
 208136            }
 137            finally
 138            {
 214139                cancellationTokenSource.CancelAfter(Timeout.InfiniteTimeSpan);
 214140                ArrayPool<byte>.Shared.Return(buffer);
 214141            }
 208142        }
 143    }
 144}