public void ParsesRequestLine(
            string requestLine,
            string expectedMethod,
            string expectedRawTarget,
            string expectedRawPath,
// This warns that theory methods should use all of their parameters,
// but this method is using a shared data collection with Http1ConnectionTests.TakeStartLineSetsHttpProtocolProperties and others.
#pragma warning disable xUnit1026
            string expectedDecodedPath,
            string expectedQueryString,
#pragma warning restore xUnit1026
            string expectedVersion)
        {
            var parser         = CreateParser(Mock.Of <IKestrelTrace>());
            var buffer         = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(requestLine));
            var requestHandler = new RequestHandler();

            Assert.True(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));

            Assert.Equal(requestHandler.Method, expectedMethod);
            Assert.Equal(requestHandler.Version, expectedVersion);
            Assert.Equal(requestHandler.RawTarget, expectedRawTarget);
            Assert.Equal(requestHandler.RawPath, expectedRawPath);
            Assert.Equal(requestHandler.Version, expectedVersion);
            Assert.True(buffer.Slice(consumed).IsEmpty);
            Assert.True(buffer.Slice(examined).IsEmpty);
        }
        /// <summary>
        /// Searches for a span of bytes in the <see cref="ReadOnlyBuffer"/> and returns a sliced <see cref="ReadOnlyBuffer"/> that
        /// contains all data up to and excluding the first byte of the span, and a <see cref="SequencePosition"/> that points to the last byte of the span.
        /// </summary>
        /// <param name="span">The <see cref="Span{Byte}"/> byte to search for</param>
        /// <param name="slice">A <see cref="ReadOnlyBuffer"/> that matches all data up to and excluding the first byte</param>
        /// <param name="cursor">A <see cref="SequencePosition"/> that points to the second byte</param>
        /// <returns>True if the byte sequence was found, false if not found</returns>
        public static bool TrySliceTo(this ReadOnlyBuffer <byte> buffer, Span <byte> span, out ReadOnlyBuffer <byte> slice, out SequencePosition cursor)
        {
            var result    = false;
            var subBuffer = buffer;

            do
            {
                // Find the first byte
                if (!subBuffer.TrySliceTo(span[0], out slice, out cursor))
                {
                    break;
                }

                // Move the buffer to where you fonud the first byte then search for the next byte
                subBuffer = buffer.Slice(cursor);

                if (subBuffer.StartsWith(span))
                {
                    slice  = buffer.Slice(buffer.Start, cursor);
                    result = true;
                    break;
                }

                // REVIEW: We need to check the performance of Slice in a loop like this
                // Not a match so skip(1)
                subBuffer = subBuffer.Slice(1);
            } while (!subBuffer.IsEmpty);

            return(result);
        }
Esempio n. 3
0
    static bool FullRequest()
    {
        ReadOnlyBuffer <byte> buffer = new ReadOnlyBuffer <byte>(s_plaintextTechEmpowerRequestBytes);
        var      parser        = new HttpParser();
        var      request       = new Request();
        int      consumedBytes = 0;
        Position examined;
        Position consumed = buffer.Start;
        bool     success  = true;

        foreach (var iteration in Benchmark.Iterations)
        {
            using (iteration.StartMeasurement()) {
                for (int i = 0; i < Benchmark.InnerIterationCount; i++)
                {
                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);

                    success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined);
                    success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes);
                }
            }
        }

        return(success);
    }
        public static bool TryParseMessage(ref ReadOnlyBuffer <byte> buffer, out ReadOnlyBuffer <byte> payload)
        {
            long length = 0;

            payload = default(ReadOnlyBuffer <byte>);

            if (buffer.Length < sizeof(long))
            {
                return(false);
            }

            // Read the length
            length = buffer.Span.Slice(0, sizeof(long)).ReadBigEndian <long>();

            if (length > Int32.MaxValue)
            {
                throw new FormatException("Messages over 2GB in size are not supported");
            }

            // We don't have enough data
            if (buffer.Length < (int)length + sizeof(long))
            {
                return(false);
            }

            // Get the payload
            payload = buffer.Slice(sizeof(long), (int)length);

            // Skip the payload
            buffer = buffer.Slice((int)length + sizeof(long));
            return(true);
        }
Esempio n. 5
0
        protected virtual void ProcessRequest(TcpConnection socket)
        {
            Log.LogVerbose("Processing Request");

            using (BufferSequence rootBuffer = new BufferSequence(RequestBufferSize)) {
                BufferSequence requestBuffer = rootBuffer;
                int            totalWritten  = 0;
                while (true)
                {
                    Span <byte> requestSpan = requestBuffer.Free;

                    int requestBytesRead = socket.Receive(requestSpan);
                    if (requestBytesRead == 0)
                    {
                        socket.Close();
                        return;
                    }

                    requestBuffer.Advance(requestBytesRead);
                    totalWritten += requestBytesRead;
                    if (requestBytesRead == requestSpan.Length)
                    {
                        requestBuffer = requestBuffer.Append(RequestBufferSize);
                    }
                    else
                    {
                        break;
                    }
                }

                var requestBytes = new ReadOnlyBuffer <byte>(rootBuffer, 0, requestBuffer, requestBuffer.Memory.Length);

                var request = new HttpRequest();
                if (!s_parser.ParseRequestLine(ref request, requestBytes, out int consumed))
                {
                    throw new Exception();
                }
                requestBytes = requestBytes.Slice(consumed);
                if (!s_parser.ParseHeaders(ref request, requestBytes, out consumed))
                {
                    throw new Exception();
                }

                var requestBody = requestBytes.Slice(consumed);

                Log.LogRequest(request, requestBody);

                using (var response = new TcpConnectionFormatter(socket, ResponseBufferSize)) {
                    WriteResponse(ref request, requestBody, response);
                }

                socket.Close();
            }

            if (Log.IsVerbose)
            {
                Log.LogMessage(Log.Level.Verbose, "Request Processed and Response Sent", DateTime.UtcNow.Ticks);
            }
        }
Esempio n. 6
0
        public static bool TryParseMessage(ref ReadOnlyBuffer <byte> buffer, out ReadOnlyBuffer <byte> payload)
        {
            payload = default;

            if (buffer.IsEmpty)
            {
                return(false);
            }

            // The payload starts with a length prefix encoded as a VarInt. VarInts use the most significant bit
            // as a marker whether the byte is the last byte of the VarInt or if it spans to the next byte. Bytes
            // appear in the reverse order - i.e. the first byte contains the least significant bits of the value
            // Examples:
            // VarInt: 0x35 - %00110101 - the most significant bit is 0 so the value is %x0110101 i.e. 0x35 (53)
            // VarInt: 0x80 0x25 - %10000000 %00101001 - the most significant bit of the first byte is 1 so the
            // remaining bits (%x0000000) are the lowest bits of the value. The most significant bit of the second
            // byte is 0 meaning this is last byte of the VarInt. The actual value bits (%x0101001) need to be
            // prepended to the bits we already read so the values is %01010010000000 i.e. 0x1480 (5248)
            // We support paylads up to 2GB so the biggest number we support is 7fffffff which when encoded as
            // VarInt is 0xFF 0xFF 0xFF 0xFF 0x07 - hence the maximum length prefix is 5 bytes.

            var length   = 0U;
            var numBytes = 0;

            var  lengthPrefixBuffer = buffer.Span.Slice(0, Math.Min(MaxLengthPrefixSize, buffer.Length));
            byte byteRead;

            do
            {
                byteRead = lengthPrefixBuffer[numBytes];
                length   = length | (((uint)(byteRead & 0x7f)) << _numBitsToShift[numBytes]);
                numBytes++;
            }while (numBytes < lengthPrefixBuffer.Length && ((byteRead & 0x80) != 0));

            // size bytes are missing
            if ((byteRead & 0x80) != 0 && (numBytes < MaxLengthPrefixSize))
            {
                return(false);
            }

            if ((byteRead & 0x80) != 0 || (numBytes == MaxLengthPrefixSize && byteRead > 7))
            {
                throw new FormatException("Messages over 2GB in size are not supported.");
            }

            // We don't have enough data
            if (buffer.Length < length + numBytes)
            {
                return(false);
            }

            // Get the payload
            payload = buffer.Slice(numBytes, (int)length);

            // Skip the payload
            buffer = buffer.Slice(numBytes + (int)length);
            return(true);
        }
        public async Task ReaderShouldNotGetUnflushedBytesWithAppend()
        {
            // Write 10 and flush
            PipeWriter buffer = _pipe.Writer;

            buffer.Write(new byte[] { 0, 0, 0, 10 });
            await buffer.FlushAsync();

            // Write Hello to another pipeline and get the buffer
            byte[] bytes = Encoding.ASCII.GetBytes("Hello");

            var c2 = new Pipe(new PipeOptions(_pool));
            await c2.Writer.WriteAsync(bytes);

            ReadResult result = await c2.Reader.ReadAsync();

            ReadOnlyBuffer <byte> c2Buffer = result.Buffer;

            Assert.Equal(bytes.Length, c2Buffer.Length);

            // Write 9 to the buffer
            buffer = _pipe.Writer;
            buffer.Write(new byte[] { 0, 0, 0, 9 });

            // Append the data from the other pipeline
            foreach (ReadOnlyMemory <byte> memory in c2Buffer)
            {
                buffer.Write(memory.Span);
            }

            // Mark it as consumed
            c2.Reader.AdvanceTo(c2Buffer.End);

            // Now read and make sure we only see the comitted data
            result = await _pipe.Reader.ReadAsync();

            ReadOnlyBuffer <byte> reader = result.Buffer;

            Assert.Equal(4, reader.Length);
            Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());

            // Consume nothing
            _pipe.Reader.AdvanceTo(reader.Start);

            // Flush the second set of writes
            await buffer.FlushAsync();

            reader = (await _pipe.Reader.ReadAsync()).Buffer;

            // int, int, "Hello"
            Assert.Equal(13, reader.Length);
            Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());
            Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray());
            Assert.Equal("Hello", Encoding.ASCII.GetString(reader.Slice(8).ToArray()));

            _pipe.Reader.AdvanceTo(reader.Start, reader.Start);
        }
