Пример #1
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadOnlyBuffer"/>, beginning at 'start', ending at 'end' (inclusive).
        /// </summary>
        /// <param name="start">The starting (inclusive) <see cref="Position"/> at which to begin this slice.</param>
        /// <param name="end">The ending (inclusive) <see cref="Position"/> of the slice</param>
        public ReadOnlyBuffer Slice(Position start, Position end)
        {
            ReadCursorOperations.BoundsCheck(BufferEnd, end);
            ReadCursorOperations.BoundsCheck(end, start);

            return(new ReadOnlyBuffer(start, end));
        }
Пример #2
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadOnlyBuffer"/>, beginning at 'start', and is at most length bytes
        /// </summary>
        /// <param name="start">The index at which to begin this slice.</param>
        /// <param name="length">The length of the slice</param>
        public ReadOnlyBuffer Slice(long start, long length)
        {
            var begin = ReadCursorOperations.Seek(BufferStart, BufferEnd, start, false);
            var end   = ReadCursorOperations.Seek(begin, BufferEnd, length, false);

            return(new ReadOnlyBuffer(begin, end));
        }
Пример #3
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadOnlyBuffer"/>, beginning at 'start', ending at 'end' (inclusive).
        /// </summary>
        /// <param name="start">The index at which to begin this slice.</param>
        /// <param name="end">The end (inclusive) of the slice</param>
        public ReadOnlyBuffer Slice(long start, Position end)
        {
            ReadCursorOperations.BoundsCheck(BufferEnd, end);
            var begin = ReadCursorOperations.Seek(BufferStart, end, start);

            return(new ReadOnlyBuffer(begin, end));
        }
Пример #4
0
            // This test verifies that optimization for known cursors works and
            // avoids additional walk but it's only valid for multi segmented buffers
            public void ReadCursorSeekDoesNotCheckEndIfTrustingEnd()
            {
                var buffer  = Factory.CreateOfSize(3);
                var buffer2 = Factory.CreateOfSize(3);

                ReadCursorOperations.Seek(buffer.Start, buffer2.End, 2, false);
            }
Пример #5
0
        public void MemorySeek(string raw, string search, char expectResult, int expectIndex)
        {
            var        cursors = BufferUtilities.CreateBuffer(raw);
            ReadCursor start   = cursors.Start;
            ReadCursor end     = cursors.End;
            ReadCursor result  = default;

            var searchFor = search.ToCharArray();

            int found = -1;

            if (searchFor.Length == 1)
            {
                found = ReadCursorOperations.Seek(start, end, out result, (byte)searchFor[0]);
            }
            else if (searchFor.Length == 2)
            {
                found = ReadCursorOperations.Seek(start, end, out result, (byte)searchFor[0], (byte)searchFor[1]);
            }
            else if (searchFor.Length == 3)
            {
                found = ReadCursorOperations.Seek(start, end, out result, (byte)searchFor[0], (byte)searchFor[1], (byte)searchFor[2]);
            }
            else
            {
                Assert.False(true, "Invalid test sample.");
            }

            Assert.Equal(expectResult, found);
            Assert.Equal(expectIndex, result.Index - start.Index);
        }
Пример #6
0
        public void ReadCursorSeekChecksEndIfNotTrustingEnd()
        {
            var buffer  = Factory.CreateOfSize(3);
            var buffer2 = Factory.CreateOfSize(3);

            Assert.Throws <InvalidOperationException>(() => ReadCursorOperations.Seek(buffer.Start, buffer2.End, 2, true));
        }
