From 0c3f6497dba9753fe912d03d0f870f53d27dce2c Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 22 Mar 2016 17:00:24 -0700 Subject: [PATCH] Fixes issue of request path segment length greater than the wildcard template route Fixes https://github.com/aspnet/Mvc/issues/4256 --- .../Tree/TreeRouteBuilder.cs | 4 +-- .../Tree/TreeRouter.cs | 12 ++++++- .../Tree/UrlMatchingNode.cs | 2 ++ .../Tree/TreeRouterTest.cs | 35 ++++++++++++++++++- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.AspNetCore.Routing/Tree/TreeRouteBuilder.cs b/src/Microsoft.AspNetCore.Routing/Tree/TreeRouteBuilder.cs index d917428ed2..b1c515b6c6 100644 --- a/src/Microsoft.AspNetCore.Routing/Tree/TreeRouteBuilder.cs +++ b/src/Microsoft.AspNetCore.Routing/Tree/TreeRouteBuilder.cs @@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.Routing.Tree { if (current.ConstrainedCatchAlls == null) { - current.ConstrainedCatchAlls = new UrlMatchingNode(length: i + 1); + current.ConstrainedCatchAlls = new UrlMatchingNode(length: i + 1) { IsCatchAll = true }; } current = current.ConstrainedCatchAlls; @@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Routing.Tree { if (current.CatchAlls == null) { - current.CatchAlls = new UrlMatchingNode(length: i + 1); + current.CatchAlls = new UrlMatchingNode(length: i + 1) { IsCatchAll = true }; } current = current.CatchAlls; diff --git a/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs b/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs index 46544b2ee0..1c3578b1b7 100644 --- a/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs +++ b/src/Microsoft.AspNetCore.Routing/Tree/TreeRouter.cs @@ -249,7 +249,17 @@ namespace Microsoft.AspNetCore.Routing.Tree while (_stack.Count > 0) { var next = _stack.Pop(); - if (++_segmentIndex >= _tokenizer.Count) + + // In case of wild card segment, the request path segment length can be greater + // Example: + // Template: a/{*path} + // Request Url: a/b/c/d + if (next.IsCatchAll && next.Matches.Count > 0) + { + Current = next; + return true; + } + else if (++_segmentIndex >= _tokenizer.Count) { _segmentIndex--; if (next.Matches.Count > 0) diff --git a/src/Microsoft.AspNetCore.Routing/Tree/UrlMatchingNode.cs b/src/Microsoft.AspNetCore.Routing/Tree/UrlMatchingNode.cs index 6d82adefb2..2e6ba9ed18 100644 --- a/src/Microsoft.AspNetCore.Routing/Tree/UrlMatchingNode.cs +++ b/src/Microsoft.AspNetCore.Routing/Tree/UrlMatchingNode.cs @@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore.Routing.Tree public int Length { get; } + public bool IsCatchAll { get; set; } + // These entries are sorted by precedence then template public List Matches { get; } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs index 30dd445490..66f530a378 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/Tree/TreeRouterTest.cs @@ -119,6 +119,39 @@ namespace Microsoft.AspNetCore.Routing.Tree Assert.Equal(expectedRouteGroup, context.RouteData.Values["test_route_group"]); } + [Theory] + [InlineData("{*path}", "/a", "a")] + [InlineData("{*path}", "/a/b/c", "a/b/c")] + [InlineData("a/{*path}", "/a/b", "b")] + [InlineData("a/{*path}", "/a/b/c/d", "b/c/d")] + [InlineData("a/{*path:regex(10/20/30)}", "/a/10/20/30", "10/20/30")] + public async Task TreeRouter_RouteAsync_MatchesWildCard_ForLargerPathSegments( + string template, + string requestPath, + string expectedResult) + { + // Arrange + var next = new Mock(); + next + .Setup(r => r.RouteAsync(It.IsAny())) + .Callback(c => c.Handler = NullHandler) + .Returns(Task.FromResult(true)) + .Verifiable(); + + var firstRoute = CreateMatchingEntry(next.Object, template, order: 0); + var matchingRoutes = new[] { firstRoute }; + var linkGenerationEntries = Enumerable.Empty(); + var attributeRoute = CreateAttributeRoute(next.Object, matchingRoutes, linkGenerationEntries); + var context = CreateRouteContext(requestPath); + + // Act + await attributeRoute.RouteAsync(context); + + // Assert + Assert.NotNull(context.Handler); + Assert.Equal(expectedResult, context.RouteData.Values["path"]); + } + [Theory] [InlineData("template/5")] [InlineData("template/{parameter:int}")] @@ -761,7 +794,7 @@ namespace Microsoft.AspNetCore.Routing.Tree IEnumerable namedEntries) { // Arrange - var expectedLink = + var expectedLink = namedEntries.First().Template.Parameters.Any() ? "/template/5" : "/template"; var matchingEntries = Enumerable.Empty();