Esempio n. 8
0
        public void SequencePositionOfMultiSegment()
        {
            var(first, last) = BufferList.Create(
                new byte[] { 1, 2 },
                new byte[] { 3, 4 }
                );
            var bytes = new ReadOnlyBuffer <byte>(first, 0, last, last.Memory.Length);

            Assert.Equal(4, bytes.Length);

            // Static method call to avoid calling instance methods
            Assert.False(Sequence.PositionOf(bytes, 0).HasValue);

            for (int i = 0; i < bytes.Length; i++)
            {
                var value = (byte)(i + 1);

                var listPosition = MemoryListExtensions.PositionOf(first, value).GetValueOrDefault();
                var(node, index) = listPosition.Get <IMemoryList <byte> >();

                if (listPosition != default)
                {
                    Assert.Equal(value, node.Memory.Span[index]);
                }

                var robPosition         = ReadOnlyBufferExtensions.PositionOf(bytes, value);
                var robSequencePosition = Sequence.PositionOf(bytes, value);

                Assert.Equal(listPosition, robPosition);
                Assert.Equal(listPosition, robSequencePosition);

                var robSlice = bytes.Slice(1);
                robPosition         = ReadOnlyBufferExtensions.PositionOf(robSlice, value);
                robSequencePosition = Sequence.PositionOf(robSlice, value);

                if (i > 0)
                {
                    Assert.Equal(listPosition, robPosition);
                    Assert.Equal(listPosition, robSequencePosition);
                }
                else
                {
                    Assert.False(robPosition.HasValue);
                    Assert.False(robSequencePosition.HasValue);
                }

                if (listPosition != default)
                {
                    robSlice = bytes.Slice(listPosition);
                    Assert.Equal(value, robSlice.First.Span[0]);
                }
            }
        }
            private void ParseExtension(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined)
            {
                // Chunk-extensions not currently parsed
                // Just drain the data
                consumed = buffer.Start;
                examined = buffer.Start;

                do
                {
                    SequencePosition?extensionCursorPosition = buffer.PositionOf(ByteCR);
                    if (extensionCursorPosition == null)
                    {
                        // End marker not found yet
                        consumed = buffer.End;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(buffer.Length);
                        return;
                    }
                    ;

                    var extensionCursor        = extensionCursorPosition.Value;
                    var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;

                    var sufixBuffer = buffer.Slice(extensionCursor);
                    if (sufixBuffer.Length < 2)
                    {
                        consumed = extensionCursor;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive);
                        return;
                    }

                    sufixBuffer = sufixBuffer.Slice(0, 2);
                    var sufixSpan = sufixBuffer.ToSpan();

                    if (sufixSpan[1] == '\n')
                    {
                        // We consumed the \r\n at the end of the extension, so switch modes.
                        _mode = _inputLength > 0 ? Mode.Data : Mode.Trailer;

                        consumed = sufixBuffer.End;
                        examined = sufixBuffer.End;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 2);
                    }
                    else
                    {
                        // Don't consume suffixSpan[1] in case it is also a \r.
                        buffer   = buffer.Slice(charsToByteCRExclusive + 1);
                        consumed = extensionCursor;
                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 1);
                    }
                } while (_mode == Mode.Extension);
            }