Пример #7
0
        public void TestSeekByteLimitAcrossBlocks(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue)
        {
            // Arrange

            var input1 = input.Substring(0, input.Length / 2);
            var input2 = input.Substring(input.Length / 2);
            var buffer = BufferUtilities.CreateBuffer(input1, string.Empty, input2);
            var block1 = buffer.Start;
            var block2 = buffer.End;
            // Act
            ReadCursor result;

            var end           = limit > input.Length ? buffer.End : buffer.Slice(0, limit).End;
            var returnValue   = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek);
            var returnValue_1 = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek);
            var returnValue_2 = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek, (byte)seek);

            // Assert
            Assert.Equal(expectedReturnValue, returnValue);
            Assert.Equal(expectedReturnValue, returnValue_1);
            Assert.Equal(expectedReturnValue, returnValue_2);

            if (expectedReturnValue != -1)
            {
                var seekCharIndex    = input.IndexOf(seek);
                var expectedEndBlock = limit <= input.Length / 2 ?
                                       block1.Segment :
                                       (seekCharIndex != -1 && seekCharIndex < input.Length / 2 ? block1.Segment : block2.Segment);

                Assert.Same(expectedEndBlock, result.Segment);

                var expectedEndIndex = expectedEndBlock.Start + (expectedEndBlock == block1.Segment ? input1.IndexOf(seek) : input2.IndexOf(seek));
                Assert.Equal(expectedEndIndex, result.Index);
            }
        }
Пример #8
0
        public void MemorySeek(string raw, string search, char expectResult, int expectIndex)
        {
            var        cursors = Factory.CreateWithContent(raw);
            ReadCursor start   = cursors.Start;
            ReadCursor end     = cursors.End;
            ReadCursor result  = default;

            var searchFor = search.ToCharArray();

            int found = -1;

            if (searchFor.Length == 1)
            {
                found = ReadCursorOperations.Seek(start, end, out result, (byte)searchFor[0]);
            }
            else if (searchFor.Length == 2)
            {
                found = ReadCursorOperations.Seek(start, end, out result, (byte)searchFor[0], (byte)searchFor[1]);
            }
            else if (searchFor.Length == 3)
            {
                found = ReadCursorOperations.Seek(start, end, out result, (byte)searchFor[0], (byte)searchFor[1], (byte)searchFor[2]);
            }
            else
            {
                Assert.False(true, "Invalid test sample.");
            }

            Assert.Equal(expectResult, found);
            Assert.Equal(cursors.Slice(result).ToArray(), Encoding.ASCII.GetBytes(raw.Substring(expectIndex)));
        }
Пример #9
0
 public Position Move(Position cursor, long count)
 {
     if (count < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(count));
     }
     return(ReadCursorOperations.Seek(cursor, BufferEnd, count, false));
 }
Пример #10
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadOnlyBuffer"/>, beginning at 'start', and is at most length bytes
        /// </summary>
        /// <param name="start">The starting (inclusive) <see cref="Position"/> at which to begin this slice.</param>
        /// <param name="length">The length of the slice</param>
        public ReadOnlyBuffer Slice(Position start, long length)
        {
            ReadCursorOperations.BoundsCheck(BufferEnd, start);

            var end = ReadCursorOperations.Seek(start, BufferEnd, length, false);

            return(new ReadOnlyBuffer(start, end));
        }
Пример #11
0
        public void TestSeekIteratorLimitWithinSameBlock(string input, char seek, char limitAfter, int expectedReturnValue)
        {
            // Arrange
            var afterSeek = (byte)'B';

            var buffer = BufferUtilities.CreateBuffer(input);

            var start   = buffer.Start;
            var scan1   = buffer.Start;
            var veryEnd = buffer.End;
            var scan2_1 = scan1;
            var scan2_2 = scan1;
            var scan3_1 = scan1;
            var scan3_2 = scan1;
            var scan3_3 = scan1;
            var end     = buffer.End;

            // Act
            var endReturnValue = ReadCursorOperations.Seek(start, veryEnd, out end, (byte)limitAfter);

            end = buffer.Slice(end, 1).End;
            var returnValue1   = ReadCursorOperations.Seek(start, end, out scan1, (byte)seek);
            var returnValue2_1 = ReadCursorOperations.Seek(start, end, out scan2_1, (byte)seek, afterSeek);
            var returnValue2_2 = ReadCursorOperations.Seek(start, end, out scan2_2, afterSeek, (byte)seek);
            var returnValue3_1 = ReadCursorOperations.Seek(start, end, out scan3_1, (byte)seek, afterSeek, afterSeek);
            var returnValue3_2 = ReadCursorOperations.Seek(start, end, out scan3_2, afterSeek, (byte)seek, afterSeek);
            var returnValue3_3 = ReadCursorOperations.Seek(start, end, out scan3_3, afterSeek, afterSeek, (byte)seek);


            // Assert
            Assert.Equal(input.Contains(limitAfter) ? limitAfter : -1, endReturnValue);
            Assert.Equal(expectedReturnValue, returnValue1);
            Assert.Equal(expectedReturnValue, returnValue2_1);
            Assert.Equal(expectedReturnValue, returnValue2_2);
            Assert.Equal(expectedReturnValue, returnValue3_1);
            Assert.Equal(expectedReturnValue, returnValue3_2);
            Assert.Equal(expectedReturnValue, returnValue3_3);

            if (expectedReturnValue != -1)
            {
                var block = start.Segment;
                Assert.Same(block, scan1.Segment);
                Assert.Same(block, scan2_1.Segment);
                Assert.Same(block, scan2_2.Segment);
                Assert.Same(block, scan3_1.Segment);
                Assert.Same(block, scan3_2.Segment);
                Assert.Same(block, scan3_3.Segment);

                var expectedEndIndex = expectedReturnValue != -1 ? start.Index + input.IndexOf(seek) : end.Index;
                Assert.Equal(expectedEndIndex, scan1.Index);
                Assert.Equal(expectedEndIndex, scan2_1.Index);
                Assert.Equal(expectedEndIndex, scan2_2.Index);
                Assert.Equal(expectedEndIndex, scan3_1.Index);
                Assert.Equal(expectedEndIndex, scan3_2.Index);
                Assert.Equal(expectedEndIndex, scan3_3.Index);
            }
        }
