Make HostMatcherPolicy implement IEndpointSelectorPolicy
This commit is contained in:
parent
94fab79771
commit
8df3dc7ae4
|
|
@ -558,14 +558,16 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
protected EndpointSelector() { }
|
||||
public abstract System.Threading.Tasks.Task SelectAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.EndpointSelectorContext context, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates);
|
||||
}
|
||||
public sealed partial class HostMatcherPolicy : Microsoft.AspNetCore.Routing.MatcherPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointComparerPolicy, Microsoft.AspNetCore.Routing.Matching.INodeBuilderPolicy
|
||||
public sealed partial class HostMatcherPolicy : Microsoft.AspNetCore.Routing.MatcherPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointComparerPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy, Microsoft.AspNetCore.Routing.Matching.INodeBuilderPolicy
|
||||
{
|
||||
public HostMatcherPolicy() { }
|
||||
public System.Collections.Generic.IComparer<Microsoft.AspNetCore.Http.Endpoint> Comparer { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public override int Order { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public bool AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
|
||||
public System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.EndpointSelectorContext context, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates) { throw null; }
|
||||
public Microsoft.AspNetCore.Routing.Matching.PolicyJumpTable BuildJumpTable(int exitDestination, System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyJumpTableEdge> edges) { throw null; }
|
||||
public System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyNodeEdge> GetEdges(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
|
||||
bool Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy.AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
|
||||
bool Microsoft.AspNetCore.Routing.Matching.INodeBuilderPolicy.AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
|
||||
}
|
||||
public sealed partial class HttpMethodMatcherPolicy : Microsoft.AspNetCore.Routing.MatcherPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointComparerPolicy, Microsoft.AspNetCore.Routing.Matching.INodeBuilderPolicy
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matching
|
||||
|
|
@ -12,20 +13,41 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
/// An <see cref="MatcherPolicy"/> that implements filtering and selection by
|
||||
/// the host header of a request.
|
||||
/// </summary>
|
||||
public sealed class HostMatcherPolicy : MatcherPolicy, IEndpointComparerPolicy, INodeBuilderPolicy
|
||||
public sealed class HostMatcherPolicy : MatcherPolicy, IEndpointComparerPolicy, INodeBuilderPolicy, IEndpointSelectorPolicy
|
||||
{
|
||||
private const string WildcardHost = "*";
|
||||
private const string WildcardPrefix = "*.";
|
||||
|
||||
// Run after HTTP methods, but before 'default'.
|
||||
public override int Order { get; } = -100;
|
||||
|
||||
public IComparer<Endpoint> Comparer { get; } = new HostMetadataEndpointComparer();
|
||||
|
||||
public bool AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
||||
bool INodeBuilderPolicy.AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
||||
{
|
||||
if (endpoints == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(endpoints));
|
||||
}
|
||||
|
||||
return !ContainsDynamicEndpoints(endpoints) && AppliesToEndpointsCore(endpoints);
|
||||
}
|
||||
|
||||
bool IEndpointSelectorPolicy.AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
||||
{
|
||||
// When the node contains dynamic endpoints we can't make any assumptions.
|
||||
var applies = ContainsDynamicEndpoints(endpoints);
|
||||
if (applies)
|
||||
{
|
||||
// Run for the side-effect of validating metadata.
|
||||
AppliesToEndpointsCore(endpoints);
|
||||
}
|
||||
|
||||
return applies;
|
||||
}
|
||||
|
||||
private bool AppliesToEndpointsCore(IReadOnlyList<Endpoint> endpoints)
|
||||
{
|
||||
return endpoints.Any(e =>
|
||||
{
|
||||
var hosts = e.Metadata.GetMetadata<IHostMetadata>()?.Hosts;
|
||||
|
|
@ -48,6 +70,97 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
});
|
||||
}
|
||||
|
||||
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (candidates == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(candidates));
|
||||
}
|
||||
|
||||
for (var i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
if (!candidates.IsValidCandidate(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var hosts = candidates[i].Endpoint.Metadata.GetMetadata<IHostMetadata>()?.Hosts;
|
||||
if (hosts == null || hosts.Count == 0)
|
||||
{
|
||||
// Can match any host.
|
||||
continue;
|
||||
}
|
||||
|
||||
var matched = false;
|
||||
var (requestHost, requestPort) = GetHostAndPort(httpContext);
|
||||
for (var j = 0; j < hosts.Count; j++)
|
||||
{
|
||||
var host = hosts[j].AsSpan();
|
||||
var port = "".AsSpan();
|
||||
|
||||
// Split into host and port
|
||||
var pivot = host.IndexOf(":");
|
||||
if (pivot >= 0)
|
||||
{
|
||||
port = host.Slice(pivot + 1);
|
||||
host = host.Slice(0, pivot);
|
||||
}
|
||||
|
||||
if (host == null || MemoryExtensions.Equals(host, WildcardHost, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Can match any host
|
||||
}
|
||||
else if (
|
||||
host.StartsWith(WildcardPrefix) &&
|
||||
|
||||
// Note that we only slice of the `*`. We want to match the leading `.` also.
|
||||
MemoryExtensions.EndsWith(requestHost, host.Slice(WildcardHost.Length), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Matches a suffix wildcard.
|
||||
}
|
||||
else if (MemoryExtensions.Equals(requestHost, host, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Matches exactly
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we get here then the host doesn't match.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MemoryExtensions.Equals(port, WildcardHost, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Port is a wildcard, we allow any port.
|
||||
}
|
||||
else if (port.Length > 0 && (!int.TryParse(port, out var parsed) || parsed != requestPort))
|
||||
{
|
||||
// If we get here then the port doesn't match.
|
||||
continue;
|
||||
}
|
||||
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!matched)
|
||||
{
|
||||
candidates.SetValidity(i, false);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static EdgeKey CreateEdgeKey(string host)
|
||||
{
|
||||
if (host == null)
|
||||
|
|
@ -71,7 +184,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
{
|
||||
return new EdgeKey(hostParts[0], port);
|
||||
}
|
||||
else if (string.Equals(hostParts[1], "*", StringComparison.Ordinal))
|
||||
else if (string.Equals(hostParts[1], WildcardHost, StringComparison.Ordinal))
|
||||
{
|
||||
return new EdgeKey(hostParts[0], null);
|
||||
}
|
||||
|
|
@ -211,6 +324,27 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
}
|
||||
}
|
||||
|
||||
private static (string host, int? port) GetHostAndPort(HttpContext httpContext)
|
||||
{
|
||||
var hostString = httpContext.Request.Host;
|
||||
if (hostString.Port != null)
|
||||
{
|
||||
return (hostString.Host, hostString.Port);
|
||||
}
|
||||
else if (string.Equals("https", httpContext.Request.Scheme, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return (hostString.Host, 443);
|
||||
}
|
||||
else if (string.Equals("http", httpContext.Request.Scheme, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return (hostString.Host, 80);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (hostString.Host, null);
|
||||
}
|
||||
}
|
||||
|
||||
private class HostMetadataEndpointComparer : EndpointMetadataComparer<IHostMetadata>
|
||||
{
|
||||
protected override int CompareMetadata(IHostMetadata x, IHostMetadata y)
|
||||
|
|
@ -237,9 +371,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
{
|
||||
// HostString can allocate when accessing the host or port
|
||||
// Store host and port locally and reuse
|
||||
var requestHost = httpContext.Request.Host;
|
||||
var host = requestHost.Host;
|
||||
var port = ResolvePort(httpContext, requestHost);
|
||||
var (host, port) = GetHostAndPort(httpContext);
|
||||
|
||||
var destinations = _destinations;
|
||||
for (var i = 0; i < destinations.Length; i++)
|
||||
|
|
@ -255,31 +387,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
return _exitDestination;
|
||||
}
|
||||
|
||||
private static int? ResolvePort(HttpContext httpContext, HostString requestHost)
|
||||
{
|
||||
if (requestHost.Port != null)
|
||||
{
|
||||
return requestHost.Port;
|
||||
}
|
||||
else if (string.Equals("https", httpContext.Request.Scheme, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 443;
|
||||
}
|
||||
else if (string.Equals("http", httpContext.Request.Scheme, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 80;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct EdgeKey : IEquatable<EdgeKey>, IComparable<EdgeKey>, IComparable
|
||||
{
|
||||
private const string WildcardHost = "*";
|
||||
internal static readonly EdgeKey WildcardEdgeKey = new EdgeKey(null, null);
|
||||
|
||||
public readonly int? Port;
|
||||
|
|
@ -292,7 +403,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
Host = host ?? WildcardHost;
|
||||
Port = port;
|
||||
|
||||
HasHostWildcard = Host.StartsWith("*.", StringComparison.Ordinal);
|
||||
HasHostWildcard = Host.StartsWith(WildcardPrefix, StringComparison.Ordinal);
|
||||
_wildcardEndsWith = HasHostWildcard ? Host.Substring(1) : null;
|
||||
}
|
||||
|
||||
|
|
@ -342,6 +453,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Host?.GetHashCode() ?? 0) ^ (Port?.GetHashCode() ?? 0);
|
||||
|
|
@ -359,7 +471,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Host}:{Port?.ToString() ?? "*"}";
|
||||
return $"{Host}:{Port?.ToString() ?? WildcardHost}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matching
|
||||
{
|
||||
// End-to-end tests for the host matching functionality
|
||||
public class HostMatcherPolicyIEndpointSelectorPolicyIntegrationTest : HostMatcherPolicyIntegrationTestBase
|
||||
{
|
||||
protected override bool HasDynamicMetadata => true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matching
|
||||
{
|
||||
// End-to-end tests for the host matching functionality
|
||||
public class HostMatcherPolicyINodeBuilderPolicyIntegrationTest : HostMatcherPolicyIntegrationTestBase
|
||||
{
|
||||
protected override bool HasDynamicMetadata => false;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,10 @@ using Xunit;
|
|||
namespace Microsoft.AspNetCore.Routing.Matching
|
||||
{
|
||||
// End-to-end tests for the host matching functionality
|
||||
public class HostMatcherPolicyIntegrationTest
|
||||
public abstract class HostMatcherPolicyIntegrationTestBase
|
||||
{
|
||||
protected abstract bool HasDynamicMetadata { get; }
|
||||
|
||||
[Fact]
|
||||
public async Task Match_Host()
|
||||
{
|
||||
|
|
@ -308,7 +310,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
return (httpContext, context);
|
||||
}
|
||||
|
||||
internal static RouteEndpoint CreateEndpoint(
|
||||
internal RouteEndpoint CreateEndpoint(
|
||||
string template,
|
||||
object defaults = null,
|
||||
object constraints = null,
|
||||
|
|
@ -321,6 +323,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
metadata.Add(new HostAttribute(hosts ?? Array.Empty<string>()));
|
||||
}
|
||||
|
||||
if (HasDynamicMetadata)
|
||||
{
|
||||
metadata.Add(new DynamicEndpointMetadata());
|
||||
}
|
||||
|
||||
var displayName = "endpoint: " + template + " " + string.Join(", ", hosts ?? new[] { "*:*" });
|
||||
return new RouteEndpoint(
|
||||
TestConstants.EmptyRequestDelegate,
|
||||
|
|
@ -335,5 +342,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
var endpoint = CreateEndpoint(template);
|
||||
return (CreateMatcher(endpoint), endpoint);
|
||||
}
|
||||
|
||||
private class DynamicEndpointMetadata : IDynamicEndpointMetadata
|
||||
{
|
||||
public bool IsDynamic => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.Matching;
|
||||
using Microsoft.AspNetCore.Routing.Patterns;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -17,12 +14,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
public class HostMatcherPolicyTest
|
||||
{
|
||||
[Fact]
|
||||
public void AppliesToEndpoints_EndpointWithoutMetadata_ReturnsFalse()
|
||||
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointWithoutMetadata_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[] { CreateEndpoint("/", null), };
|
||||
|
||||
var policy = CreatePolicy();
|
||||
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
|
@ -32,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void AppliesToEndpoints_EndpointWithoutHosts_ReturnsFalse()
|
||||
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointWithoutHosts_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[]
|
||||
|
|
@ -40,7 +37,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
CreateEndpoint("/", new HostAttribute(Array.Empty<string>())),
|
||||
};
|
||||
|
||||
var policy = CreatePolicy();
|
||||
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
|
@ -50,7 +47,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void AppliesToEndpoints_EndpointHasHosts_ReturnsTrue()
|
||||
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointHasHosts_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[]
|
||||
|
|
@ -59,7 +56,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
CreateEndpoint("/", new HostAttribute(new[] { "localhost", })),
|
||||
};
|
||||
|
||||
var policy = CreatePolicy();
|
||||
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
|
@ -68,6 +65,25 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointHasDynamicMetadata_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[]
|
||||
{
|
||||
CreateEndpoint("/", new HostAttribute(Array.Empty<string>())),
|
||||
CreateEndpoint("/", new HostAttribute(new[] { "localhost", }), new DynamicEndpointMetadata()),
|
||||
};
|
||||
|
||||
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(":")]
|
||||
[InlineData(":80")]
|
||||
|
|
@ -75,12 +91,104 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
[InlineData("")]
|
||||
[InlineData("::")]
|
||||
[InlineData("*:test")]
|
||||
public void AppliesToEndpoints_InvalidHosts(string host)
|
||||
public void INodeBuilderPolicy_AppliesToEndpoints_InvalidHosts(string host)
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[] { CreateEndpoint("/", new HostAttribute(new[] { host })), };
|
||||
|
||||
var policy = CreatePolicy();
|
||||
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
policy.AppliesToEndpoints(endpoints);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IEndpointSelectorPolicy_AppliesToEndpoints_EndpointWithoutMetadata_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[] { CreateEndpoint("/", null, new DynamicEndpointMetadata()), };
|
||||
|
||||
var policy = (IEndpointSelectorPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IEndpointSelectorPolicy_AppliesToEndpoints_EndpointWithoutHosts_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[]
|
||||
{
|
||||
CreateEndpoint("/", new HostAttribute(Array.Empty<string>()), new DynamicEndpointMetadata()),
|
||||
};
|
||||
|
||||
var policy = (IEndpointSelectorPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IEndpointSelectorPolicy_AppliesToEndpoints_EndpointHasHosts_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[]
|
||||
{
|
||||
CreateEndpoint("/", new HostAttribute(Array.Empty<string>())),
|
||||
CreateEndpoint("/", new HostAttribute(new[] { "localhost", }), new DynamicEndpointMetadata()),
|
||||
};
|
||||
|
||||
var policy = (IEndpointSelectorPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IEndpointSelectorPolicy_AppliesToEndpoints_EndpointHasNoDynamicMetadata_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[]
|
||||
{
|
||||
CreateEndpoint("/", new HostAttribute(Array.Empty<string>())),
|
||||
CreateEndpoint("/", new HostAttribute(new[] { "localhost", })),
|
||||
};
|
||||
|
||||
var policy = (IEndpointSelectorPolicy)CreatePolicy();
|
||||
|
||||
// Act
|
||||
var result = policy.AppliesToEndpoints(endpoints);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(":")]
|
||||
[InlineData(":80")]
|
||||
[InlineData("80:")]
|
||||
[InlineData("")]
|
||||
[InlineData("::")]
|
||||
[InlineData("*:test")]
|
||||
public void IEndpointSelectorPolicy_AppliesToEndpoints_InvalidHosts(string host)
|
||||
{
|
||||
// Arrange
|
||||
var endpoints = new[] { CreateEndpoint("/", new HostAttribute(new[] { host }), new DynamicEndpointMetadata()), };
|
||||
|
||||
var policy = (IEndpointSelectorPolicy)CreatePolicy();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
|
|
@ -152,7 +260,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
});
|
||||
}
|
||||
|
||||
private static RouteEndpoint CreateEndpoint(string template, IHostMetadata hostMetadata)
|
||||
private static RouteEndpoint CreateEndpoint(string template, IHostMetadata hostMetadata, params object[] more)
|
||||
{
|
||||
var metadata = new List<object>();
|
||||
if (hostMetadata != null)
|
||||
|
|
@ -160,6 +268,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
metadata.Add(hostMetadata);
|
||||
}
|
||||
|
||||
if (more != null)
|
||||
{
|
||||
metadata.AddRange(more);
|
||||
}
|
||||
|
||||
return new RouteEndpoint(
|
||||
(context) => Task.CompletedTask,
|
||||
RoutePatternFactory.Parse(template),
|
||||
|
|
@ -172,5 +285,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
{
|
||||
return new HostMatcherPolicy();
|
||||
}
|
||||
|
||||
private class DynamicEndpointMetadata : IDynamicEndpointMetadata
|
||||
{
|
||||
public bool IsDynamic => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue