Azure.Core.Http.Multipart.MultipartReader - Coverage Report

 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}

ncG1vNJzZmiZqqq%2Fpr%2FDpJirrJmbrqTA0meZpaeSY7CwvsRnrqKmlKTEtHrNnqtomaqqv6Z50p2iZp6fp3qvsdNoeqiclVp%2FcY%2FOr5yrmZeafILG1KucZ4ukpL%2Bis8RneaWnkqh7g63TnJ%2BYhaWhwaq8wKuri52RmbKzesetpKU%3D