Пример #12
0
        public bool TryGet(ref Position cursor, out ReadOnlyMemory <byte> data, bool advance = true)
        {
            var result = ReadCursorOperations.TryGetBuffer(cursor, End, out data, out var next);

            if (advance)
            {
                cursor = next;
            }

            return(result);
        }
Пример #13
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadOnlyBuffer"/>, beginning at 'start', ending at the existing <see cref="ReadOnlyBuffer"/>'s end.
        /// </summary>
        /// <param name="start">The start index at which to begin this slice.</param>
        public ReadOnlyBuffer Slice(long start)
        {
            if (start == 0)
            {
                return(this);
            }

            var begin = ReadCursorOperations.Seek(BufferStart, BufferEnd, start, false);

            return(new ReadOnlyBuffer(begin, BufferEnd));
        }
Пример #14
0
        private static Span <byte> TryGetNewLineSpan(ref ReadableBuffer buffer, out ReadCursor end)
        {
            var start = buffer.Start;

            if (ReadCursorOperations.Seek(start, buffer.End, out end, ByteLF) != -1)
            {
                // Move 1 byte past the \n
                end = buffer.Move(end, 1);
                return(buffer.Slice(start, end).ToSpan());
            }

            return(default);
Пример #15
0
        public void TestSeekIteratorLimitWithinSameBlock(string input, char seek, char limitAfter, int expectedReturnValue)
        {
            // Arrange
            var afterSeek = (byte)'B';

            var buffer = Factory.CreateWithContent(input);

            var start   = buffer.Start;
            var scan1   = buffer.Start;
            var veryEnd = buffer.End;
            var scan2_1 = scan1;
            var scan2_2 = scan1;
            var scan3_1 = scan1;
            var scan3_2 = scan1;
            var scan3_3 = scan1;
            var end     = buffer.End;

            // Act
            var endReturnValue = ReadCursorOperations.Seek(start, veryEnd, out end, (byte)limitAfter);

            if (endReturnValue != -1)
            {
                end = buffer.Slice(end, 1).End;
            }
            var returnValue1   = ReadCursorOperations.Seek(start, end, out scan1, (byte)seek);
            var returnValue2_1 = ReadCursorOperations.Seek(start, end, out scan2_1, (byte)seek, afterSeek);
            var returnValue2_2 = ReadCursorOperations.Seek(start, end, out scan2_2, afterSeek, (byte)seek);
            var returnValue3_1 = ReadCursorOperations.Seek(start, end, out scan3_1, (byte)seek, afterSeek, afterSeek);
            var returnValue3_2 = ReadCursorOperations.Seek(start, end, out scan3_2, afterSeek, (byte)seek, afterSeek);
            var returnValue3_3 = ReadCursorOperations.Seek(start, end, out scan3_3, afterSeek, afterSeek, (byte)seek);


            // Assert
            Assert.Equal(input.Contains(limitAfter) ? limitAfter : -1, endReturnValue);
            Assert.Equal(expectedReturnValue, returnValue1);
            Assert.Equal(expectedReturnValue, returnValue2_1);
            Assert.Equal(expectedReturnValue, returnValue2_2);
            Assert.Equal(expectedReturnValue, returnValue3_1);
            Assert.Equal(expectedReturnValue, returnValue3_2);
            Assert.Equal(expectedReturnValue, returnValue3_3);

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

                Assert.Equal(buffer.Slice(scan1).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan2_1).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan2_2).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan3_1).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan3_2).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
                Assert.Equal(buffer.Slice(scan3_3).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)));
            }
        }
