Exemplo n.º 1
0
        private async Task <Dictionary <string, StringValues> > ReadHeadersAsync(CancellationToken cancellationToken)
        {
            int totalSize   = 0;
            var accumulator = new KeyValueAccumulator();
            var line        = await _stream.ReadLineAsync(HeadersLengthLimit - totalSize, cancellationToken).ConfigureAwait(false);

            while (!string.IsNullOrEmpty(line))
            {
                if (HeadersLengthLimit - totalSize < line.Length)
                {
                    throw new InvalidDataException($"Multipart headers length limit {HeadersLengthLimit} exceeded.");
                }
                totalSize += line.Length;
                int splitIndex = line.IndexOf(':');
                if (splitIndex <= 0)
                {
                    throw new InvalidDataException($"Invalid header line: {line}");
                }

                var name  = line.Substring(0, splitIndex);
                var value = line.Substring(splitIndex + 1, line.Length - splitIndex - 1).Trim();
                accumulator.Append(name, value);
                if (accumulator.KeyCount > HeadersCountLimit)
                {
                    throw new InvalidDataException($"Multipart headers count limit {HeadersCountLimit} exceeded.");
                }

                line = await _stream.ReadLineAsync(HeadersLengthLimit - totalSize, cancellationToken).ConfigureAwait(false);
            }

            return(accumulator.GetResults());
        }
        public override async Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        {
            if (_finished)
            {
                return(0);
            }

            PositionInnerStream();
            if (!await _innerStream.EnsureBufferedAsync(_boundary.FinalBoundaryLength, cancellationToken).ConfigureAwait(false))
            {
                throw new IOException("Unexpected end of Stream, the content may have already been read by another component. ");
            }
            var bufferedData = _innerStream.BufferedData;

            // scan for a boundary match, full or partial.
            int matchOffset;
            int matchCount;
            int read;

            if (SubMatch(bufferedData, _boundary.BoundaryBytes, out matchOffset, out matchCount))
            {
                // We found a possible match, return any data before it.
                if (matchOffset > bufferedData.Offset)
                {
                    // Sync, it's already buffered
                    read = _innerStream.Read(buffer, offset, Math.Min(count, matchOffset - bufferedData.Offset));
                    return(UpdatePosition(read));
                }

                var length = _boundary.BoundaryBytes.Length;
                Debug.Assert(matchCount == length);

                // "The boundary may be followed by zero or more characters of
                // linear whitespace. It is then terminated by either another CRLF"
                // or -- for the final boundary.
                var boundary = _bytePool.Rent(length);
                read = _innerStream.Read(boundary, 0, length);
                _bytePool.Return(boundary);
                Debug.Assert(read == length);                                                                                                     // It should have all been buffered

                var remainder = await _innerStream.ReadLineAsync(lengthLimit : 100, cancellationToken : cancellationToken).ConfigureAwait(false); // Whitespace may exceed the buffer.

                remainder = remainder.Trim();
                if (string.Equals("--", remainder, StringComparison.Ordinal))
                {
                    FinalBoundaryFound = true;
                }
                Debug.Assert(FinalBoundaryFound || string.Equals(string.Empty, remainder, StringComparison.Ordinal), "Un-expected data found on the boundary line: " + remainder);

                _finished = true;
                return(0);
            }

            // No possible boundary match within the buffered data, return the data from the buffer.
            read = _innerStream.Read(buffer, offset, Math.Min(count, bufferedData.Count));
            return(UpdatePosition(read));
        }