public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (feature == null) { throw new ArgumentNullException(nameof(feature)); } var path = httpContext.Request.Path.Value; for (var i = 0; i < Matchers.Length; i++) { if (Matchers[i].TryMatch(path)) { feature.Endpoint = Matchers[i].Endpoint; feature.RouteValues = new RouteValueDictionary(); } } return(Task.CompletedTask); }
public async Task MatchAsync_DuplicateTemplatesAndDifferentOrder_LowerOrderEndpointMatched() { // Arrange var higherOrderEndpoint = CreateEndpoint("/Teams", 1); var lowerOrderEndpoint = CreateEndpoint("/Teams", 0); var endpointDataSource = new DefaultEndpointDataSource(new List <Endpoint> { higherOrderEndpoint, lowerOrderEndpoint }); var treeMatcher = CreateTreeMatcher(endpointDataSource); var httpContext = new DefaultHttpContext(); httpContext.Request.Path = "/Teams"; var endpointFeature = new EndpointFeature(); // Act await treeMatcher.MatchAsync(httpContext, endpointFeature); // Assert Assert.Equal(lowerOrderEndpoint, endpointFeature.Endpoint); }
public void RouteUrl_WithRouteName_UsesAmbientValues() { // Arrange var endpoint1 = CreateEndpoint( "api/orders/{id}", defaults: new { controller = "Orders", action = "GetById" }, requiredValues: new { controller = "Orders", action = "GetById" }, routeName: "OrdersApi"); var endpoint2 = CreateEndpoint( "api/orders", defaults: new { controller = "Orders", action = "GetAll" }, requiredValues: new { controller = "Orders", action = "GetAll" }, routeName: "OrdersApi"); var urlHelper = CreateUrlHelper(new[] { endpoint1, endpoint2 }); // Set the endpoint feature and current context just as a normal request to MVC app would be var endpointFeature = new EndpointFeature(); urlHelper.ActionContext.HttpContext.Features.Set <IEndpointFeature>(endpointFeature); endpointFeature.Endpoint = endpoint1; endpointFeature.Values = new RouteValueDictionary { ["controller"] = "Orders", ["action"] = "GetById", ["id"] = "500" }; // Act var url = urlHelper.RouteUrl( routeName: "OrdersApi", values: new { }); // Assert Assert.Equal("/api/orders/500", url); }
/// <summary> /// Extension method for setting the <see cref="Endpoint"/> for the current request. /// </summary> /// <param name="context">The <see cref="HttpContext"/> context.</param> /// <param name="endpoint">The <see cref="Endpoint"/>.</param> public static void SetEndpoint(this HttpContext context, Endpoint?endpoint) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var feature = context.Features.Get <IEndpointFeature>(); if (endpoint != null) { if (feature == null) { feature = new EndpointFeature(); context.Features.Set(feature); } feature.Endpoint = endpoint; } else { if (feature == null) { // No endpoint to set and no feature on context. Do nothing return; } feature.Endpoint = null; } }
public async Task Endpoints_InvokeReturnedEndpoint_ActionInvokerProviderCalled() { // Arrange var endpointFeature = new EndpointFeature { RouteValues = new RouteValueDictionary() }; var featureCollection = new FeatureCollection(); featureCollection.Set <IEndpointFeature>(endpointFeature); featureCollection.Set <IRouteValuesFeature>(endpointFeature); featureCollection.Set <IRoutingFeature>(endpointFeature); var httpContextMock = new Mock <HttpContext>(); httpContextMock.Setup(m => m.Features).Returns(featureCollection); var descriptorProviderMock = new Mock <IActionDescriptorCollectionProvider>(); descriptorProviderMock.Setup(m => m.ActionDescriptors).Returns(new ActionDescriptorCollection(new List <ActionDescriptor> { new ActionDescriptor { AttributeRouteInfo = new AttributeRouteInfo { Template = string.Empty }, FilterDescriptors = new List <FilterDescriptor>() } }, 0)); var actionInvokerCalled = false; var actionInvokerMock = new Mock <IActionInvoker>(); actionInvokerMock.Setup(m => m.InvokeAsync()).Returns(() => { actionInvokerCalled = true; return(Task.CompletedTask); }); var actionInvokerProviderMock = new Mock <IActionInvokerFactory>(); actionInvokerProviderMock.Setup(m => m.CreateInvoker(It.IsAny <ActionContext>())).Returns(actionInvokerMock.Object); var dataSource = CreateMvcEndpointDataSource( descriptorProviderMock.Object, new MvcEndpointInvokerFactory(actionInvokerProviderMock.Object)); // Act var endpoints = dataSource.Endpoints; // Assert var endpoint = Assert.Single(endpoints); var matcherEndpoint = Assert.IsType <RouteEndpoint>(endpoint); await matcherEndpoint.RequestDelegate(httpContextMock.Object); Assert.True(actionInvokerCalled); }
public async Task MatchAsync_MultipleMatches_EndpointSelectorCalled() { // Arrange var endpointWithoutConstraint = CreateEndpoint("/Teams", 0); var endpointWithConstraint = CreateEndpoint( "/Teams", 0, metadata: new EndpointMetadataCollection(new object[] { new HttpMethodEndpointConstraint(new[] { "POST" }) })); var endpointDataSource = new DefaultEndpointDataSource(new List <Endpoint> { endpointWithoutConstraint, endpointWithConstraint }); var treeMatcher = CreateTreeMatcher(endpointDataSource); var httpContext = new DefaultHttpContext(); httpContext.Request.Method = "POST"; httpContext.Request.Path = "/Teams"; var endpointFeature = new EndpointFeature(); // Act await treeMatcher.MatchAsync(httpContext, endpointFeature); // Assert Assert.Equal(endpointWithConstraint, endpointFeature.Endpoint); }
public static void AssertNotMatch(EndpointFeature feature, HttpContext context) { if (feature.Endpoint != null) { throw new XunitException( $"Was expected not to match '{feature.Endpoint.DisplayName}' " + $"but matched with values: {FormatRouteValues(context.Features.Get<IRouteValuesFeature>().RouteValues)}."); } }
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature) { if (_isHandled) { feature.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index" }); feature.Endpoint = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "Test endpoint"); } return(Task.CompletedTask); }
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature) { if (TryMatch(httpContext.Request.Path.Value)) { feature.Endpoint = Endpoint; feature.RouteValues = new RouteValueDictionary(); } return(Task.CompletedTask); }
private static (HttpContext httpContext, EndpointFeature feature) CreateContext() { var feature = new EndpointFeature(); var httpContext = new DefaultHttpContext(); httpContext.Features.Set <IEndpointFeature>(feature); httpContext.Features.Set <IRouteValuesFeature>(feature); return(httpContext, feature); }
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];
public void Setup() { SetupEndpoints(); SetupRequests(); _baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder()); _dfa = SetupMatcher(CreateDfaMatcherBuilder()); _feature = new EndpointFeature(); }
public void Setup() { SetupEndpoints(); SetupRequests(); _route = SetupMatcher(RouteMatcher.CreateBuilder()); _tree = SetupMatcher(TreeRouterMatcher.CreateBuilder()); _feature = new EndpointFeature(); }
public void Setup() { SetupEndpoints(); SetupRequests(); _baseline = (TrivialMatcher)SetupMatcher(new TrivialMatcherBuilder()); _dfa = (DfaMatcher)SetupMatcher(CreateDfaMatcherBuilder()); _feature = new EndpointFeature(); }
internal static (HttpContext httpContext, IEndpointFeature feature) CreateContext(string path) { var httpContext = new DefaultHttpContext(); httpContext.Request.Method = "TEST"; httpContext.Request.Path = path; httpContext.RequestServices = CreateServices(); var feature = new EndpointFeature(); httpContext.Features.Set <IEndpointFeature>(feature); return(httpContext, feature); }
public Task ApplyAsync(HttpContext httpContext, EndpointFeature endpointFeature, CandidateSet candidateSet) { // PERF: we can skip over action constraints if there aren't any app-wide. // // Running action constraints (or just checking for them) in a candidate set // is somewhat expensive compared to other routing operations. This should only // happen if user-code adds action constraints. if (ShouldRunActionConstraints) { ApplyActionConstraints(httpContext, candidateSet); } return(Task.CompletedTask); }
public static void AssertMatch(EndpointFeature feature, HttpContext context, Endpoint expected, string[] keys, string[] values) { keys = keys ?? Array.Empty <string>(); values = values ?? Array.Empty <string>(); if (keys.Length != values.Length) { throw new XunitException($"Keys and Values must be the same length."); } var zipped = keys.Zip(values, (k, v) => new KeyValuePair <string, object>(k, v)); AssertMatch(feature, context, expected, new RouteValueDictionary(zipped)); }
public void Setup() { SetupEndpoints(); SetupRequests(); _baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder()); _dfa = SetupMatcher(new DfaMatcherBuilder()); _instruction = SetupMatcher(new InstructionMatcherBuilder()); _route = SetupMatcher(new RouteMatcherBuilder()); _tree = SetupMatcher(new TreeRouterMatcherBuilder()); _feature = new EndpointFeature(); }
public static void SetEndpoint(this HttpContext context, Endpoint endpoint) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var feature = new EndpointFeature { Endpoint = endpoint }; context.Features.Set(typeof(IEndpointFeature), feature); }
public void Setup() { SetupEndpoints(); SetupRequests(); // The perf is kinda slow for these benchmarks, so we do some sampling // of the request data. _samples = SampleRequests(EndpointCount, SampleCount); _route = SetupMatcher(RouteMatcher.CreateBuilder()); _tree = SetupMatcher(TreeRouterMatcher.CreateBuilder()); _feature = new EndpointFeature(); }
public void Setup() { SetupEndpoints(); SetupRequests(); // The perf is kinda slow for these benchmarks, so we do some sampling // of the request data. _samples = SampleRequests(EndpointCount, SampleCount); _baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder()); _dfa = SetupMatcher(CreateDfaMatcherBuilder()); _feature = new EndpointFeature(); }
public async Task MatchAsync_MultipleMatches_EndpointSelectorCalled() { // Arrange var endpoint1 = CreateEndpoint("/Teams", 0); var endpoint2 = CreateEndpoint("/Teams", 1); var endpointSelector = new Mock <EndpointSelector>(); endpointSelector .Setup(s => s.SelectAsync(It.IsAny <HttpContext>(), It.IsAny <IEndpointFeature>(), It.IsAny <CandidateSet>())) .Callback <HttpContext, IEndpointFeature, CandidateSet>((c, f, cs) => { Assert.Equal(2, cs.Count); Assert.Same(endpoint1, cs[0].Endpoint); Assert.True(cs[0].IsValidCandidate); Assert.Equal(0, cs[0].Score); Assert.Empty(cs[0].Values); Assert.Same(endpoint2, cs[1].Endpoint); Assert.True(cs[1].IsValidCandidate); Assert.Equal(1, cs[1].Score); Assert.Empty(cs[1].Values); f.Endpoint = endpoint2; }) .Returns(Task.CompletedTask); var endpointDataSource = new DefaultEndpointDataSource(new List <Endpoint> { endpoint1, endpoint2 }); var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector.Object); var httpContext = new DefaultHttpContext(); httpContext.Request.Path = "/Teams"; var endpointFeature = new EndpointFeature(); // Act await matcher.MatchAsync(httpContext, endpointFeature); // Assert Assert.Equal(endpoint2, endpointFeature.Endpoint); }
public void Setup() { var policyProvider = new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())); _authorizationMiddleware = new AuthorizationMiddleware((context) => Task.CompletedTask, policyProvider); _httpContextNoEndpoint = new DefaultHttpContext(); var feature = new EndpointFeature { Endpoint = new Endpoint((context) => Task.CompletedTask, EndpointMetadataCollection.Empty, "Test endpoint") }; _httpContextHasEndpoint = new DefaultHttpContext(); _httpContextHasEndpoint.Features.Set <IEndpointFeature>(feature); }
public void Setup() { Endpoints = new RouteEndpoint[1]; Endpoints[0] = CreateEndpoint("/plaintext"); Requests = new HttpContext[1]; Requests[0] = new DefaultHttpContext(); Requests[0].RequestServices = CreateServices(); Requests[0].Request.Path = "/plaintext"; _baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder()); _dfa = SetupMatcher(CreateDfaMatcherBuilder()); _route = SetupMatcher(new RouteMatcherBuilder()); _tree = SetupMatcher(new TreeRouterMatcherBuilder()); _feature = new EndpointFeature(); }
public void Setup() { _endpoints = new MatcherEndpoint[1]; _endpoints[0] = CreateEndpoint("/plaintext"); _requests = new HttpContext[1]; _requests[0] = new DefaultHttpContext(); _requests[0].RequestServices = CreateServices(); _requests[0].Request.Path = "/plaintext"; _minimal = SetupMatcher(MinimalMatcher.CreateBuilder()); _dfa = SetupMatcher(DfaMatcher.CreateBuilder()); _instruction = SetupMatcher(InstructionMatcher.CreateBuilder()); _route = SetupMatcher(RouteMatcher.CreateBuilder()); _tree = SetupMatcher(TreeRouterMatcher.CreateBuilder()); _feature = new EndpointFeature(); }
public override async Task SelectAsync( HttpContext httpContext, EndpointFeature feature, CandidateSet candidateSet) { var selectorPolicies = _selectorPolicies; for (var i = 0; i < _selectorPolicies.Length; i++) { await selectorPolicies[i].ApplyAsync(httpContext, feature, candidateSet); if (feature.Endpoint != null) { // This is a short circuit, the selector chose an endpoint. return; } } ProcessFinalCandidates(httpContext, feature, candidateSet); }
private static void ProcessFinalCandidates( HttpContext httpContext, EndpointFeature feature, CandidateSet candidateSet) { Endpoint endpoint = null; RouteValueDictionary values = null; int?foundScore = null; for (var i = 0; i < candidateSet.Count; i++) { ref var state = ref candidateSet[i]; var isValid = state.IsValidCandidate; if (isValid && foundScore == null) { // This is the first match we've seen - speculatively assign it. endpoint = state.Endpoint; values = state.Values; foundScore = state.Score; } else if (isValid && foundScore < state.Score) { // This candidate is lower priority than the one we've seen // so far, we can stop. // // Don't worry about the 'null < state.Score' case, it returns false. break; } else if (isValid && foundScore == state.Score) { // This is the second match we've found of the same score, so there // must be an ambiguity. // // Don't worry about the 'null == state.Score' case, it returns false. ReportAmbiguity(candidateSet); // Unreachable, ReportAmbiguity always throws. throw new NotSupportedException(); } }
public async override Task MatchAsync(HttpContext httpContext, EndpointFeature feature) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (feature == null) { throw new ArgumentNullException(nameof(feature)); } var context = new RouteContext(httpContext); await _inner.RouteAsync(context); if (context.Handler != null) { feature.RouteValues = context.RouteData.Values; await context.Handler(httpContext); } }
public void SetEndpoint_NullOnContextWithFeature_NullSetOnExistingFeature() { // Arrange var context = new DefaultHttpContext(); var initialEndpoint = new Endpoint(c => Task.CompletedTask, EndpointMetadataCollection.Empty, "Test endpoint"); var initialFeature = new EndpointFeature { Endpoint = initialEndpoint }; context.Features.Set <IEndpointFeature>(initialFeature); // Act context.SetEndpoint(null); // Assert var feature = context.Features.Get <IEndpointFeature>(); Assert.Equal(initialFeature, feature); Assert.Null(context.GetEndpoint()); }
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)); } var path = httpContext.Request.Path.Value; if (string.Equals(_endpoint.RoutePattern.RawText, path, StringComparison.OrdinalIgnoreCase)) { feature.Endpoint = _endpoint; feature.RouteValues = new RouteValueDictionary(); } return(Task.CompletedTask); }