Esempio n. 10
0
        public void ParseRequestLineSplitBufferWithoutNewLineDoesNotUpdateConsumed()
        {
            HttpParser parser = new HttpParser();

            ReadOnlyBuffer <byte> buffer         = BufferUtilities.CreateBuffer("GET ", "/");
            RequestHandler        requestHandler = new RequestHandler();

            bool result = parser.ParseRequestLine(requestHandler, buffer, out SequencePosition consumed, out SequencePosition examined);

            Assert.False(result);
            Assert.Equal(buffer.Slice(consumed).Length, buffer.Length);
            Assert.True(buffer.Slice(examined).IsEmpty);
        }
Esempio n. 11
0
        public void ParseHeadersDoesNotConsumeIncompleteHeader(string rawHeaders)
        {
            var parser = CreateParser(Mock.Of <IKestrelTrace>());

            var buffer         = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(rawHeaders));
            var requestHandler = new RequestHandler();

            parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);

            Assert.Equal(buffer.Length, buffer.Slice(consumed).Length);
            Assert.True(buffer.Slice(examined).IsEmpty);
            Assert.Equal(0, consumedBytes);
        }
            private void ParseChunkedSuffix(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined)
            {
                consumed = buffer.Start;
                examined = buffer.Start;

                if (buffer.Length < 2)
                {
                    examined = buffer.End;
                    return;
                }

                var suffixBuffer = buffer.Slice(0, 2);
                var suffixSpan   = suffixBuffer.ToSpan();

                if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n')
                {
                    consumed = suffixBuffer.End;
                    examined = suffixBuffer.End;
                    AddAndCheckConsumedBytes(2);
                    _mode = Mode.Prefix;
                }
                else
                {
                    _context.ThrowRequestRejected(RequestRejectionReason.BadChunkSuffix);
                }
            }
Esempio n. 13
0
        private static T ReadMultiLittle <[Primitive] T>(ReadOnlyBuffer <byte> buffer, int len) where T : struct
        {
            Span <byte> localSpan = stackalloc byte[len];

            buffer.Slice(0, len).CopyTo(localSpan);
            return(((ReadOnlySpan <byte>)localSpan).ReadLittleEndian <T>());
        }
