public async Task AdvanceWithGetPositionCrossingIntoWriteHeadWorks()
        {
            // Create two blocks
            Memory <byte> memory = _pipe.Writer.GetMemory(1);

            _pipe.Writer.Advance(memory.Length);
            memory = _pipe.Writer.GetMemory(1);
            _pipe.Writer.Advance(memory.Length);
            await _pipe.Writer.FlushAsync();

            // Read single block
            ReadResult readResult = await _pipe.Reader.ReadAsync();

            // Allocate more memory
            memory = _pipe.Writer.GetMemory(1);

            // Create position that would cross into write head
            ReadOnlyBuffer <byte> buffer   = readResult.Buffer;
            SequencePosition      position = buffer.GetPosition(buffer.Start, buffer.Length);

            // Return everything
            _pipe.Reader.AdvanceTo(position);

            // Advance writer
            _pipe.Writer.Advance(memory.Length);
            _pipe.Writer.Commit();
        }
Esempio n. 2
0
        private bool ParsePreface(ReadOnlyBuffer<byte> readableBuffer, out SequencePosition consumed, out SequencePosition examined)
        {
            consumed = readableBuffer.Start;
            examined = readableBuffer.End;

            if (readableBuffer.Length < ClientPreface.Length)
            {
                return false;
            }

            var span = readableBuffer.IsSingleSegment
                ? readableBuffer.First.Span
                : readableBuffer.ToSpan();

            for (var i = 0; i < ClientPreface.Length; i++)
            {
                if (ClientPreface[i] != span[i])
                {
                    throw new Exception("Invalid HTTP/2 connection preface.");
                }
            }

            consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, ClientPreface.Length);
            return true;
        }
Esempio n. 3
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. 4
0
        public void SegmentStartIsConsideredInBoundsCheck()
        {
            // 0               50           100    0             50             100
            // [                ##############] -> [##############                ]
            //                         ^c1            ^c2
            var bufferSegment1 = new BufferSegment();

            bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 50, 99);

            var bufferSegment2 = new BufferSegment();

            bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 50);
            bufferSegment1.SetNext(bufferSegment2);

            var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 50);

            var c1 = readableBuffer.GetPosition(readableBuffer.Start, 25); // segment 1 index 75
            var c2 = readableBuffer.GetPosition(readableBuffer.Start, 55); // segment 2 index 5

            var sliced = readableBuffer.Slice(c1, c2);

            Assert.Equal(30, sliced.Length);
        }
Esempio n. 5
0
        public static SequencePosition?PositionOf <T>(this ReadOnlyBuffer <T> buffer, T value) where T : IEquatable <T>
        {
            SequencePosition position = buffer.Start;
            SequencePosition result   = position;

            while (buffer.TryGet(ref position, out var memory))
            {
                var index = memory.Span.IndexOf(value);
                if (index != -1)
                {
                    return(buffer.GetPosition(result, index));
                }
                result = position;
            }
            return(null);
        }
            private void ReadChunkedData(ReadOnlyBuffer <byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
            {
                var actual = Math.Min(buffer.Length, _inputLength);

                consumed = buffer.GetPosition(buffer.Start, actual);
                examined = consumed;

                Copy(buffer.Slice(0, actual), writableBuffer);

                _inputLength -= actual;
                AddAndCheckConsumedBytes(actual);

                if (_inputLength == 0)
                {
                    _mode = Mode.Suffix;
                }
            }
            protected override bool Read(ReadOnlyBuffer <byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
            {
                if (_inputLength == 0)
                {
                    throw new InvalidOperationException("Attempted to read from completed Content-Length request body.");
                }

                var actual = (int)Math.Min(readableBuffer.Length, _inputLength);

                _inputLength -= actual;

                consumed = readableBuffer.GetPosition(readableBuffer.Start, actual);
                examined = consumed;

                Copy(readableBuffer.Slice(0, actual), writableBuffer);

                return(_inputLength == 0);
            }
Esempio n. 8
0
        public void MovePrefersNextSegment()
        {
            var bufferSegment1 = new BufferSegment();

            bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 49, 99);

            var bufferSegment2 = new BufferSegment();

            bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 0);
            bufferSegment1.SetNext(bufferSegment2);

            var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 0);

            var c1 = readableBuffer.GetPosition(readableBuffer.Start, 50);

            Assert.Equal(0, c1.Index);
            Assert.Equal(bufferSegment2, c1.Segment);
        }
        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);
        }
