From 3a92c93cfbdf7c1d350b85de0cf01f89e80fb220 Mon Sep 17 00:00:00 2001 From: Kahbazi Date: Mon, 28 Oct 2019 19:21:30 +0330 Subject: [PATCH] Add PreserveMatchedPathSegment to MapOptions #3762 (#15364) --- ...AspNetCore.Http.Abstractions.netcoreapp.cs | 2 ++ .../src/Extensions/MapExtensions.cs | 17 ++++++++++- .../src/Extensions/MapMiddleware.cs | 24 +++++++++------- .../src/Extensions/MapOptions.cs | 8 +++++- .../test/MapPathMiddlewareTests.cs | 28 +++++++++++++++++++ 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/Http/Http.Abstractions/ref/Microsoft.AspNetCore.Http.Abstractions.netcoreapp.cs b/src/Http/Http.Abstractions/ref/Microsoft.AspNetCore.Http.Abstractions.netcoreapp.cs index cf19578fe0..a443507540 100644 --- a/src/Http/Http.Abstractions/ref/Microsoft.AspNetCore.Http.Abstractions.netcoreapp.cs +++ b/src/Http/Http.Abstractions/ref/Microsoft.AspNetCore.Http.Abstractions.netcoreapp.cs @@ -27,6 +27,7 @@ namespace Microsoft.AspNetCore.Builder public static partial class MapExtensions { public static Microsoft.AspNetCore.Builder.IApplicationBuilder Map(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, Microsoft.AspNetCore.Http.PathString pathMatch, System.Action configuration) { throw null; } + public static Microsoft.AspNetCore.Builder.IApplicationBuilder Map(this Microsoft.AspNetCore.Builder.IApplicationBuilder app, Microsoft.AspNetCore.Http.PathString pathMatch, bool preserveMatchedPathSegment, System.Action configuration) { throw null; } } public static partial class MapWhenExtensions { @@ -67,6 +68,7 @@ namespace Microsoft.AspNetCore.Builder.Extensions public MapOptions() { } public Microsoft.AspNetCore.Http.RequestDelegate Branch { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public Microsoft.AspNetCore.Http.PathString PathMatch { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } + public bool PreserveMatchedPathSegment { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } } public partial class MapWhenMiddleware { diff --git a/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs index 448e2c6f6d..fc33e8fe8a 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapExtensions.cs @@ -21,6 +21,20 @@ namespace Microsoft.AspNetCore.Builder /// The branch to take for positive path matches. /// The instance. public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action configuration) + { + return Map(app, pathMatch, preserveMatchedPathSegment: false, configuration); + } + + /// + /// Branches the request pipeline based on matches of the given request path. If the request path starts with + /// the given path, the branch is executed. + /// + /// The instance. + /// The request path to match. + /// if false, matched path would be removed from Request.Path and added to Request.PathBase. + /// The branch to take for positive path matches. + /// The instance. + public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, bool preserveMatchedPathSegment, Action configuration) { if (app == null) { @@ -46,8 +60,9 @@ namespace Microsoft.AspNetCore.Builder { Branch = branch, PathMatch = pathMatch, + PreserveMatchedPathSegment = preserveMatchedPathSegment }; return app.Use(next => new MapMiddleware(next, options).Invoke); } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs index 4215b82697..0ba76507c8 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs @@ -48,16 +48,17 @@ namespace Microsoft.AspNetCore.Builder.Extensions throw new ArgumentNullException(nameof(context)); } - PathString matchedPath; - PathString remainingPath; - - if (context.Request.Path.StartsWithSegments(_options.PathMatch, out matchedPath, out remainingPath)) + if (context.Request.Path.StartsWithSegments(_options.PathMatch, out var matchedPath, out var remainingPath)) { - // Update the path var path = context.Request.Path; var pathBase = context.Request.PathBase; - context.Request.PathBase = pathBase.Add(matchedPath); - context.Request.Path = remainingPath; + + if (!_options.PreserveMatchedPathSegment) + { + // Update the path + context.Request.PathBase = pathBase.Add(matchedPath); + context.Request.Path = remainingPath; + } try { @@ -65,8 +66,11 @@ namespace Microsoft.AspNetCore.Builder.Extensions } finally { - context.Request.PathBase = pathBase; - context.Request.Path = path; + if (!_options.PreserveMatchedPathSegment) + { + context.Request.PathBase = pathBase; + context.Request.Path = path; + } } } else @@ -75,4 +79,4 @@ namespace Microsoft.AspNetCore.Builder.Extensions } } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs b/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs index 60adc74379..d914aa4210 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapOptions.cs @@ -19,5 +19,11 @@ namespace Microsoft.AspNetCore.Builder.Extensions /// The branch taken for a positive match. /// public RequestDelegate Branch { get; set; } + + /// + /// If false, matched path would be removed from Request.Path and added to Request.PathBase + /// Defaults to false. + /// + public bool PreserveMatchedPathSegment { get; set; } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs index a30e99603c..47637a5a54 100644 --- a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs +++ b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs @@ -95,6 +95,34 @@ namespace Microsoft.AspNetCore.Builder.Extensions Assert.Equal(requestPath.Substring(matchPath.Length), context.Items["test.Path"]); } + [Theory] + [InlineData("/foo", "", "/foo")] + [InlineData("/foo", "", "/foo/")] + [InlineData("/foo", "/Bar", "/foo")] + [InlineData("/foo", "/Bar", "/foo/cho")] + [InlineData("/foo", "/Bar", "/foo/cho/")] + [InlineData("/foo/cho", "/Bar", "/foo/cho")] + [InlineData("/foo/cho", "/Bar", "/foo/cho/do")] + [InlineData("/foo", "", "/Foo")] + [InlineData("/foo", "", "/Foo/")] + [InlineData("/foo", "/Bar", "/Foo")] + [InlineData("/foo", "/Bar", "/Foo/Cho")] + [InlineData("/foo", "/Bar", "/Foo/Cho/")] + [InlineData("/foo/cho", "/Bar", "/Foo/Cho")] + [InlineData("/foo/cho", "/Bar", "/Foo/Cho/do")] + public async Task PathMatchAction_BranchTaken_WithPreserveMatchedPathSegment(string matchPath, string basePath, string requestPath) + { + HttpContext context = CreateRequest(basePath, requestPath); + var builder = new ApplicationBuilder(serviceProvider: null); + builder.Map(matchPath, true, subBuilder => subBuilder.Run(Success)); + var app = builder.Build(); + await app.Invoke(context); + + Assert.Equal(200, context.Response.StatusCode); + Assert.Equal(basePath, (string)context.Items["test.PathBase"]); + Assert.Equal(requestPath, context.Items["test.Path"]); + } + [Theory] [InlineData("/")] [InlineData("/foo/")]