Esempio n. 14
0
        public void TestSeekByteLimitWithinSameBlock(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue)
        {
            // Arrange
            ReadOnlyBuffer <byte> originalBuffer = Factory.CreateWithContent(input);

            // Act
            ReadOnlyBuffer <byte> buffer = limit > input.Length ? originalBuffer : originalBuffer.Slice(0, limit);

            SequencePosition?result = buffer.PositionOf((byte)seek);

            // Assert
            if (expectedReturnValue == -1)
            {
                Assert.Null(result);
            }
            else
            {
                Assert.NotNull(result);
            }

            if (expectedReturnValue != -1)
            {
                Assert.Equal(Encoding.ASCII.GetBytes(input.Substring(expectedBytesScanned - 1)), originalBuffer.Slice(result.Value).ToArray());
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Trim whitespace starting from the specified <see cref="ReadOnlyBuffer"/>.
        /// </summary>
        /// <param name="buffer">The <see cref="ReadOnlyBuffer"/> to trim</param>
        /// <returns>A new <see cref="ReadOnlyBuffer"/> with the starting whitespace trimmed.</returns>
        public static ReadOnlyBuffer TrimEnd(this ReadOnlyBuffer buffer)
        {
            var end = -1;
            var i   = 0;

            foreach (var memory in buffer)
            {
                var span = memory.Span;
                for (int j = 0; j < span.Length; j++)
                {
                    i++;
                    if (IsWhitespaceChar(span[j]))
                    {
                        if (end == -1)
                        {
                            end = i;
                        }
                    }
                    else
                    {
                        end = -1;
                    }
                }
            }

            return(end != -1 ? buffer.Slice(0, end - 1) : buffer);
        }
            private void ParseChunkedTrailer(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined)
            {
                consumed = buffer.Start;
                examined = buffer.Start;

                if (buffer.Length < 2)
                {
                    examined = buffer.End;
                    return;
                }

                var trailerBuffer = buffer.Slice(0, 2);
                var trailerSpan   = trailerBuffer.ToSpan();

                if (trailerSpan[0] == '\r' && trailerSpan[1] == '\n')
                {
                    consumed = trailerBuffer.End;
                    examined = trailerBuffer.End;
                    AddAndCheckConsumedBytes(2);
                    _mode = Mode.Complete;
                }
                else
                {
                    _mode = Mode.TrailerHeaders;
                }
            }
Esempio n. 17
0
        public void TestSeekIteratorLimitWithinSameBlock(string input, char seek, char limitAfter, int expectedReturnValue)
        {
            ReadOnlyBuffer <byte> originalBuffer = Factory.CreateWithContent(input);

            SequencePosition      scan1  = originalBuffer.Start;
            ReadOnlyBuffer <byte> buffer = originalBuffer;

            // Act
            SequencePosition?end = originalBuffer.PositionOf((byte)limitAfter);

            if (end.HasValue)
            {
                buffer = originalBuffer.Slice(buffer.Start, buffer.GetPosition(end.Value, 1));
            }

            SequencePosition?returnValue1 = buffer.PositionOf((byte)seek);

            // Assert
            Assert.Equal(input.Contains(limitAfter), end.HasValue);

            if (expectedReturnValue != -1)
            {
                int expectedEndIndex = input.IndexOf(seek);

                Assert.NotNull(returnValue1);
                Assert.Equal(Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)), originalBuffer.Slice(returnValue1.Value).ToArray());
            }
        }
Esempio n. 18
0
        public void TechEmpowerRob()
        {
            var parser  = new HttpParser();
            var request = new Request();
            ReadOnlyBuffer <byte> buffer = new ReadOnlyBuffer <byte>(_plaintextTechEmpowerRequestBytes);

            Assert.True(parser.ParseRequestLine(ref request, buffer, out var consumed));
            Assert.Equal(25, consumed);

            Assert.True(parser.ParseHeaders(ref request, buffer.Slice(consumed), out consumed));
            Assert.Equal(139, consumed);

            // request line
            Assert.Equal(Http.Method.Get, request.Method);
            Assert.Equal(Http.Version.Http11, request.Version);
            Assert.Equal("/plaintext", request.Path);

            // headers
            Assert.Equal(3, request.Headers.Count);
            Assert.True(request.Headers.ContainsKey("Host"));
            Assert.True(request.Headers.ContainsKey("Accept"));
            Assert.True(request.Headers.ContainsKey("Connection"));
            Assert.Equal("localhost", request.Headers["Host"]);
            Assert.Equal("text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7", request.Headers["Accept"]);
            Assert.Equal("keep-alive", request.Headers["Connection"]);
        }
Esempio n. 19
0
        public void TryParseInt32Multisegment(int expected)
        {
            byte[] array = new byte[32];
            Utf8Formatter.TryFormat(expected, array, out var written);
            array[written] = (byte)'#';
            var memory = new Memory <byte>(array, 0, written + 1);

            for (int pivot = 0; pivot < written; pivot++)
            {
                var front = memory.Slice(0, pivot);
                var back  = memory.Slice(pivot);
                var first = new BufferList(front);
                var last  = first.Append(back);

                var bytes = new ReadOnlyBuffer <byte>(first, 0, last, last.Memory.Length);

                Assert.True(Sequence.TryParse(bytes, out int value, out int consumed));
                Assert.Equal(expected, value);

                Assert.True(Sequence.TryParse(bytes, out value, out SequencePosition consumedPosition));
                Assert.Equal(expected, value);

                var afterValue = bytes.Slice(consumedPosition);
                Assert.Equal((byte)'#', afterValue.First.Span[0]);
            }
        }
