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)); }