diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs index 90ddf74273..2a68eb1b3c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectRule.cs @@ -34,6 +34,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public override void ApplyRule(RewriteContext context) { var path = context.HttpContext.Request.Path; + var pathBase = context.HttpContext.Request.PathBase; + Match initMatchResults; if (path == PathString.Empty) { @@ -54,7 +56,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules if (string.IsNullOrEmpty(newPath)) { - response.Headers[HeaderNames.Location] = "/"; + response.Headers[HeaderNames.Location] = pathBase.HasValue ? pathBase.Value : "/"; return; } @@ -70,11 +72,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules QueryString.FromUriComponent( newPath.Substring(split))); // not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308 - response.Headers[HeaderNames.Location] = newPath.Substring(0, split) + query; + response.Headers[HeaderNames.Location] = pathBase + newPath.Substring(0, split) + query; } else { - response.Headers[HeaderNames.Location] = newPath; + response.Headers[HeaderNames.Location] = pathBase + newPath; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs index dfac28fc80..b295804064 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RedirectAction.cs @@ -47,6 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { var pattern = Url.Evaluate(context, ruleMatch, condMatch); var response = context.HttpContext.Response; + var pathBase = context.HttpContext.Request.PathBase; if (EscapeBackReferences) { // because escapebackreferences will be encapsulated by the pattern, just escape the pattern @@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions if (string.IsNullOrEmpty(pattern)) { - response.Headers[HeaderNames.Location] = "/"; + response.Headers[HeaderNames.Location] = pathBase.HasValue ? pathBase.Value : "/"; return; } @@ -77,7 +78,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions pattern.Substring(split))); // not using the response.redirect here because status codes may be 301, 302, 307, 308 - response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; + response.Headers[HeaderNames.Location] = pathBase + pattern.Substring(0, split) + query; } else { @@ -85,11 +86,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions // by default. if (QueryStringDelete) { - response.Headers[HeaderNames.Location] = pattern; + response.Headers[HeaderNames.Location] = pathBase + pattern; } else { - response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString; + response.Headers[HeaderNames.Location] = pathBase + pattern + context.HttpContext.Request.QueryString; } } context.Result = RuleTermination.ResponseComplete; diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs index 51456357c6..9a6f4d9c46 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/CodeRules/MiddlewareTests.cs @@ -102,5 +102,24 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules Assert.Equal(response, "/"); } + + [Fact] + public async Task SettingPathBase() + { + var options = new RewriteOptions().AddRedirect("(.*)", "$1"); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder) {BaseAddress = new Uri("http://localhost:5000/foo")}; + + var response = await server.CreateClient().GetAsync(""); + + Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs index 57daef1bc3..0c3b943636 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ModRewriteMiddlewareTest.cs @@ -1,6 +1,7 @@ // 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. +using System; using System.IO; using System.Net; using System.Threading.Tasks; @@ -286,5 +287,24 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite var response = await server.CreateClient().GetStringAsync(input); Assert.Equal(response, "/"); } + + [Fact] + public async Task Invoke_CaptureEmptyStringInRegexAssertLocationHeaderContainsPathBase() + { + var options = new RewriteOptions().AddApacheModRewrite(new StringReader(@"RewriteRule ^(.*)$ $1 [R=301,L]")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder) { BaseAddress = new Uri("http://localhost:5000/foo") }; + + var response = await server.CreateClient().GetAsync(""); + + Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs index e20c5b9419..dcc7cb98c4 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/MiddleWareTests.cs @@ -310,5 +310,31 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(response, "/"); } + + [Fact] + public async Task Invoke_CaptureEmptyStringInRegexAssertLocationHeaderContainsPathBase() + { + var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(@" + + + + + + + ")); + var builder = new WebHostBuilder() + .Configure(app => + { + app.UseRewriter(options); + app.Run(context => context.Response.WriteAsync( + context.Request.Path + + context.Request.QueryString)); + }); + var server = new TestServer(builder) { BaseAddress = new Uri("http://localhost:5000/foo") }; + + var response = await server.CreateClient().GetAsync(""); + + Assert.Equal(response.Headers.Location.OriginalString, "/foo"); + } } }