Пример #16
0
            private void ParseExtension(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
            {
                // Chunk-extensions not currently parsed
                // Just drain the data
                consumed = buffer.Start;
                examined = buffer.Start;

                do
                {
                    ReadCursor extensionCursor;
                    if (ReadCursorOperations.Seek(buffer.Start, buffer.End, out extensionCursor, ByteCR) == -1)
                    {
                        // End marker not found yet
                        consumed = buffer.End;
                        examined = buffer.End;
                        AddAndCheckConsumedBytes(buffer.Length);
                        return;
                    }
                    ;

                    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);
            }
Пример #17
0
        private static bool TryGetNewLineSpan(ref ReadableBuffer buffer, ref Span <byte> span, out ReadCursor end)
        {
            var start = buffer.Start;

            if (ReadCursorOperations.Seek(start, buffer.End, out end, ByteLF) != -1)
            {
                // Move 1 byte past the \n
                end  = buffer.Move(end, 1);
                span = buffer.Slice(start, end).ToSpan();
                return(true);
            }
            return(false);
        }
        private static void FindAllNewLines(ReadableBuffer buffer)
        {
            var start = buffer.Start;
            var end   = buffer.End;

            while (true)
            {
                if (ReadCursorOperations.Seek(start, end, out var found, (byte)'\n') == -1)
                {
                    break;
                }

                start = buffer.Move(found, 1);
            }
        }
Пример #19
0
        private static void FindAllNewLinesReadableBufferReader(ReadableBuffer buffer)
        {
            var reader = new ReadableBufferReader(buffer);
            var end    = buffer.End;

            while (!reader.End)
            {
                var span = reader.Span;

                // Trim the start if we have an index
                if (reader.Index > 0)
                {
                    span = span.Slice(reader.Index);
                }

                while (span.Length > 0)
                {
                    var length = span.IndexOf((byte)'\n');
                    var skip   = length;

                    if (length == -1)
                    {
                        var current = reader.Cursor;

                        if (ReadCursorOperations.Seek(current, end, out var found, (byte)'\n') == -1)
                        {
                            // We're done
                            return;
                        }

                        length = span.Length;
                        skip   = (int)buffer.Slice(current, found).Length + 1;
                    }
                    else
                    {
                        length += 1;
                        skip    = length;
                    }

                    span = span.Slice(length);
                    reader.Skip(skip);
                }
            }
        }
Пример #20
0
        public void TestSeekByteLimitWithinSameBlock(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue)
        {
            // Arrange
            var buffer = Factory.CreateWithContent(input);

            // Act
            var end           = limit > input.Length ? buffer.End : buffer.Slice(0, limit).End;
            var returnValue   = ReadCursorOperations.Seek(buffer.Start, end, out ReadCursor result, (byte)seek);
            var returnValue_1 = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek);
            var returnValue_2 = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek, (byte)seek);

            // Assert
            Assert.Equal(expectedReturnValue, returnValue);
            Assert.Equal(expectedReturnValue, returnValue_1);
            Assert.Equal(expectedReturnValue, returnValue_2);

            if (expectedReturnValue != -1)
            {
                Assert.Equal(buffer.Slice(result).ToArray(), Encoding.ASCII.GetBytes(input.Substring(expectedBytesScanned - 1)));
            }
        }