Esempio n. 20
0
        public bool TakeMessageHeaders(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
        {
            // Make sure the buffer is limited
            bool overLength = false;

            if (buffer.Length >= _remainingRequestHeadersBytesAllowed)
            {
                buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed);

                // If we sliced it means the current buffer bigger than what we're
                // allowed to look at
                overLength = true;
            }

            var result = _parser.ParseHeaders(new Http1ParsingHandler(this), buffer, out consumed, out examined, out var consumedBytes);

            _remainingRequestHeadersBytesAllowed -= consumedBytes;

            if (!result && overLength)
            {
                ThrowRequestRejected(RequestRejectionReason.HeadersExceedMaxTotalSize);
            }
            if (result)
            {
                TimeoutControl.CancelTimeout();
            }

            return(result);
        }
Esempio n. 21
0
        public void MemorySeek(string raw, char searchFor, int expectIndex)
        {
            ReadOnlyBuffer <byte> cursors = Factory.CreateWithContent(raw);
            SequencePosition?     result  = cursors.PositionOf((byte)searchFor);

            Assert.NotNull(result);
            Assert.Equal(cursors.Slice(result.Value).ToArray(), Encoding.ASCII.GetBytes(raw.Substring(expectIndex)));
        }
        public async Task ReaderShouldNotGetUnflushedBytesWhenOverflowingSegments()
        {
            // Fill the block with stuff leaving 5 bytes at the end
            Memory <byte> buffer = _pipe.Writer.GetMemory();

            int len = buffer.Length;

            // Fill the buffer with garbage
            //     block 1       ->    block2
            // [padding..hello]  ->  [  world   ]
            byte[] paddingBytes = Enumerable.Repeat((byte)'a', len - 5).ToArray();
            _pipe.Writer.Write(paddingBytes);
            await _pipe.Writer.FlushAsync();

            // Write 10 and flush
            _pipe.Writer.Write(new byte[] { 0, 0, 0, 10 });

            // Write 9
            _pipe.Writer.Write(new byte[] { 0, 0, 0, 9 });

            // Write 8
            _pipe.Writer.Write(new byte[] { 0, 0, 0, 8 });

            // Make sure we don't see it yet
            ReadResult result = await _pipe.Reader.ReadAsync();

            ReadOnlyBuffer <byte> reader = result.Buffer;

            Assert.Equal(len - 5, reader.Length);

            // Don't move
            _pipe.Reader.AdvanceTo(reader.End);

            // Now flush
            await _pipe.Writer.FlushAsync();

            reader = (await _pipe.Reader.ReadAsync()).Buffer;

            Assert.Equal(12, reader.Length);
            Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());
            Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray());
            Assert.Equal(new byte[] { 0, 0, 0, 8 }, reader.Slice(8, 4).ToArray());

            _pipe.Reader.AdvanceTo(reader.Start, reader.Start);
        }
Esempio n. 23
0
        public static bool TryParseMessage(ref ReadOnlyBuffer <byte> buffer, out ReadOnlyBuffer <byte> payload)
        {
            payload = default(ReadOnlyBuffer <byte>);

            var index = buffer.Span.IndexOf(TextMessageFormatter.RecordSeparator);

            if (index == -1)
            {
                return(false);
            }

            payload = buffer.Slice(0, index);

            // Skip record separator
            buffer = buffer.Slice(index + 1);

            return(true);
        }
        /// <summary>
        /// Checks to see if the <see cref="ReadOnlyBuffer"/> starts with the specified <see cref="Span{Byte}"/>.
        /// </summary>
        /// <param name="value">The <see cref="Span{Byte}"/> to compare to</param>
        /// <returns>True if the bytes StartsWith, false if not</returns>
        public static bool StartsWith(this ReadOnlyBuffer <byte> buffer, Span <byte> value)
        {
            if (buffer.Length < value.Length)
            {
                // just nope
                return(false);
            }

            return(buffer.Slice(0, value.Length).EqualsTo(value));
        }
