public void BuildEndpoints_JustHostWithWildcard_Works()
        {
            // Arrange
            var builder     = Create <RuntimeRouteBuilder>();
            var parsedRoute = new ParsedRoute
            {
                RouteId  = "route1",
                Host     = "*.example.com",
                Priority = 12,
            };
            var cluster   = new ClusterInfo("cluster1", new DestinationManager(), new Mock <IProxyHttpClientFactory>().Object);
            var routeInfo = new RouteInfo("route1");

            // Act
            var config = builder.Build(parsedRoute, cluster, routeInfo);

            // Assert
            Assert.Same(cluster, config.Cluster);
            Assert.Equal(12, config.Priority);
            Assert.Equal(parsedRoute.GetConfigHash(), config.ConfigHash);
            Assert.Single(config.Endpoints);
            var routeEndpoint = config.Endpoints[0] as AspNetCore.Routing.RouteEndpoint;

            Assert.Equal("route1", routeEndpoint.DisplayName);
            Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>());
            Assert.Equal("/{**catchall}", routeEndpoint.RoutePattern.RawText);

            var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>();

            Assert.NotNull(hostMetadata);
            Assert.Single(hostMetadata.Hosts);
            Assert.Equal("*.example.com", hostMetadata.Hosts[0]);
        }
예제 #2
0
        public void BuildEndpoints_HostAndPath_Works()
        {
            // Arrange
            var builder     = Create <RuntimeRouteBuilder>();
            var parsedRoute = new ParsedRoute
            {
                RouteId  = "route1",
                Host     = "example.com",
                Path     = "/a",
                Priority = 12,
            };
            var backend   = new BackendInfo("backend1", new DestinationManager(), new Mock <IProxyHttpClientFactory>().Object);
            var routeInfo = new RouteInfo("route1");

            // Act
            var config = builder.Build(parsedRoute, backend, routeInfo);

            // Assert
            Assert.Same(backend, config.BackendOrNull);
            Assert.Equal(12, config.Priority);
            Assert.Equal(parsedRoute.GetConfigHash(), config.ConfigHash);
            Assert.Single(config.Endpoints);
            var routeEndpoint = config.Endpoints[0] as AspNetCore.Routing.RouteEndpoint;

            Assert.Equal("route1", routeEndpoint.DisplayName);
            Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>());
            Assert.Equal("/a", routeEndpoint.RoutePattern.RawText);

            var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>();

            Assert.NotNull(hostMetadata);
            Assert.Single(hostMetadata.Hosts);
            Assert.Equal("example.com", hostMetadata.Hosts[0]);
        }
        /// <inheritdoc/>
        public RouteConfig Build(ParsedRoute source, ClusterInfo cluster, RouteInfo runtimeRoute)
        {
            _ = source ?? throw new ArgumentNullException(nameof(source));
            _ = runtimeRoute ?? throw new ArgumentNullException(nameof(runtimeRoute));

            var transforms = _transformBuilder.Build(source.Transforms);

            // NOTE: `new RouteConfig(...)` needs a reference to the list of ASP .NET Core endpoints,
            // but the ASP .NET Core endpoints cannot be created without a `RouteConfig` metadata item.
            // We solve this chicken-egg problem by creating an (empty) list first
            // and passing a read-only wrapper of it to `RouteConfig.ctor`.
            // Recall that `List<T>.AsReadOnly()` creates a wrapper over the original list,
            // and changes to the underlying list *are* reflected on the read-only view.
            var aspNetCoreEndpoints = new List <Endpoint>(1);
            var newRouteConfig      = new RouteConfig(
                runtimeRoute,
                source.GetConfigHash(),
                source.Priority,
                cluster,
                aspNetCoreEndpoints.AsReadOnly(),
                transforms);

            // TODO: Handle arbitrary AST's properly
            // Catch-all pattern when no path was specified
            var pathPattern = string.IsNullOrEmpty(source.Path) ? "/{**catchall}" : source.Path;

            // TODO: Propagate route priority
            var endpointBuilder = new AspNetCore.Routing.RouteEndpointBuilder(
                requestDelegate: _pipeline ?? Invoke,
                routePattern: AspNetCore.Routing.Patterns.RoutePatternFactory.Parse(pathPattern),
                order: 0);

            endpointBuilder.DisplayName = source.RouteId;
            endpointBuilder.Metadata.Add(newRouteConfig);

            if (!string.IsNullOrEmpty(source.Host))
            {
                endpointBuilder.Metadata.Add(new AspNetCore.Routing.HostAttribute(source.Host));
            }

            if (source.Methods != null && source.Methods.Count > 0)
            {
                endpointBuilder.Metadata.Add(new AspNetCore.Routing.HttpMethodMetadata(source.Methods));
            }

            if (string.Equals(AuthorizationConstants.Default, source.AuthorizationPolicy, StringComparison.OrdinalIgnoreCase))
            {
                endpointBuilder.Metadata.Add(DefaultAuthorization);
            }
            else if (!string.IsNullOrEmpty(source.AuthorizationPolicy))
            {
                endpointBuilder.Metadata.Add(new AuthorizeAttribute(source.AuthorizationPolicy));
            }

            var endpoint = endpointBuilder.Build();

            aspNetCoreEndpoints.Add(endpoint);

            return(newRouteConfig);
        }
예제 #4
0
 public bool HasConfigChanged(ParsedRoute newConfig, BackendInfo backendOrNull)
 {
     return(BackendOrNull != backendOrNull ||
            !ConfigHash.Equals(newConfig.GetConfigHash()));
 }
예제 #5
0
 public bool HasConfigChanged(ParsedRoute newConfig, ClusterInfo cluster)
 {
     return(Cluster != cluster ||
            !ConfigHash.Equals(newConfig.GetConfigHash()));
 }