Add option to limit domains on AddRedirectToWww (#9676)

This commit is contained in:
Bruno 2019-05-15 03:33:03 +12:00 committed by Justin Kotalik
parent 2ed7be91e0
commit 124064ef47
4 changed files with 157 additions and 0 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}