Пример #21
0
        public void TestSeekByteLimitWithinSameBlock(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue)
        {
            // Arrange
            var buffer = BufferUtilities.CreateBuffer(input);

            // Act
            var end           = limit > input.Length ? buffer.End : buffer.Slice(0, limit).End;
            var returnValue   = ReadCursorOperations.Seek(buffer.Start, end, out ReadCursor result, (byte)seek);
            var returnValue_1 = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek);
            var returnValue_2 = ReadCursorOperations.Seek(buffer.Start, end, out result, (byte)seek, (byte)seek, (byte)seek);

            // Assert
            Assert.Equal(expectedReturnValue, returnValue);
            Assert.Equal(expectedReturnValue, returnValue_1);
            Assert.Equal(expectedReturnValue, returnValue_2);

            if (expectedReturnValue != -1)
            {
                Assert.Same(buffer.Start.Segment, result.Segment);
                Assert.Equal(result.Segment.Start + input.IndexOf(seek), result.Index);
            }
        }
        public ParseResult ParseMessage(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out byte[] message)
        {
            consumed = buffer.Start;
            examined = buffer.End;
            message  = null;

            var start = consumed;
            var end   = examined;

            while (buffer.Length > 0)
            {
                if (ReadCursorOperations.Seek(start, end, out var lineEnd, ByteLF) == -1)
                {
                    // 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.Move(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);
        }
Пример #23
0
        public unsafe bool ParseHeaders <T>(T handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes) where T : IHttpHeadersHandler
        {
            consumed      = buffer.Start;
            examined      = buffer.End;
            consumedBytes = 0;

            var bufferEnd = buffer.End;

            var reader = new ReadableBufferReader(buffer);
            var start  = default(ReadableBufferReader);
            var done   = false;

            try
            {
                while (!reader.End)
                {
                    var span      = reader.Span;
                    var remaining = span.Length - reader.Index;

                    fixed(byte *pBuffer = &span.DangerousGetPinnableReference())
                    {
                        while (remaining > 0)
                        {
                            var index = reader.Index;
                            int ch1;
                            int ch2;

                            // Fast path, we're still looking at the same span
                            if (remaining >= 2)
                            {
                                ch1 = pBuffer[index];
                                ch2 = pBuffer[index + 1];
                            }
                            else
                            {
                                // Store the reader before we look ahead 2 bytes (probably straddling
                                // spans)
                                start = reader;

                                // Possibly split across spans
                                ch1 = reader.Take();
                                ch2 = reader.Take();
                            }

                            if (ch1 == ByteCR)
                            {
                                // Check for final CRLF.
                                if (ch2 == -1)
                                {
                                    // Reset the reader so we don't consume anything
                                    reader = start;
                                    return(false);
                                }
                                else if (ch2 == ByteLF)
                                {
                                    // If we got 2 bytes from the span directly so skip ahead 2 so that
                                    // the reader's state matches what we expect
                                    if (index == reader.Index)
                                    {
                                        reader.Skip(2);
                                    }

                                    done = true;
                                    return(true);
                                }

                                // Headers don't end in CRLF line.
                                RejectRequest(RequestRejectionReason.InvalidRequestHeadersNoCRLF);
                            }

                            // We moved the reader so look ahead 2 bytes so reset both the reader
                            // and the index
                            if (index != reader.Index)
                            {
                                reader = start;
                                index  = reader.Index;
                            }

                            var endIndex = new ReadOnlySpan <byte>(pBuffer + index, remaining).IndexOf(ByteLF);
                            var length   = 0;

                            if (endIndex != -1)
                            {
                                length = endIndex + 1;
                                var pHeader = pBuffer + index;

                                TakeSingleHeader(pHeader, length, handler);
                            }
                            else
                            {
                                var current = reader.Cursor;

                                // Split buffers
                                if (ReadCursorOperations.Seek(current, bufferEnd, out var lineEnd, ByteLF) == -1)
                                {
                                    // Not there
                                    return(false);
                                }

                                // Make sure LF is included in lineEnd
                                lineEnd = buffer.Move(lineEnd, 1);
                                var headerSpan = buffer.Slice(current, lineEnd).ToSpan();
                                length = headerSpan.Length;

                                fixed(byte *pHeader = &headerSpan.DangerousGetPinnableReference())
                                {
                                    TakeSingleHeader(pHeader, length, handler);
                                }

                                // We're going to the next span after this since we know we crossed spans here
                                // so mark the remaining as equal to the headerSpan so that we end up at 0
                                // on the next iteration
                                remaining = length;
                            }

                            // Skip the reader forward past the header line
                            reader.Skip(length);
                            remaining -= length;
                        }
                    }
                }

                return(false);
            }
            finally
            {
                consumed      = reader.Cursor;
                consumedBytes = reader.ConsumedBytes;

                if (done)
                {
                    examined = consumed;
                }
            }
        }
Пример #24
0
        public void TestSeekIteratorLimitAcrossBlocks(string input, char seek, char limitAt, int expectedReturnValue)
        {
            // Arrange
            var afterSeek = (byte)'B';

            var input1 = input.Substring(0, input.Length / 2);
            var input2 = input.Substring(input.Length / 2);
            var buffer = BufferUtilities.CreateBuffer(input1, string.Empty, input2);

            var start   = buffer.Start;
            var scan1   = buffer.Start;
            var veryEnd = buffer.End;
            var scan2_1 = scan1;
            var scan2_2 = scan1;
            var scan3_1 = scan1;
            var scan3_2 = scan1;
            var scan3_3 = scan1;
            var end     = buffer.End;

            // Act
            var endReturnValue = ReadCursorOperations.Seek(start, veryEnd, out end, (byte)limitAt);

            end = buffer.Move(end, 1);
            var returnValue1   = ReadCursorOperations.Seek(start, end, out scan1, (byte)seek);
            var returnValue2_1 = ReadCursorOperations.Seek(start, end, out scan2_1, (byte)seek, afterSeek);
            var returnValue2_2 = ReadCursorOperations.Seek(start, end, out scan2_2, afterSeek, (byte)seek);
            var returnValue3_1 = ReadCursorOperations.Seek(start, end, out scan3_1, (byte)seek, afterSeek, afterSeek);
            var returnValue3_2 = ReadCursorOperations.Seek(start, end, out scan3_2, afterSeek, (byte)seek, afterSeek);
            var returnValue3_3 = ReadCursorOperations.Seek(start, end, out scan3_3, afterSeek, afterSeek, (byte)seek);

            // Assert
            Assert.Equal(input.Contains(limitAt) ? limitAt : -1, endReturnValue);
            Assert.Equal(expectedReturnValue, returnValue1);
            Assert.Equal(expectedReturnValue, returnValue2_1);
            Assert.Equal(expectedReturnValue, returnValue2_2);
            Assert.Equal(expectedReturnValue, returnValue3_1);
            Assert.Equal(expectedReturnValue, returnValue3_2);
            Assert.Equal(expectedReturnValue, returnValue3_3);

            if (expectedReturnValue != -1)
            {
                var seekCharIndex    = input.IndexOf(seek);
                var limitAtIndex     = input.IndexOf(limitAt);
                var expectedEndBlock = seekCharIndex != -1 && seekCharIndex < input.Length / 2 ?
                                       start.Segment :
                                       (limitAtIndex != -1 && limitAtIndex < input.Length / 2 ? start.Segment : end.Segment);
                Assert.Same(expectedEndBlock, scan1.Segment);
                Assert.Same(expectedEndBlock, scan2_1.Segment);
                Assert.Same(expectedEndBlock, scan2_2.Segment);
                Assert.Same(expectedEndBlock, scan3_1.Segment);
                Assert.Same(expectedEndBlock, scan3_2.Segment);
                Assert.Same(expectedEndBlock, scan3_3.Segment);

                var expectedEndIndex = expectedReturnValue != -1 ?
                                       expectedEndBlock.Start + (expectedEndBlock == start.Segment ? input1.IndexOf(seek) : input2.IndexOf(seek)) :
                                       end.Index;
                Assert.Equal(expectedEndIndex, scan1.Index);
                Assert.Equal(expectedEndIndex, scan2_1.Index);
                Assert.Equal(expectedEndIndex, scan2_2.Index);
                Assert.Equal(expectedEndIndex, scan3_1.Index);
                Assert.Equal(expectedEndIndex, scan3_2.Index);
                Assert.Equal(expectedEndIndex, scan3_3.Index);
            }
        }