public override async Task <int> ReadAsync(
            byte[] buffer,
            int offset,
            int count,
            CancellationToken cancellationToken)
        {
            Validation.RequireValidBuffer(buffer, offset, count);

            // Finished?
            if (_trailerReader.IsCompleted)
            {
                return(0);
            }

            // Before reading the body,
            // make sure we have the header (so we know its length)
            await EnsureChunkHeaderWasReadAsync(cancellationToken);

            // Here, chunk header is defined,
            // If the chunk we are reading is the last chunk,
            // Read the remaining chunk trailer, and always return zero byte.
            if (_currentChunkHeader.Length == 0)
            {
                await _trailerReader.ReadTrailerAsync(_header);

                return(0);
            }
            // If the chunk we are reading is not the last chunk,
            // read it and return number of bytes read.
            else
            {
                return(await ContinueReadChunkBodyAsync(buffer, offset, count));
            }
        }
        public async Task AppendAsync(byte[] buffer, int offset, int count)
        {
            Validation.RequireValidBuffer(buffer, offset, count);

            // Size of the requested buffer too large for our internal buffer?
            // Split it into multiple writes
            while (count > _maxChunkSize)
            {
                await AppendAsync(buffer, offset, _maxChunkSize);

                offset += _maxChunkSize;
                count  -= _maxChunkSize;
            }

            // Size of the requested buffer is now smaller
            // than or equal to our internal buffer size.
            //
            // First, flush the internal buffer if
            // it doesn't have enough space for appending
            if ((_buffer.Length + count) > _maxChunkSize)
            {
                await FlushAsync();
            }

            // Now write to the internal buffer
            _buffer.Write(buffer, offset, count);
        }
示例#3
0
        /// <summary>
        /// Pop data from the stack,
        /// Copy 'count' bytes to the specified buffer, starting from offset.
        /// </summary>
        public void Pop(byte[] dest, int offset, int count)
        {
            // Some validations
            Validation.RequireValidBuffer(dest, offset, count);
            RequireEnoughDataToPop(count);

            // Write to dest!
            Buffer.BlockCopy(
                src:            _stackData,
                srcOffset:      _rollbackBufferTopIndex,
                dst:            dest,
                dstOffset:      offset,
                count:          count
                );

            // Move the head of the stack to the right 'count' bytes.
            // Notes: it is important to move the pointer after the BlockCopy() above.
            _rollbackBufferTopIndex += count;
        }
示例#4
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);
        }
示例#5
0
        /// <summary>
        /// Push data to the stack,
        /// Copy 'count' bytes from specified buffer into the stack,
        /// starting from 'offset'.
        /// </summary>
        public void Push(byte[] src, int offset, int count)
        {
            // Some validations
            Validation.RequireValidBuffer(src, offset, count);
            RequireEnoughSpaceToPush(count);

            // Move the head of the stack to the left 'count' bytes.
            // Notes: it is important to move the pointer first,
            // before doing BlockCopy()
            _rollbackBufferTopIndex -= count;

            // Write!
            Buffer.BlockCopy(
                src:            src,
                srcOffset:      offset,
                dst:            _stackData,
                dstOffset:      _rollbackBufferTopIndex,
                count:          count
                );
        }
示例#6
0
        /// <summary>
        /// Read data from the underlying stream into the specified buffer;
        /// If caller already Push() some data into the stream, those data are read first.
        /// </summary>
        public override async Task <int> ReadAsync(
            byte[] buffer,
            int offset,
            int count,
            CancellationToken cancellationToken)
        {
            Validation.RequireValidBuffer(buffer, offset, count);

            // Do we have data in the _readAheadBuffer?
            // if so, read from it first;
            if (_readAheadBuffer.Length > 0)
            {
                var bytesToRead = Math.Min(count, _readAheadBuffer.Length);
                _readAheadBuffer.Pop(dest: buffer, offset: offset, count: bytesToRead);
                return(bytesToRead);
            }

            // Pass this point, the _readAheadBuffer is empty,
            // we can read directly from the _rawTcpStream
            return(await _original.ReadAsync(buffer, offset, count, cancellationToken));
        }
示例#7
0
        public bool AppendBuffer(
            byte[] buffer,
            int start,
            int count,
            out int contentStartIndex)
        {
            Validation.RequireValidBuffer(buffer, start, count);
            RequireNullResult();

            // Early exit if there is no new line in the appended buffer;
            contentStartIndex = default(int);
            int nextLineStartIndex;

            if (false == _lineBuilder.AppendBuffer(buffer, start, count, out nextLineStartIndex))
            {
                return(false);
            }

            // New line found in the supplied buffer!
            // The chunk header ends here
            contentStartIndex = nextLineStartIndex;
            _result           = BuildResult(_lineBuilder.Result);
            return(true);
        }
示例#8
0
        /// <summary>
        /// Continue building the line by appending a buffer into this builder,
        /// this method returns true when the appended buffer has a newline
        /// character in it (\r\n or \n);
        /// </summary>
        /// <param name="nextLineStartIndex"></param>
        /// <returns></returns>
        public bool AppendBuffer(
            byte[] buffer,
            int offset,
            int count,
            out int nextLineStartIndex)
        {
            RequireNonDisposed();
            RequireResultNull();
            RequireLength(count);
            Validation.RequireValidBuffer(buffer, offset, count);

            // Append those bytes to our temporary line
            _lineBuilder.Write(buffer, offset, count);

            // Now check our temp line see if it is ended
            var lineBuffer = _lineBuilder.GetBuffer();

            for (var i = 0
                 ; i < _lineBuilder.Length                /*tmp.Length, not tmpBuffer.Length!*/
                 ; i++)
            {
                // Yay! a new line detected,
                // Notes that according HTTP standard, \r\n is a newline,
                // however they recommended to support \n as well.
                // See https://stackoverflow.com/questions/5757290/http-header-line-break-style
                if (lineBuffer[i] == SpecialChars.NL)
                {
                    SetResult(lineBuffer, i);
                    nextLineStartIndex = i - ((int)_lineBuilder.Length - count) + offset + 1;
                    return(true);
                }
            }

            nextLineStartIndex = default(int);
            return(false);
        }