Пример #1
0
        public void Implementation()
        {
            var path = Input;
            Span <PathSegment> segments = stackalloc PathSegment[MaxCount];

            FastPathTokenizer.Tokenize(path, segments);
        }
Пример #2
0
        public sealed override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (feature == null)
            {
                throw new ArgumentNullException(nameof(feature));
            }

            // The sequence of actions we take is optimized to avoid doing expensive work
            // like creating substrings, creating route value dictionaries, and calling
            // into policies like versioning.
            var path = httpContext.Request.Path.Value;

            // First tokenize the path into series of segments.
            Span <PathSegment> buffer = stackalloc PathSegment[_maxSegmentCount];
            var count    = FastPathTokenizer.Tokenize(path, buffer);
            var segments = buffer.Slice(0, count);

            // FindCandidateSet will process the DFA and return a candidate set. This does
            // some preliminary matching of the URL (mostly the literal segments).
            var candidates = FindCandidateSet(httpContext, path, segments);

            if (candidates.Length == 0)
            {
                return(Task.CompletedTask);
            }

            // At this point we have a candidate set, defined as a list of endpoints in
            // priority order.
            //
            // We don't yet know that any candidate can be considered a match, because
            // we haven't processed things like route constraints and complex segments.
            //
            // Now we'll iterate each endpoint to capture route values, process constraints,
            // and process complex segments.

            // `candidates` has all of our internal state that we use to process the
            // set of endpoints before we call the EndpointSelector.
            //
            // `candidateSet` is the mutable state that we pass to the EndpointSelector.
            var candidateSet = new CandidateSet(candidates);

            for (var i = 0; i < candidates.Length; i++)
            {
                // PERF: using ref here to avoid copying around big structs.
                //
                // Reminder!
                // candidate: readonly data about the endpoint and how to match
                // state: mutable storarge for our processing
                ref var candidate = ref candidates[i];
                ref var state     = ref candidateSet[i];
Пример #3
0
        public void Tokenize_RootPath()
        {
            // Arrange
            Span <PathSegment> segments = stackalloc PathSegment[1];

            // Act
            var count = FastPathTokenizer.Tokenize("/", segments);

            // Assert
            Assert.Equal(0, count);
        }
Пример #4
0
        private (HttpContext context, string path, int count) CreateMatchingContext(string requestPath, PathSegment[] buffer)
        {
            var context = CreateContext();

            context.Request.Path = requestPath;

            // First tokenize the path into series of segments.
            var count = FastPathTokenizer.Tokenize(requestPath, buffer);

            return(context, requestPath, count);
        }
Пример #5
0
        public void Tokenize_SingleSegment()
        {
            // Arrange
            Span <PathSegment> segments = stackalloc PathSegment[1];

            // Act
            var count = FastPathTokenizer.Tokenize("/abc", segments);

            // Assert
            Assert.Equal(1, count);
            Assert.Equal(new PathSegment(1, 3), segments[0]);
        }
Пример #6
0
        public void Dfa()
        {
            var httpContext             = Requests[0];
            var path                    = httpContext.Request.Path.Value;
            Span <PathSegment> segments = stackalloc PathSegment[SegmentCount];
            var count                   = FastPathTokenizer.Tokenize(path, segments);

            var candidates = _dfa.FindCandidateSet(httpContext, path, segments.Slice(0, count));

            var endpoint = candidates[0].Endpoint;

            Validate(Requests[0], Endpoints[0], endpoint);
        }
Пример #7
0
        public void Tokenize_LongerSegments()
        {
            // Arrange
            Span <PathSegment> segments = stackalloc PathSegment[3];

            // Act
            var count = FastPathTokenizer.Tokenize("/aaa/bb/ccccc", segments);

            // Assert
            Assert.Equal(3, count);
            Assert.Equal(new PathSegment(1, 3), segments[0]);
            Assert.Equal(new PathSegment(5, 2), segments[1]);
            Assert.Equal(new PathSegment(8, 5), segments[2]);
        }
Пример #8
0
        [Fact] // Empty trailing / is ignored
        public void Tokenize_WithSomeSegments_TrailingSlash()
        {
            // Arrange
            Span <PathSegment> segments = stackalloc PathSegment[3];

            // Act
            var count = FastPathTokenizer.Tokenize("/a/b/c/", segments);

            // Assert
            Assert.Equal(3, count);
            Assert.Equal(new PathSegment(1, 1), segments[0]);
            Assert.Equal(new PathSegment(3, 1), segments[1]);
            Assert.Equal(new PathSegment(5, 1), segments[2]);
        }
Пример #9
0
        public void Tokenize_TooManySegments()
        {
            // Arrange
            Span <PathSegment> segments = stackalloc PathSegment[3];

            // Act
            var count = FastPathTokenizer.Tokenize("/a/b/c/d", segments);

            // Assert
            Assert.Equal(3, count);
            Assert.Equal(new PathSegment(1, 1), segments[0]);
            Assert.Equal(new PathSegment(3, 1), segments[1]);
            Assert.Equal(new PathSegment(5, 1), segments[2]);
        }
Пример #10
0
        public void Tokenize_EmptySegments()
        {
            // Arrange
            Span <PathSegment> segments = stackalloc PathSegment[3];

            // Act
            var count = FastPathTokenizer.Tokenize("///c", segments);

            // Assert
            Assert.Equal(3, count);
            Assert.Equal(new PathSegment(1, 0), segments[0]);
            Assert.Equal(new PathSegment(2, 0), segments[1]);
            Assert.Equal(new PathSegment(3, 1), segments[2]);
        }
Пример #11
0
        public sealed override Task MatchAsync(HttpContext httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            // All of the logging we do here is at level debug, so we can get away with doing a single check.
            var log = _logger.IsEnabled(LogLevel.Debug);

            // The sequence of actions we take is optimized to avoid doing expensive work
            // like creating substrings, creating route value dictionaries, and calling
            // into policies like versioning.
            var path = httpContext.Request.Path.Value;

            // First tokenize the path into series of segments.
            Span <PathSegment> buffer = stackalloc PathSegment[_maxSegmentCount];
            var count    = FastPathTokenizer.Tokenize(path, buffer);
            var segments = buffer.Slice(0, count);

            // FindCandidateSet will process the DFA and return a candidate set. This does
            // some preliminary matching of the URL (mostly the literal segments).
            var(candidates, policies) = FindCandidateSet(httpContext, path, segments);
            var candidateCount = candidates.Length;

            if (candidateCount == 0)
            {
                if (log)
                {
                    Logger.CandidatesNotFound(_logger, path);
                }

                return(Task.CompletedTask);
            }

            if (log)
            {
                Logger.CandidatesFound(_logger, path, candidates);
            }

            var policyCount = policies.Length;

            // This is a fast path for single candidate, 0 policies and default selector
            if (candidateCount == 1 && policyCount == 0 && _isDefaultEndpointSelector)
            {
                ref readonly var candidate = ref candidates[0];
Пример #12
0
        public void Dfa()
        {
            for (var i = 0; i < SampleCount; i++)
            {
                var sample      = _samples[i];
                var httpContext = Requests[sample];

                var path = httpContext.Request.Path.Value;
                Span <PathSegment> segments = stackalloc PathSegment[FastPathTokenizer.DefaultSegmentCount];
                var count = FastPathTokenizer.Tokenize(path, segments);

                var candidates = _dfa.FindCandidateSet(httpContext, path, segments.Slice(0, count));

                var endpoint = candidates[0].Endpoint;
                Validate(httpContext, Endpoints[sample], endpoint);
            }
        }