Esempio n. 10
0
        public static bool TryParseMessage(ReadOnlyBuffer <byte> buffer, out NegotiationMessage negotiationMessage, out SequencePosition consumed, out SequencePosition examined)
        {
            var separator = buffer.PositionOf(TextMessageFormatter.RecordSeparator);

            if (separator == null)
            {
                // Haven't seen the entire negotiate message so bail
                consumed           = buffer.Start;
                examined           = buffer.End;
                negotiationMessage = null;
                return(false);
            }
            else
            {
                consumed = buffer.GetPosition(separator.Value, 1);
                examined = consumed;
            }

            var memory = buffer.IsSingleSegment ? buffer.First : buffer.ToArray();

            return(TryParseMessage(memory.Span, out negotiationMessage));
        }
Esempio n. 11
0
        public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined)
        {
            consumed = buffer.Start;
            examined = buffer.End;

            // Prepare the first span
            var span      = buffer.First.Span;
            var lineIndex = span.IndexOf(ByteLF);

            if (lineIndex >= 0)
            {
                consumed = buffer.GetPosition(consumed, lineIndex + 1);
                span     = span.Slice(0, lineIndex + 1);
            }
            else if (buffer.IsSingleSegment)
            {
                // No request line end
                return(false);
            }
            else if (TryGetNewLine(ref buffer, out var found))
            {
                span     = buffer.Slice(consumed, found).ToSpan();
                consumed = found;
            }
Esempio n. 12
0
        public void GetPositionDoesNotCrossOutsideBuffer()
        {
            var bufferSegment1 = new BufferSegment();

            bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 100);

            var bufferSegment2 = new BufferSegment();

            bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 100);

            var bufferSegment3 = new BufferSegment();

            bufferSegment3.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 0);

            bufferSegment1.SetNext(bufferSegment2);
            bufferSegment2.SetNext(bufferSegment3);

            var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 100);

            var c1 = readableBuffer.GetPosition(readableBuffer.Start, 200);

            Assert.Equal(100, c1.Index);
            Assert.Equal(bufferSegment2, c1.Segment);
        }
Esempio n. 13
0
        public static bool ReadFrame(ReadOnlyBuffer <byte> readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined)
        {
            consumed = readableBuffer.Start;
            examined = readableBuffer.End;

            if (readableBuffer.Length < Http2Frame.HeaderLength)
            {
                return(false);
            }

            var headerSlice = readableBuffer.Slice(0, Http2Frame.HeaderLength);

            headerSlice.CopyTo(frame.Raw);

            if (readableBuffer.Length < Http2Frame.HeaderLength + frame.Length)
            {
                return(false);
            }

            readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload);
            consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length);

            return(true);
        }
        /// <summary>
        /// Searches for a byte in the <see cref="ReadOnlyBuffer"/> and returns a sliced <see cref="ReadOnlyBuffer"/> that
        /// contains all data up to and excluding the byte, and a <see cref="SequencePosition"/> that points to the byte.
        /// </summary>
        /// <param name="b1">The first byte to search for</param>
        /// <param name="slice">A <see cref="ReadOnlyBuffer"/> slice that contains 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, byte b1, out ReadOnlyBuffer <byte> slice, out SequencePosition cursor)
        {
            if (buffer.IsEmpty)
            {
                slice  = default;
                cursor = default;
                return(false);
            }

            var byte0Vector = GetVector(b1);

            var seek = 0;

            foreach (var memory in buffer)
            {
                var currentSpan = memory.Span;
                var found       = false;

                if (Vector.IsHardwareAccelerated)
                {
                    while (currentSpan.Length >= VectorWidth)
                    {
                        var data        = ReadMachineEndian <Vector <byte> >(currentSpan);
                        var byte0Equals = Vector.Equals(data, byte0Vector);

                        if (byte0Equals.Equals(Vector <byte> .Zero))
                        {
                            currentSpan = currentSpan.Slice(VectorWidth);
                            seek       += VectorWidth;
                        }
                        else
                        {
                            var index = FindFirstEqualByte(ref byte0Equals);
                            seek += index;
                            found = true;
                            break;
                        }
                    }
                }

                if (!found)
                {
                    // Slow search
                    for (int i = 0; i < currentSpan.Length; i++)
                    {
                        if (currentSpan[i] == b1)
                        {
                            found = true;
                            break;
                        }
                        seek++;
                    }
                }

                if (found)
                {
                    cursor = buffer.GetPosition(buffer.Start, seek);
                    slice  = buffer.Slice(buffer.Start, cursor);
                    return(true);
                }
            }

            slice  = default;
            cursor = default;
            return(false);
        }
Esempio n. 15
0
 public Position GetPosition(Position origin, long offset)
 => _buffer.GetPosition(origin, offset);
        public ParseResult ParseMessage(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined, out byte[] message)
        {
            consumed = buffer.Start;
            examined = buffer.End;
            message  = null;

            var start = consumed;
            var end   = examined;

            while (buffer.Length > 0)
            {
                if (!(buffer.PositionOf(ByteLF) is SequencePosition lineEnd))
                {
                    // For the case of  data: Foo\r\n\r\<Anytine except \n>
                    if (_internalParserState == InternalParseState.ReadEndOfMessage)
                    {
                        if (ConvertBufferToSpan(buffer.Slice(start, buffer.End)).Length > 1)
                        {
                            throw new FormatException("Expected a \\r\\n frame ending");
                        }
                    }

                    // Partial message. We need to read more.
                    return(ParseResult.Incomplete);
                }

                lineEnd = buffer.GetPosition(lineEnd, 1);
                var line = ConvertBufferToSpan(buffer.Slice(start, lineEnd));
                buffer = buffer.Slice(line.Length);

                if (line.Length <= 1)
                {
                    throw new FormatException("There was an error in the frame format");
                }

                // Skip comments
                if (line[0] == ByteColon)
                {
                    start    = lineEnd;
                    consumed = lineEnd;
                    continue;
                }

                if (IsMessageEnd(line))
                {
                    _internalParserState = InternalParseState.ReadEndOfMessage;
                }

                // To ensure that the \n was preceded by a \r
                // since messages can't contain \n.
                // data: foo\n\bar should be encoded as
                // data: foo\r\n
                // data: bar\r\n
                else if (line[line.Length - _sseLineEnding.Length] != ByteCR)
                {
                    throw new FormatException("Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'");
                }
                else
                {
                    EnsureStartsWithDataPrefix(line);
                }

                var payload = Array.Empty <byte>();
                switch (_internalParserState)
                {
                case InternalParseState.ReadMessagePayload:
                    EnsureStartsWithDataPrefix(line);

                    // Slice away the 'data: '
                    var payloadLength = line.Length - (_dataPrefix.Length + _sseLineEnding.Length);
                    var newData       = line.Slice(_dataPrefix.Length, payloadLength).ToArray();
                    _data.Add(newData);

                    start    = lineEnd;
                    consumed = lineEnd;
                    break;

                case InternalParseState.ReadEndOfMessage:
                    if (_data.Count == 1)
                    {
                        payload = _data[0];
                    }
                    else if (_data.Count > 1)
                    {
                        // Find the final size of the payload
                        var payloadSize = 0;
                        foreach (var dataLine in _data)
                        {
                            payloadSize += dataLine.Length;
                        }

                        payloadSize += _newLine.Length * _data.Count;

                        // Allocate space in the payload buffer for the data and the new lines.
                        // Subtract newLine length because we don't want a trailing newline.
                        payload = new byte[payloadSize - _newLine.Length];

                        var offset = 0;
                        foreach (var dataLine in _data)
                        {
                            dataLine.CopyTo(payload, offset);
                            offset += dataLine.Length;
                            if (offset < payload.Length)
                            {
                                _newLine.CopyTo(payload, offset);
                                offset += _newLine.Length;
                            }
                        }
                    }

                    message  = payload;
                    consumed = lineEnd;
                    examined = consumed;
                    return(ParseResult.Completed);
                }

                if (buffer.Length > 0 && buffer.First.Span[0] == ByteCR)
                {
                    _internalParserState = InternalParseState.ReadEndOfMessage;
                }
            }
            return(ParseResult.Incomplete);
        }
Esempio n. 17
0
 public SequencePosition GetPosition(SequencePosition origin, long offset)
 => _buffer.GetPosition(origin, offset);