/// <summary>
        /// Searches for 2 sequential bytes in the <see cref="ReadOnlyBuffer"/> and returns a sliced <see cref="ReadOnlyBuffer"/> that
        /// contains all data up to and excluding the first byte, and a <see cref="SequencePosition"/> that points to the second byte.
        /// </summary>
        /// <param name="b1">The first byte to search for</param>
        /// <param name="b2">The second 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 unsafe bool TrySliceTo(this ReadOnlyBuffer <byte> buffer, byte b1, byte b2, out ReadOnlyBuffer <byte> slice, out SequencePosition cursor)
        {
            // use address of ushort rather than stackalloc as the inliner won't inline functions with stackalloc
            ushort twoBytes;
            byte * byteArray = (byte *)&twoBytes;

            byteArray[0] = b1;
            byteArray[1] = b2;
            return(buffer.TrySliceTo(new Span <byte>(byteArray, 2), out slice, out cursor));
        }
        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));
        }
Beispiel #3
0
        public bool TryDecode(ref ReadOnlyBuffer input, out Line frame)
        {
            if (input.TrySliceTo((byte)'\r', (byte)'\n', out ReadOnlyBuffer slice, out Position cursor))
            {
                frame = new Line {
                    Data = slice.GetUtf8Span()
                };
                input = input.Slice(cursor).Slice(1);
                return(true);
            }

            frame = null;
            return(false);
        }
Beispiel #4
0
        private unsafe void TestIndexOfWorksForAllLocations(ref ReadOnlyBuffer <byte> readBuffer, byte emptyValue)
        {
            byte huntValue = (byte)~emptyValue;

            var handles = new List <MemoryHandle>();
            // we're going to fully index the final locations of the buffer, so that we
            // can mutate etc in constant time
            var addresses = BuildPointerIndex(ref readBuffer, handles);
            var found     = readBuffer.TrySliceTo(huntValue, out ReadOnlyBuffer <byte> slice, out Position cursor);

            Assert.False(found);

            // correctness test all values
            for (int i = 0; i < readBuffer.Length; i++)
            {
                *addresses[i] = huntValue;
                found = readBuffer.TrySliceTo(huntValue, out slice, out cursor);
                *addresses[i] = emptyValue;

                Assert.True(found);
                var remaining = readBuffer.Slice(cursor);
                var handle    = remaining.First.Retain(pin: true);
                Assert.True(handle.Pointer != null);
                if (i % BlockSize == 0)
                {
                    Assert.True((byte *)handle.Pointer == addresses[i]);
                }
                handle.Dispose();
            }

            // free up memory handles
            foreach (var handle in handles)
            {
                handle.Dispose();
            }
            handles.Clear();
        }
Beispiel #5
0
        public ParseResult ParseRequest(ReadOnlyBuffer buffer, out Position consumed, out Position examined)
        {
            consumed = buffer.Start;
            examined = buffer.Start;

            if (_state == ParsingState.StartLine)
            {
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out ReadOnlyBuffer startLine, out Position delim))
                {
                    return(ParseResult.Incomplete);
                }

                // Move the buffer to the rest
                buffer = buffer.Slice(delim).Slice(2);

                if (!startLine.TrySliceTo((byte)' ', out ReadOnlyBuffer method, out delim))
                {
                    return(ParseResult.BadRequest);
                }

                _method = method.ToArray();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                if (!startLine.TrySliceTo((byte)' ', out ReadOnlyBuffer path, out delim))
                {
                    return(ParseResult.BadRequest);
                }

                _path = path.ToArray();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                var httpVersion = startLine;
                if (httpVersion.IsEmpty)
                {
                    return(ParseResult.BadRequest);
                }

                _httpVersion = httpVersion.ToArray();

                _state   = ParsingState.Headers;
                consumed = buffer.Start;
                examined = buffer.Start;
            }

            // Parse headers
            // key: value\r\n

            while (!buffer.IsEmpty)
            {
                var headerValue = default(ReadOnlyBuffer);
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out ReadOnlyBuffer headerPair, out Position delim))
                {
                    return(ParseResult.Incomplete);
                }

                buffer = buffer.Slice(delim).Slice(2);

                consumed = buffer.Start;
                examined = buffer.Start;

                // End of headers
                if (headerPair.IsEmpty)
                {
                    return(ParseResult.Complete);
                }

                // :
                if (!headerPair.TrySliceTo((byte)':', out ReadOnlyBuffer headerName, out delim))
                {
                    return(ParseResult.BadRequest);
                }

                headerName = headerName.TrimStart();
                headerPair = headerPair.Slice(delim).Slice(1);

                headerValue = headerPair.TrimStart();
                RequestHeaders.SetHeader(ref headerName, ref headerValue);
            }

            return(ParseResult.Incomplete);
        }