private bool ParsePreface(ReadOnlyBuffer readableBuffer, out Position consumed, out Position examined)
        {
            consumed = readableBuffer.Start;
            examined = readableBuffer.End;

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

            var span = readableBuffer.IsSingleSpan
                ? 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.Move(readableBuffer.Start, ClientPreface.Length);
            return(true);
        }
Esempio n. 2
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(new Position(bufferSegment1, 0), new Position(bufferSegment2, 50));

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

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

            Assert.Equal(30, sliced.Length);
        }
Esempio n. 3
0
        private static void FindAllNewLines(ReadOnlyBuffer 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);
            }
        }
            private void ReadChunkedData(ReadOnlyBuffer buffer, WritableBuffer writableBuffer, out Position consumed, out Position examined)
            {
                var actual = Math.Min(buffer.Length, _inputLength);

                consumed = buffer.Move(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 readableBuffer, WritableBuffer writableBuffer, out Position consumed, out Position 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.Move(readableBuffer.Start, actual);
                examined = consumed;

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

                return(_inputLength == 0);
            }
Esempio n. 6
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(new Position(bufferSegment1, 0), new Position(bufferSegment2, 0));

            var c1 = readableBuffer.Move(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(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.Move(buffer1.Start, headerLine.Length - 1), consumed);
            Assert.Equal(buffer1.End, examined);
            Assert.Equal(headerLine.Length - 1, consumedBytes);

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

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

            Assert.Equal(buffer2.End, consumed);
            Assert.Equal(buffer2.End, examined);
            Assert.Equal(2, consumedBytes);
        }
Esempio n. 8
0
        public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer buffer, out Position consumed, out Position 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.Move(consumed, lineIndex + 1);
                span     = span.Slice(0, lineIndex + 1);
            }
            else if (buffer.IsSingleSpan)
            {
                // No request line end
                return(false);
            }
            else if (TryGetNewLine(ref buffer, out var found))
            {
                span     = buffer.Slice(consumed, found).ToSpan();
                consumed = found;
            }
        public static bool ReadFrame(ReadOnlyBuffer readableBuffer, Http2Frame frame, out Position consumed, out Position 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.Move(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length);

            return(true);
        }
        public ParseResult ParseMessage(ReadOnlyBuffer buffer, out Position consumed, out Position examined, out byte[] message)
        {
            consumed = buffer.Start;
            examined = buffer.End;
            message  = null;

            var start = consumed;
            var end   = examined;

            while (buffer.Length > 0)
            {
                if (ReadOnlyBuffer.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);
        }
        /// <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="Position"/> 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="Position"/> 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 buffer, byte b1, out ReadOnlyBuffer slice, out Position 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.Move(buffer.Start, seek);
                    slice  = buffer.Slice(buffer.Start, cursor);
                    return(true);
                }
            }

            slice  = default;
            cursor = default;
            return(false);
        }