Bläddra i källkod

Add option to limit domains on AddRedirectToWww (#9676)

Bruno 6 år sedan
förälder
incheckning
124064ef47

+ 5 - 0
src/Middleware/Rewrite/ref/Microsoft.AspNetCore.Rewrite.netcoreapp3.0.cs

@@ -56,7 +56,10 @@ namespace Microsoft.AspNetCore.Rewrite
         public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToHttpsPermanent(this Microsoft.AspNetCore.Rewrite.RewriteOptions options) { throw null; }
         public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToWww(this Microsoft.AspNetCore.Rewrite.RewriteOptions options) { throw null; }
         public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToWww(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, int statusCode) { throw null; }
+        public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToWww(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, int statusCode, params string[] domains) { throw null; }
+        public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToWww(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, params string[] domains) { throw null; }
         public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToWwwPermanent(this Microsoft.AspNetCore.Rewrite.RewriteOptions options) { throw null; }
+        public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRedirectToWwwPermanent(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, params string[] domains) { throw null; }
         public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, string regex, string replacement, bool skipRemainingRules) { throw null; }
     }
     public enum RuleResult
@@ -129,8 +132,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal
     }
     public partial class RedirectToWwwRule : Microsoft.AspNetCore.Rewrite.IRule
     {
+        public readonly string[] _domains;
         public readonly int _statusCode;
         public RedirectToWwwRule(int statusCode) { }
+        public RedirectToWwwRule(int statusCode, params string[] domains) { }
         public virtual void ApplyRule(Microsoft.AspNetCore.Rewrite.RewriteContext context) { }
     }
     public partial class RewriteRule : Microsoft.AspNetCore.Rewrite.IRule

+ 38 - 0
src/Middleware/Rewrite/src/Internal/RedirectToWwwRule.cs

@@ -12,15 +12,33 @@ namespace Microsoft.AspNetCore.Rewrite.Internal
     public class RedirectToWwwRule : IRule
     {
         public readonly int _statusCode;
+        public readonly string[] _domains;
 
         public RedirectToWwwRule(int statusCode)
         {
             _statusCode = statusCode;
         }
 
+        public RedirectToWwwRule(int statusCode, params string[] domains)
+        {
+            if (domains == null)
+            {
+                throw new ArgumentNullException(nameof(domains));
+            }
+
+            if (domains.Length < 1)
+            {
+                throw new ArgumentException(nameof(domains));
+            }
+
+            _domains = domains;
+            _statusCode = statusCode;
+        }
+
         public virtual void ApplyRule(RewriteContext context)
         {
             var req = context.HttpContext.Request;
+
             if (req.Host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
             {
                 context.Result = RuleResult.ContinueRules;
@@ -33,6 +51,26 @@ namespace Microsoft.AspNetCore.Rewrite.Internal
                 return;
             }
 
+            if (_domains != null)
+            {
+                var isHostInDomains = false;
+
+                foreach (var domain in _domains)
+                {
+                    if (domain.Equals(req.Host.Host, StringComparison.OrdinalIgnoreCase))
+                    {
+                        isHostInDomains = true;
+                        break;
+                    }
+                }
+
+                if (!isHostInDomains)
+                {
+                    context.Result = RuleResult.ContinueRules;
+                    return;
+                }
+            }
+
             var wwwHost = new HostString($"www.{req.Host.Value}");
             var newUrl = UriHelper.BuildAbsolute(req.Scheme, wwwHost, req.PathBase, req.Path, req.QueryString);
             var response = context.HttpContext.Response;

+ 33 - 0
src/Middleware/Rewrite/src/RewriteOptionsExtensions.cs

@@ -128,6 +128,17 @@ namespace Microsoft.AspNetCore.Rewrite
             return AddRedirectToWww(options, statusCode: StatusCodes.Status308PermanentRedirect);
         }
 
+        /// <summary>
+        /// Permanently redirects the request to the www subdomain if the request is non-www.
+        /// </summary>
+        /// <param name="options">The <see cref="RewriteOptions"/>.</param>
+        /// <param name="domains">Limit the rule to apply only on the specified domain(s).</param>
+        /// <returns></returns>
+        public static RewriteOptions AddRedirectToWwwPermanent(this RewriteOptions options, params string[] domains)
+        {
+            return AddRedirectToWww(options, statusCode: StatusCodes.Status308PermanentRedirect, domains);
+        }
+
         /// <summary>
         /// Redirect the request to the www subdomain if the incoming request is non-www.
         /// </summary>
@@ -137,6 +148,16 @@ namespace Microsoft.AspNetCore.Rewrite
             return AddRedirectToWww(options, statusCode: StatusCodes.Status307TemporaryRedirect);
         }
 
+        /// <summary>
+        /// Redirect the request to the www subdomain if the incoming request is non-www.
+        /// </summary>
+        /// <param name="options">The <see cref="RewriteOptions"/>.</param>
+        /// <param name="domains">Limit the rule to apply only on the specified domain(s).</param>
+        public static RewriteOptions AddRedirectToWww(this RewriteOptions options, params string[] domains)
+        {
+            return AddRedirectToWww(options, statusCode: StatusCodes.Status307TemporaryRedirect, domains);
+        }
+
         /// <summary>
         /// Redirect the request to the www subdomain if the incoming request is non-www.
         /// </summary>
@@ -147,5 +168,17 @@ namespace Microsoft.AspNetCore.Rewrite
             options.Rules.Add(new RedirectToWwwRule(statusCode));
             return options;
         }
+
+        /// <summary>
+        /// Redirect the request to the www subdomain if the incoming request is non-www.
+        /// </summary>
+        /// <param name="options">The <see cref="RewriteOptions"/>.</param>
+        /// <param name="statusCode">The status code to add to the response.</param>
+        /// <param name="domains">Limit the rule to apply only on the specified domain(s).</param>
+        public static RewriteOptions AddRedirectToWww(this RewriteOptions options, int statusCode, params string[] domains)
+        {
+            options.Rules.Add(new RedirectToWwwRule(statusCode, domains));
+            return options;
+        }
     }
 }

+ 81 - 0
src/Middleware/Rewrite/test/MiddlewareTests.cs

@@ -284,5 +284,86 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules
 
             Assert.Equal("/foo", response.Headers.Location.OriginalString);
         }
+
+        [Theory]
+        [InlineData("http://example.com")]
+        [InlineData("https://example.com")]
+        [InlineData("http://example.com:8081")]
+        [InlineData("https://example.com:8081")]
+        [InlineData("https://example.com:8081/example?q=1")]
+        public async Task CheckNoRedirectToWwwInNonWhitelistedDomains(string requestUri)
+        {
+            var options = new RewriteOptions().AddRedirectToWww("example2.com");
+            var builder = new WebHostBuilder()
+            .Configure(app =>
+            {
+                app.UseRewriter(options);
+            });
+            var server = new TestServer(builder);
+
+            var response = await server.CreateClient().GetAsync(new Uri(requestUri));
+
+            Assert.Null(response.Headers.Location);
+        }
+
+        [Theory]
+        [InlineData("http://example.com/", "http://www.example.com/")]
+        [InlineData("https://example.com/", "https://www.example.com/")]
+        [InlineData("http://example.com:8081", "http://www.example.com:8081/")]
+        [InlineData("http://example.com:8081/example?q=1", "http://www.example.com:8081/example?q=1")]
+        public async Task CheckRedirectToWwwInWhitelistedDomains(string requestUri, string redirectUri)
+        {
+            var options = new RewriteOptions().AddRedirectToWww("example.com");
+            var builder = new WebHostBuilder()
+                .Configure(app =>
+                {
+                    app.UseRewriter(options);
+                });
+            var server = new TestServer(builder);
+
+            var response = await server.CreateClient().GetAsync(new Uri(requestUri));
+
+            Assert.Equal(redirectUri, response.Headers.Location.OriginalString);
+            Assert.Equal(StatusCodes.Status307TemporaryRedirect, (int)response.StatusCode);
+        }
+
+        [Fact]
+        public async Task CheckPermanentRedirectToWwwInWhitelistedDomains()
+        {
+            var options = new RewriteOptions().AddRedirectToWwwPermanent("example.com");
+            var builder = new WebHostBuilder()
+                .Configure(app =>
+                {
+                    app.UseRewriter(options);
+                });
+            var server = new TestServer(builder);
+
+            var response = await server.CreateClient().GetAsync(new Uri("https://example.com"));
+
+            Assert.Equal("https://www.example.com/", response.Headers.Location.OriginalString);
+            Assert.Equal(StatusCodes.Status308PermanentRedirect, (int)response.StatusCode);
+        }
+
+        [Theory]
+        [InlineData(StatusCodes.Status301MovedPermanently)]
+        [InlineData(StatusCodes.Status302Found)]
+        [InlineData(StatusCodes.Status307TemporaryRedirect)]
+        [InlineData(StatusCodes.Status308PermanentRedirect)]
+        public async Task CheckRedirectToWwwWithStatusCodeInWhitelistedDomains(int statusCode)
+        {
+            var options = new RewriteOptions().AddRedirectToWww(statusCode: statusCode, "example.com");
+            var builder = new WebHostBuilder()
+            .Configure(app =>
+            {
+                app.UseRewriter(options);
+            });
+            var server = new TestServer(builder);
+
+            var response = await server.CreateClient().GetAsync(new Uri("https://example.com"));
+
+            Assert.Equal("https://www.example.com/", response.Headers.Location.OriginalString);
+            Assert.Equal(statusCode, (int)response.StatusCode);
+        }
+
     }
 }