Make HostMatcherPolicy implement IEndpointSelectorPolicy
This commit is contained in:
parent
94fab79771
commit
8df3dc7ae4
|
|
@ -558,14 +558,16 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
protected EndpointSelector() { }
|
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 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 HostMatcherPolicy() { }
|
||||||
public System.Collections.Generic.IComparer<Microsoft.AspNetCore.Http.Endpoint> Comparer { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
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 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 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; }
|
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
|
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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
@ -12,20 +13,41 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
/// An <see cref="MatcherPolicy"/> that implements filtering and selection by
|
/// An <see cref="MatcherPolicy"/> that implements filtering and selection by
|
||||||
/// the host header of a request.
|
/// the host header of a request.
|
||||||
/// </summary>
|
/// </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'.
|
// Run after HTTP methods, but before 'default'.
|
||||||
public override int Order { get; } = -100;
|
public override int Order { get; } = -100;
|
||||||
|
|
||||||
public IComparer<Endpoint> Comparer { get; } = new HostMetadataEndpointComparer();
|
public IComparer<Endpoint> Comparer { get; } = new HostMetadataEndpointComparer();
|
||||||
|
|
||||||
public bool AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
bool INodeBuilderPolicy.AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
||||||
{
|
{
|
||||||
if (endpoints == null)
|
if (endpoints == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(endpoints));
|
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 =>
|
return endpoints.Any(e =>
|
||||||
{
|
{
|
||||||
var hosts = e.Metadata.GetMetadata<IHostMetadata>()?.Hosts;
|
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)
|
private static EdgeKey CreateEdgeKey(string host)
|
||||||
{
|
{
|
||||||
if (host == null)
|
if (host == null)
|
||||||
|
|
@ -71,7 +184,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
return new EdgeKey(hostParts[0], port);
|
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);
|
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>
|
private class HostMetadataEndpointComparer : EndpointMetadataComparer<IHostMetadata>
|
||||||
{
|
{
|
||||||
protected override int CompareMetadata(IHostMetadata x, IHostMetadata y)
|
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
|
// HostString can allocate when accessing the host or port
|
||||||
// Store host and port locally and reuse
|
// Store host and port locally and reuse
|
||||||
var requestHost = httpContext.Request.Host;
|
var (host, port) = GetHostAndPort(httpContext);
|
||||||
var host = requestHost.Host;
|
|
||||||
var port = ResolvePort(httpContext, requestHost);
|
|
||||||
|
|
||||||
var destinations = _destinations;
|
var destinations = _destinations;
|
||||||
for (var i = 0; i < destinations.Length; i++)
|
for (var i = 0; i < destinations.Length; i++)
|
||||||
|
|
@ -255,31 +387,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
return _exitDestination;
|
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 readonly struct EdgeKey : IEquatable<EdgeKey>, IComparable<EdgeKey>, IComparable
|
||||||
{
|
{
|
||||||
private const string WildcardHost = "*";
|
|
||||||
internal static readonly EdgeKey WildcardEdgeKey = new EdgeKey(null, null);
|
internal static readonly EdgeKey WildcardEdgeKey = new EdgeKey(null, null);
|
||||||
|
|
||||||
public readonly int? Port;
|
public readonly int? Port;
|
||||||
|
|
@ -292,7 +403,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
Host = host ?? WildcardHost;
|
Host = host ?? WildcardHost;
|
||||||
Port = port;
|
Port = port;
|
||||||
|
|
||||||
HasHostWildcard = Host.StartsWith("*.", StringComparison.Ordinal);
|
HasHostWildcard = Host.StartsWith(WildcardPrefix, StringComparison.Ordinal);
|
||||||
_wildcardEndsWith = HasHostWildcard ? Host.Substring(1) : null;
|
_wildcardEndsWith = HasHostWildcard ? Host.Substring(1) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,6 +453,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return (Host?.GetHashCode() ?? 0) ^ (Port?.GetHashCode() ?? 0);
|
return (Host?.GetHashCode() ?? 0) ^ (Port?.GetHashCode() ?? 0);
|
||||||
|
|
@ -359,7 +471,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public override string ToString()
|
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
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
// End-to-end tests for the host matching functionality
|
// End-to-end tests for the host matching functionality
|
||||||
public class HostMatcherPolicyIntegrationTest
|
public abstract class HostMatcherPolicyIntegrationTestBase
|
||||||
{
|
{
|
||||||
|
protected abstract bool HasDynamicMetadata { get; }
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Match_Host()
|
public async Task Match_Host()
|
||||||
{
|
{
|
||||||
|
|
@ -308,7 +310,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return (httpContext, context);
|
return (httpContext, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static RouteEndpoint CreateEndpoint(
|
internal RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
|
|
@ -321,6 +323,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
metadata.Add(new HostAttribute(hosts ?? Array.Empty<string>()));
|
metadata.Add(new HostAttribute(hosts ?? Array.Empty<string>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HasDynamicMetadata)
|
||||||
|
{
|
||||||
|
metadata.Add(new DynamicEndpointMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
var displayName = "endpoint: " + template + " " + string.Join(", ", hosts ?? new[] { "*:*" });
|
var displayName = "endpoint: " + template + " " + string.Join(", ", hosts ?? new[] { "*:*" });
|
||||||
return new RouteEndpoint(
|
return new RouteEndpoint(
|
||||||
TestConstants.EmptyRequestDelegate,
|
TestConstants.EmptyRequestDelegate,
|
||||||
|
|
@ -335,5 +342,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var endpoint = CreateEndpoint(template);
|
var endpoint = CreateEndpoint(template);
|
||||||
return (CreateMatcher(endpoint), endpoint);
|
return (CreateMatcher(endpoint), endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DynamicEndpointMetadata : IDynamicEndpointMetadata
|
||||||
|
{
|
||||||
|
public bool IsDynamic => true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,11 +4,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -17,12 +14,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public class HostMatcherPolicyTest
|
public class HostMatcherPolicyTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AppliesToEndpoints_EndpointWithoutMetadata_ReturnsFalse()
|
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointWithoutMetadata_ReturnsFalse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new[] { CreateEndpoint("/", null), };
|
var endpoints = new[] { CreateEndpoint("/", null), };
|
||||||
|
|
||||||
var policy = CreatePolicy();
|
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = policy.AppliesToEndpoints(endpoints);
|
var result = policy.AppliesToEndpoints(endpoints);
|
||||||
|
|
@ -32,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AppliesToEndpoints_EndpointWithoutHosts_ReturnsFalse()
|
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointWithoutHosts_ReturnsFalse()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new[]
|
var endpoints = new[]
|
||||||
|
|
@ -40,7 +37,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
CreateEndpoint("/", new HostAttribute(Array.Empty<string>())),
|
CreateEndpoint("/", new HostAttribute(Array.Empty<string>())),
|
||||||
};
|
};
|
||||||
|
|
||||||
var policy = CreatePolicy();
|
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = policy.AppliesToEndpoints(endpoints);
|
var result = policy.AppliesToEndpoints(endpoints);
|
||||||
|
|
@ -50,7 +47,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AppliesToEndpoints_EndpointHasHosts_ReturnsTrue()
|
public void INodeBuilderPolicy_AppliesToEndpoints_EndpointHasHosts_ReturnsTrue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new[]
|
var endpoints = new[]
|
||||||
|
|
@ -59,7 +56,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
CreateEndpoint("/", new HostAttribute(new[] { "localhost", })),
|
CreateEndpoint("/", new HostAttribute(new[] { "localhost", })),
|
||||||
};
|
};
|
||||||
|
|
||||||
var policy = CreatePolicy();
|
var policy = (INodeBuilderPolicy)CreatePolicy();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = policy.AppliesToEndpoints(endpoints);
|
var result = policy.AppliesToEndpoints(endpoints);
|
||||||
|
|
@ -68,6 +65,25 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
Assert.True(result);
|
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]
|
[Theory]
|
||||||
[InlineData(":")]
|
[InlineData(":")]
|
||||||
[InlineData(":80")]
|
[InlineData(":80")]
|
||||||
|
|
@ -75,12 +91,104 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[InlineData("")]
|
[InlineData("")]
|
||||||
[InlineData("::")]
|
[InlineData("::")]
|
||||||
[InlineData("*:test")]
|
[InlineData("*:test")]
|
||||||
public void AppliesToEndpoints_InvalidHosts(string host)
|
public void INodeBuilderPolicy_AppliesToEndpoints_InvalidHosts(string host)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new[] { CreateEndpoint("/", new HostAttribute(new[] { host })), };
|
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
|
// Act & Assert
|
||||||
Assert.Throws<InvalidOperationException>(() =>
|
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>();
|
var metadata = new List<object>();
|
||||||
if (hostMetadata != null)
|
if (hostMetadata != null)
|
||||||
|
|
@ -160,6 +268,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
metadata.Add(hostMetadata);
|
metadata.Add(hostMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (more != null)
|
||||||
|
{
|
||||||
|
metadata.AddRange(more);
|
||||||
|
}
|
||||||
|
|
||||||
return new RouteEndpoint(
|
return new RouteEndpoint(
|
||||||
(context) => Task.CompletedTask,
|
(context) => Task.CompletedTask,
|
||||||
RoutePatternFactory.Parse(template),
|
RoutePatternFactory.Parse(template),
|
||||||
|
|
@ -172,5 +285,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
return new HostMatcherPolicy();
|
return new HostMatcherPolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DynamicEndpointMetadata : IDynamicEndpointMetadata
|
||||||
|
{
|
||||||
|
public bool IsDynamic => true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue