< Summary

Class:Azure.Core.Http.Multipart.MultipartReader
Assembly:Azure.Storage.Blobs.Batch
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs.Batch\src\Shared\MultipartReader.cs
Covered lines:35
Uncovered lines:9
Coverable lines:44
Total lines:122
Line coverage:79.5% (35 of 44)
Covered branches:11
Total branches:18
Branch coverage:61.1% (11 of 18)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-100%100%
.ctor(...)-72.73%50%
get_HeadersCountLimit()-0%100%
get_HeadersLengthLimit()-0%100%
get_BodyLengthLimit()-0%100%
ReadNextSectionAsync()-100%75%
ReadHeadersAsync()-83.33%62.5%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs.Batch\src\Shared\MultipartReader.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4// Copied from https://github.com/aspnet/AspNetCore/tree/master/src/Http/WebUtilities/src
 5
 6using System;
 7using System.Collections.Generic;
 8using System.Diagnostics;
 9using System.IO;
 10using System.Threading;
 11using System.Threading.Tasks;
 12
 13#pragma warning disable CA1001  // disposable fields
 14#pragma warning disable IDE0008 // Use explicit type
 15
 16namespace Azure.Core.Http.Multipart
 17{
 18    // https://www.ietf.org/rfc/rfc2046.txt
 19    internal class MultipartReader
 20    {
 21        public const int DefaultHeadersCountLimit = 16;
 22        public const int DefaultHeadersLengthLimit = 1024 * 16;
 23        private const int DefaultBufferSize = 1024 * 4;
 24
 25        private readonly BufferedReadStream _stream;
 26        private readonly MultipartBoundary _boundary;
 27        private MultipartReaderStream _currentStream;
 28
 29        public MultipartReader(string boundary, Stream stream)
 8830            : this(boundary, stream, DefaultBufferSize)
 31        {
 8832        }
 33
 8834        public MultipartReader(string boundary, Stream stream, int bufferSize)
 35        {
 8836            if (boundary == null)
 37            {
 038                throw new ArgumentNullException(nameof(boundary));
 39            }
 40
 8841            if (stream == null)
 42            {
 043                throw new ArgumentNullException(nameof(stream));
 44            }
 45
 8846            if (bufferSize < boundary.Length + 8) // Size of the boundary + leading and trailing CRLF + leading and trai
 47            {
 048                throw new ArgumentOutOfRangeException(nameof(bufferSize), bufferSize, "Insufficient buffer space, the bu
 49            }
 8850            _stream = new BufferedReadStream(stream, bufferSize);
 8851            _boundary = new MultipartBoundary(boundary, false);
 52            // This stream will drain any preamble data and remove the first boundary marker.
 53            // TODO: HeadersLengthLimit can't be modified until after the constructor.
 8854            _currentStream = new MultipartReaderStream(_stream, _boundary) { LengthLimit = HeadersLengthLimit };
 8855        }
 56
 57        /// <summary>
 58        /// The limit for the number of headers to read.
 59        /// </summary>
 060        public int HeadersCountLimit { get; set; } = DefaultHeadersCountLimit;
 61
 62        /// <summary>
 63        /// The combined size limit for headers per multipart section.
 64        /// </summary>
 065        public int HeadersLengthLimit { get; set; } = DefaultHeadersLengthLimit;
 66
 67        /// <summary>
 68        /// The optional limit for the total response body length.
 69        /// </summary>
 070        public long? BodyLengthLimit { get; set; }
 71
 72        public async Task<MultipartSection> ReadNextSectionAsync(CancellationToken cancellationToken = new CancellationT
 73        {
 74            // Drain the prior section.
 136075            await _currentStream.DrainAsync(cancellationToken).ConfigureAwait(false);
 76            // If we're at the end return null
 136077            if (_currentStream.FinalBoundaryFound)
 78            {
 79                // There may be trailer data after the last boundary.
 8880                await _stream.DrainAsync(HeadersLengthLimit, cancellationToken).ConfigureAwait(false);
 8881                return null;
 82            }
 127283            var headers = await ReadHeadersAsync(cancellationToken).ConfigureAwait(false);
 127284            _boundary.ExpectLeadingCrlf = true;
 127285            _currentStream = new MultipartReaderStream(_stream, _boundary) { LengthLimit = BodyLengthLimit };
 127286            long? baseStreamOffset = _stream.CanSeek ? (long?)_stream.Position : null;
 127287            return new MultipartSection() { Headers = headers, Body = _currentStream, BaseStreamOffset = baseStreamOffse
 136088        }
 89
 90        private async Task<Dictionary<string, StringValues>> ReadHeadersAsync(CancellationToken cancellationToken)
 91        {
 127292            int totalSize = 0;
 127293            var accumulator = new KeyValueAccumulator();
 127294            var line = await _stream.ReadLineAsync(HeadersLengthLimit - totalSize, cancellationToken).ConfigureAwait(fal
 381295            while (!string.IsNullOrEmpty(line))
 96            {
 254097                if (HeadersLengthLimit - totalSize < line.Length)
 98                {
 099                    throw new InvalidDataException($"Multipart headers length limit {HeadersLengthLimit} exceeded.");
 100                }
 2540101                totalSize += line.Length;
 2540102                int splitIndex = line.IndexOf(':');
 2540103                if (splitIndex <= 0)
 104                {
 0105                    throw new InvalidDataException($"Invalid header line: {line}");
 106                }
 107
 2540108                var name = line.Substring(0, splitIndex);
 2540109                var value = line.Substring(splitIndex + 1, line.Length - splitIndex - 1).Trim();
 2540110                accumulator.Append(name, value);
 2540111                if (accumulator.KeyCount > HeadersCountLimit)
 112                {
 0113                    throw new InvalidDataException($"Multipart headers count limit {HeadersCountLimit} exceeded.");
 114                }
 115
 2540116                line = await _stream.ReadLineAsync(HeadersLengthLimit - totalSize, cancellationToken).ConfigureAwait(fal
 117            }
 118
 1272119            return accumulator.GetResults();
 1272120        }
 121    }
 122}