diff --git a/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs b/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs index 7cc748ddf4..28b5cdf353 100644 --- a/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs +++ b/src/Microsoft.AspNetCore.Routing/Matching/DfaMatcherBuilder.cs @@ -592,12 +592,23 @@ namespace Microsoft.AspNetCore.Routing.Matching // Start with the current node as the root. var work = new List() { node, }; + List previousWork = null; for (var i = 0; i < _nodeBuilders.Length; i++) { var nodeBuilder = _nodeBuilders[i]; // Build a list of each - var nextWork = new List(); + List nextWork; + if (previousWork == null) + { + nextWork = new List(); + } + else + { + // Reuse previous collection for the next collection + previousWork.Clear(); + nextWork = previousWork; + } for (var j = 0; j < work.Count; j++) { @@ -639,6 +650,7 @@ namespace Microsoft.AspNetCore.Routing.Matching parent.Matches?.Clear(); } + previousWork = work; work = nextWork; } } diff --git a/src/Microsoft.AspNetCore.Routing/Matching/HttpMethodMatcherPolicy.cs b/src/Microsoft.AspNetCore.Routing/Matching/HttpMethodMatcherPolicy.cs index f6149531d4..8a5beb5bd9 100644 --- a/src/Microsoft.AspNetCore.Routing/Matching/HttpMethodMatcherPolicy.cs +++ b/src/Microsoft.AspNetCore.Routing/Matching/HttpMethodMatcherPolicy.cs @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Routing.Matching for (var i = 0; i < endpoints.Count; i++) { - if (endpoints[i].Metadata.GetMetadata()?.HttpMethods.Any() == true) + if (endpoints[i].Metadata.GetMetadata()?.HttpMethods.Count > 0) { return true; } @@ -219,31 +219,41 @@ namespace Microsoft.AspNetCore.Routing.Matching /// public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList edges) { - var destinations = new Dictionary(StringComparer.OrdinalIgnoreCase); - var corsPreflightDestinations = new Dictionary(StringComparer.OrdinalIgnoreCase); + Dictionary destinations = null; + Dictionary corsPreflightDestinations = null; for (var i = 0; i < edges.Count; i++) { // We create this data, so it's safe to cast it. var key = (EdgeKey)edges[i].State; if (key.IsCorsPreflightRequest) { + if (corsPreflightDestinations == null) + { + corsPreflightDestinations = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + corsPreflightDestinations.Add(key.HttpMethod, edges[i].Destination); } else { + if (destinations == null) + { + destinations = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + destinations.Add(key.HttpMethod, edges[i].Destination); } } int corsPreflightExitDestination = exitDestination; - if (corsPreflightDestinations.TryGetValue(AnyMethod, out var matchesAnyVerb)) + if (corsPreflightDestinations != null && corsPreflightDestinations.TryGetValue(AnyMethod, out var matchesAnyVerb)) { // If we have endpoints that match any HTTP method, use that as the exit. corsPreflightExitDestination = matchesAnyVerb; corsPreflightDestinations.Remove(AnyMethod); } - if (destinations.TryGetValue(AnyMethod, out matchesAnyVerb)) + if (destinations != null && destinations.TryGetValue(AnyMethod, out matchesAnyVerb)) { // If we have endpoints that match any HTTP method, use that as the exit. exitDestination = matchesAnyVerb; @@ -304,7 +314,7 @@ namespace Microsoft.AspNetCore.Routing.Matching _corsPreflightExitDestination = corsPreflightExitDestination; _corsPreflightDestinations = corsPreflightDestinations; - _supportsCorsPreflight = _corsPreflightDestinations.Count > 0; + _supportsCorsPreflight = _corsPreflightDestinations != null && _corsPreflightDestinations.Count > 0; } public override int GetDestination(HttpContext httpContext) @@ -318,12 +328,14 @@ namespace Microsoft.AspNetCore.Routing.Matching httpContext.Request.Headers.TryGetValue(AccessControlRequestMethod, out var accessControlRequestMethod) && !StringValues.IsNullOrEmpty(accessControlRequestMethod)) { - return _corsPreflightDestinations.TryGetValue(accessControlRequestMethod, out destination) + return _corsPreflightDestinations != null && + _corsPreflightDestinations.TryGetValue(accessControlRequestMethod, out destination) ? destination : _corsPreflightExitDestination; } - return _destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination; + return _destinations != null && + _destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination; } }