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