/// <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;
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
                }
            }
        }
예제 #4
0
        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);
        }
예제 #6
0
        /// <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);
        }
예제 #8
0
        /// <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;
        }