/// <summary> /// Read trailer and append extra trailer key-values into the specified header. /// </summary> public async Task ReadTrailerAsync(HttpHeader header) { if (header == null) { throw new ArgumentNullException(nameof(header)); } if (_isCompleted) { throw new InvalidOperationException("Trailer already read"); } // Keep reading until we find a blank line while (true) { // Read var bytesRead = await _httpMessageBodyStream.ReadAsync( _readBuffer, 0, _readBuffer.Length); HttpPrematureFinishException.ThrowIfZero(bytesRead); // Process if (HandleBytesRead(bytesRead, header)) { break; } } _isCompleted = true; }
async Task <int> ContinueReadChunkBodyAsync(byte[] buffer, int offset, int count) { Contract.Requires(_currentChunkHeader != null); // Pass this point, // It would be a bug if _currentChunkRemainingBytes is 0 Contract.Assert( _currentChunkRemainingBytes > 0, $"{nameof(_currentChunkRemainingBytes)} cannot less than or equal to zero" ); // Now read. var bytesRead = await _requestStream.ReadAsync( buffer, 0, Math.Min(buffer.Length, (int)Math.Min(count, _currentChunkRemainingBytes))); HttpPrematureFinishException.ThrowIfZero(bytesRead); _currentChunkRemainingBytes -= bytesRead; // No more data to read? if (_currentChunkRemainingBytes == 0) { await CompleteReadingCurrentChunkAsync(); } return(bytesRead); }
async Task EnsureChunkHeaderWasReadAsync( CancellationToken cancellationToken) { while (_currentChunkHeader == null) { cancellationToken.ThrowIfCancellationRequested(); // Read var bytesRead = await _requestStream.ReadAsync(_readBuffer, 0, _readBuffer.Length); HttpPrematureFinishException.ThrowIfZero(bytesRead); // Append the data we just read to the header builder. // If header is built after this call, we are done here. int contentStartIndex; if (_chunkHeaderBuilder.AppendBuffer(_readBuffer, 0, bytesRead, out contentStartIndex)) { // Set current chunk metadata _currentChunkHeader = _chunkHeaderBuilder.Result; _currentChunkRemainingBytes = _chunkHeaderBuilder.Result.Length; // If we read some bytes from the body, rollback those read. _requestStream.TryRollbackFromIndex( _readBuffer, srcLength: bytesRead, startIndex: contentStartIndex); } } }
async Task ReceiveHeaderAsync() { RequireNullHeader(); var headerBuilder = HttpHeaderBuilderFactory.CreateRequestHeaderBuilder(); var buffer = new byte[_tcpSettings.ReadWriteBufferSize]; // Keep reading socket until header received while (null == _requestHeader) { var bytesRead = await _requestStream.ReadAsync(buffer, 0, buffer.Length); HttpPrematureFinishException.ThrowIfZero(bytesRead); int bodyStartIndex; if (headerBuilder.AppendBuffer(buffer, 0, bytesRead, out bodyStartIndex)) { // Done! // Set the header _requestHeader = headerBuilder.Result; // The remaining bytes of the buffer, those belongs to the body. _requestStream.TryRollbackFromIndex(buffer, srcLength: bytesRead, startIndex: bodyStartIndex); } } }
public override int Read(byte[] buffer, int offset, int count) { var maxBytesToRead = (int)Math.Min(count, _contentLength - _position); if (maxBytesToRead == 0) { return(0); } var bytesRead = _requestStream.Read(buffer, offset, maxBytesToRead); HttpPrematureFinishException.ThrowIfZero(bytesRead); _position += bytesRead; return(bytesRead); }
/// <summary> /// Continue building the header by appending the specified buffer. /// </summary> /// <returns>True once building header finishes, /// the Result property becomes available for access.</returns> public bool AppendBuffer( byte[] buffer, int start, int count, out int bodyStartIndex) { Validation.RequireValidBuffer(buffer, start, count); bodyStartIndex = default(int); // Unless there is no new line in this buffer, keep continue. int nextLineStartIndex; while (_lineBuilder.AppendBuffer(buffer, start, count, out nextLineStartIndex)) { RequireTotalLinesLessThanLimit(_totalLines); // Process this line: // AppendResult() returns false indicates // header ends here. Body starts on the next line. if (false == AppendResult(_lineBuilder.Result, ref _requestLine, _entries)) { bodyStartIndex = nextLineStartIndex; // Build result to make the 'Result' property available // for caller. MakeResultPropertyAvailable(); return(true); } // Prep for the next line _lineBuilder.Reset(); count -= nextLineStartIndex - start; start = nextLineStartIndex; // We didn't see the message ends with a blank line, // however the message already end - this is invalid. HttpPrematureFinishException.ThrowIfZero(count); } // Header didn't end within this buffer; return(false); }
public override async Task <int> ReadAsync( byte[] buffer, int offset, int count, CancellationToken cancellationToken) { var maxBytesToRead = (int)Math.Min(count, _contentLength - _position); if (maxBytesToRead == 0) { return(0); } var bytesRead = await _requestStream.ReadAsync( buffer, offset, maxBytesToRead, cancellationToken); HttpPrematureFinishException.ThrowIfZero(bytesRead); _position += bytesRead; return(bytesRead); }
/// <summary> /// Called when current chunk has no more data to read, /// we'll do some cleaning here. /// </summary> async Task CompleteReadingCurrentChunkAsync() { // A chunk always nend with a new line character, // let's skip it. var bytesRead = await _requestStream.ReadAsync(_readBuffer, 0, _readBuffer.Length); HttpPrematureFinishException.ThrowIfZero(bytesRead); if (false == _lineBuilder.AppendBuffer(_readBuffer, 0, bytesRead, out int nextLineStartIndex)) { throw new HttpBadRequestException( "Chunk body must end with an empty line" ); } _lineBuilder.Reset(); _requestStream.TryRollbackFromIndex(_readBuffer, bytesRead, nextLineStartIndex); // Prepare to read the next header _chunkHeaderBuilder.Reset(); // Clear the header, so next ReadAsync() operation // will attempt to read the next header _currentChunkHeader = null; }