Esempio n. 25
0
        private void VerifyRawHeaders(string rawHeaders, IEnumerable <string> expectedHeaderNames, IEnumerable <string> expectedHeaderValues)
        {
            Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match");

            var parser = new HttpParser();
            var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(rawHeaders));

            var requestHandler = new RequestHandler();

            parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);

            var parsedHeaders = requestHandler.Headers.ToArray();

            Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length);
            Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key));
            Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value));
            Assert.True(buffer.Slice(consumed).IsEmpty);
            Assert.True(buffer.Slice(examined).IsEmpty);
        }
Esempio n. 26
0
        //[Fact]
        //public void ExceptionDetailNotIncludedWhenLogLevelInformationNotEnabled()
        //{
        //    var mockTrace = new HttpParser();
        //    mockTrace
        //        .Setup(trace => trace.IsEnabled(LogLevel.Information))
        //        .Returns(false);

        //    var parser = new HttpParser();

        //    // Invalid request line
        //    var buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n"));
        //    var requestHandler = new RequestHandler();

        //    var exception = Assert.Throws<BadHttpRequestException>(() =>
        //        parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));

        //    Assert.Equal("Invalid request line: ''", exception.Message);
        //    Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode);

        //    // Unrecognized HTTP version
        //    buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n"));

        //    exception = Assert.Throws<BadHttpRequestException>(() =>
        //        parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));

        //    Assert.Equal("Unrecognized HTTP version: ''", exception.Message);
        //    Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, (exception as BadHttpRequestException).StatusCode);

        //    // Invalid request header
        //    buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes("Header: value\n\r\n"));

        //    exception = Assert.Throws<BadHttpRequestException>(() =>
        //        parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes));

        //    Assert.Equal("Invalid request header: ''", exception.Message);
        //    Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);
        //}

        private void VerifyHeader(
            string headerName,
            string rawHeaderValue,
            string expectedHeaderValue)
        {
            var parser = new HttpParser();
            var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n"));

            var requestHandler = new RequestHandler();

            parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes);

            var pairs = requestHandler.Headers.ToArray();

            Assert.Equal(1, pairs.Length);
            Assert.Equal(headerName, pairs[0].Key);
            Assert.Equal(expectedHeaderValue, pairs[0].Value);
            Assert.True(buffer.Slice(consumed).IsEmpty);
            Assert.True(buffer.Slice(examined).IsEmpty);
        }
Esempio n. 27
0
        public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine)
        {
            var parser         = CreateParser(Mock.Of <IKestrelTrace>());
            var buffer         = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(requestLine));
            var requestHandler = new RequestHandler();

            Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined));

            Assert.Equal(buffer.Start, consumed);
            Assert.True(buffer.Slice(examined).IsEmpty);
        }
Esempio n. 28
0
        public void ParseHeadersConsumesBytesCorrectlyAtEnd()
        {
            var parser = CreateParser(Mock.Of <IKestrelTrace>());

            const string headerLine     = "Header: value\r\n\r";
            var          buffer1        = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(headerLine));
            var          requestHandler = new RequestHandler();

            Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes));

            Assert.Equal(buffer1.GetPosition(buffer1.Start, headerLine.Length - 1), consumed);
            Assert.Equal(buffer1.End, examined);
            Assert.Equal(headerLine.Length - 1, consumedBytes);

            var buffer2 = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes("\r\n"));

            Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes));

            Assert.True(buffer2.Slice(consumed).IsEmpty);
            Assert.True(buffer2.Slice(examined).IsEmpty);
            Assert.Equal(2, consumedBytes);
        }
        public override TPackageInfo Filter(ref ReadOnlyBuffer <byte> buffer)
        {
            ReadOnlyBuffer <byte> slice;
            Position cursor;

            if (!buffer.TrySliceTo(new Span <byte>(_terminator), out slice, out cursor))
            {
                return(null);
            }

            buffer = buffer.Slice(cursor).Slice(_terminator.Length);
            return(ResolvePackage(slice));
        }
Esempio n. 30
0
        private static void FindAllNewLines(ReadOnlyBuffer buffer)
        {
            while (true)
            {
                var position = buffer.PositionOf((byte)'\n');
                if (position == null)
                {
                    break;
                }

                buffer = buffer.Slice(position.Value).Slice(1);
            }
        }