diff --git a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs index 35b25f40e62b..3122b7640909 100644 --- a/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs +++ b/src/Http/Http.Abstractions/src/Extensions/MapMiddleware.cs @@ -64,7 +64,7 @@ public Task Invoke(HttpContext context) return _next(context); } - private async Task InvokeCore(HttpContext context, string matchedPath, string remainingPath) + private async Task InvokeCore(HttpContext context, PathString matchedPath, PathString remainingPath) { var path = context.Request.Path; var pathBase = context.Request.PathBase; diff --git a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs index 0bdf4fcfed97..46280bb4f221 100644 --- a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs +++ b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseExtensions.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -26,7 +26,7 @@ public static IApplicationBuilder UsePathBase(this IApplicationBuilder app, Path } // Strip trailing slashes - pathBase = pathBase.Value?.TrimEnd('/'); + pathBase = new PathString(pathBase.Value?.TrimEnd('/')); if (!pathBase.HasValue) { return app; @@ -35,4 +35,4 @@ public static IApplicationBuilder UsePathBase(this IApplicationBuilder app, Path return app.UseMiddleware(pathBase); } } -} \ No newline at end of file +} diff --git a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs index 34ffc5738d40..ef7b9d586cfd 100644 --- a/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs +++ b/src/Http/Http.Abstractions/src/Extensions/UsePathBaseMiddleware.cs @@ -55,7 +55,7 @@ public Task Invoke(HttpContext context) return _next(context); } - private async Task InvokeCore(HttpContext context, string matchedPath, string remainingPath) + private async Task InvokeCore(HttpContext context, PathString matchedPath, PathString remainingPath) { var originalPath = context.Request.Path; var originalPathBase = context.Request.PathBase; diff --git a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs index 48c718a47c16..acaa0e0bce6d 100644 --- a/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs +++ b/src/Http/Http.Abstractions/test/MapPathMiddlewareTests.cs @@ -43,24 +43,27 @@ public void NullArguments_ArgumentNullException() } [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")] - public async Task PathMatchFunc_BranchTaken(string matchPath, string basePath, string requestPath) + [InlineData("/foo", "", "/foo", "/foo", "")] + [InlineData("/foo", "", "/foo/", "/foo", "/")] + [InlineData("/foo", "/Bar", "/foo", "/Bar/foo", "")] + [InlineData("/foo", "/Bar", "/foo/cho", "/Bar/foo", "/cho")] + [InlineData("/foo", "/Bar", "/foo/cho/", "/Bar/foo", "/cho/")] + [InlineData("/foo/cho", "/Bar", "/foo/cho", "/Bar/foo/cho", "")] + [InlineData("/foo/cho", "/Bar", "/foo/cho/do", "/Bar/foo/cho", "/do")] + [InlineData("/foo%42/cho", "/Bar%42", "/foo%42/cho/do%42", "/Bar%42/foo%42/cho", "/do%42")] + public async Task PathMatchFunc_BranchTaken(string matchPath, string basePath, string requestPath, string expectedPathBase, string expectedPath) { HttpContext context = CreateRequest(basePath, requestPath); var builder = new ApplicationBuilder(serviceProvider: null!); - builder.Map(matchPath, UseSuccess); + builder.Map(new PathString(matchPath), UseSuccess); var app = builder.Build(); await app.Invoke(context); Assert.Equal(200, context.Response.StatusCode); Assert.Equal(basePath, context.Request.PathBase.Value); Assert.Equal(requestPath, context.Request.Path.Value); + Assert.Equal(expectedPathBase, (string)context.Items["test.PathBase"]!); + Assert.Equal(expectedPath, context.Items["test.Path"]); } [Theory] diff --git a/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs b/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs index a5511ef0c18b..ebb695ed0656 100644 --- a/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs +++ b/src/Http/Http.Abstractions/test/UsePathBaseExtensionsTests.cs @@ -131,11 +131,23 @@ public Task PathBaseCanHaveUnicodeCharacters(string registeredPathBase, string p return TestPathBase(registeredPathBase, pathBase, requestPath, expectedPathBase, expectedPath); } + [Theory] + [InlineData("/b%42", "", "/b%42/something%42", "/b%42", "/something%42")] + [InlineData("/b%42", "", "/B%42/something%42", "/B%42", "/something%42")] + [InlineData("/b%42", "", "/b%42/Something%42", "/b%42", "/Something%42")] + [InlineData("/b%42", "/oldb%42", "/b%42/something%42", "/oldb%42/b%42", "/something%42")] + [InlineData("/b%42", "/oldb%42", "/b%42/Something%42", "/oldb%42/b%42", "/Something%42")] + [InlineData("/b%42", "/oldb%42", "/B%42/something%42", "/oldb%42/B%42", "/something%42")] + public Task PathBaseCanHavePercentCharacters(string registeredPathBase, string pathBase, string requestPath, string expectedPathBase, string expectedPath) + { + return TestPathBase(registeredPathBase, pathBase, requestPath, expectedPathBase, expectedPath); + } + private static async Task TestPathBase(string registeredPathBase, string pathBase, string requestPath, string expectedPathBase, string expectedPath) { HttpContext requestContext = CreateRequest(pathBase, requestPath); var builder = CreateBuilder() - .UsePathBase(registeredPathBase); + .UsePathBase(new PathString(registeredPathBase)); builder.Run(context => { context.Items["test.Path"] = context.Request.Path;