Modifies .Rewrite and .Redirect to use normal regex syntax for backreferences

This commit is contained in:
Justin Kotalik 2016-08-29 13:55:44 -07:00
parent 28133b6808
commit 4a06b37280
12 changed files with 305 additions and 239 deletions

View File

@ -27,7 +27,7 @@ namespace RewriteSample
// TODO make this startup do something useful. // TODO make this startup do something useful.
app.UseRewriter(new RewriteOptions() app.UseRewriter(new RewriteOptions()
.Rewrite(@"foo/(\d+)", "foo?id={R:1}") .Rewrite(@"foo/(\d+)", "foo?id=$1")
.ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml") .ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml")
.ImportFromModRewrite(hostingEnv, "Rewrite.txt")); .ImportFromModRewrite(hostingEnv, "Rewrite.txt"));

View File

@ -0,0 +1,66 @@
// 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.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules
{
public class RedirectRule : Rule
{
private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1);
public Regex InitialMatch { get; }
public string Replacement { get; }
public int StatusCode { get; }
public RedirectRule(string regex, string replacement, int statusCode)
{
InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout);
Replacement = replacement;
StatusCode = statusCode;
}
public override void ApplyRule(RewriteContext context)
{
var path = context.HttpContext.Request.Path;
Match initMatchResults;
if (path == PathString.Empty)
{
initMatchResults = InitialMatch.Match(path.ToString());
}
else
{
initMatchResults = InitialMatch.Match(path.ToString().Substring(1));
}
if (initMatchResults.Success)
{
var newPath = initMatchResults.Result(Replacement);
var response = context.HttpContext.Response;
response.StatusCode = StatusCode;
if (newPath.IndexOf("://", StringComparison.Ordinal) == -1 && !newPath.StartsWith("/"))
{
newPath = '/' + newPath;
}
var split = newPath.IndexOf('?');
if (split >= 0)
{
var query = context.HttpContext.Request.QueryString.Add(
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;
}
else
{
response.Headers[HeaderNames.Location] = newPath;
}
context.Result = RuleTermination.ResponseComplete;
}
}
}
}

View File

@ -0,0 +1,94 @@
// 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.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules
{
public class RewriteRule : Rule
{
private readonly string ForwardSlash = "/";
private readonly TimeSpan _regexTimeout = TimeSpan.FromSeconds(1);
public Regex InitialMatch { get; }
public string Replacement { get; }
public bool StopProcessing { get; }
public RewriteRule(string regex, string replacement, bool stopProcessing)
{
InitialMatch = new Regex(regex, RegexOptions.Compiled | RegexOptions.CultureInvariant, _regexTimeout);
Replacement = replacement;
StopProcessing = stopProcessing;
}
public override void ApplyRule(RewriteContext context)
{
var path = context.HttpContext.Request.Path;
Match initMatchResults;
if (path == PathString.Empty)
{
initMatchResults = InitialMatch.Match(path.ToString());
}
else
{
initMatchResults = InitialMatch.Match(path.ToString().Substring(1));
}
if (initMatchResults.Success)
{
var result = initMatchResults.Result(Replacement);
var request = context.HttpContext.Request;
if (result.IndexOf("://", StringComparison.Ordinal) >= 0)
{
string scheme;
HostString host;
PathString pathString;
QueryString query;
FragmentString fragment;
UriHelper.FromAbsolute(result, out scheme, out host, out pathString, out query, out fragment);
request.Scheme = scheme;
request.Host = host;
request.Path = pathString;
request.QueryString = query.Add(request.QueryString);
}
else
{
var split = result.IndexOf('?');
if (split >= 0)
{
var newPath = result.Substring(0, split);
if (newPath.StartsWith(ForwardSlash))
{
request.Path = PathString.FromUriComponent(newPath);
}
else
{
request.Path = PathString.FromUriComponent(ForwardSlash + newPath);
}
request.QueryString = request.QueryString.Add(
QueryString.FromUriComponent(
result.Substring(split)));
}
else
{
if (result.StartsWith(ForwardSlash))
{
request.Path = PathString.FromUriComponent(result);
}
else
{
request.Path = PathString.FromUriComponent(ForwardSlash + result);
}
}
}
if (StopProcessing)
{
context.Result = RuleTermination.StopRules;
}
}
}
}
}

View File

@ -1,70 +0,0 @@
// 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 Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
{
public class ModRewriteRedirectAction : UrlAction
{
public int StatusCode { get; }
public bool QueryStringAppend { get; }
public bool QueryStringDelete { get; }
public bool EscapeBackReferences { get; }
public ModRewriteRedirectAction(
int statusCode,
Pattern pattern,
bool queryStringAppend,
bool queryStringDelete,
bool escapeBackReferences)
{
StatusCode = statusCode;
Url = pattern;
QueryStringAppend = queryStringAppend;
QueryStringDelete = queryStringDelete;
EscapeBackReferences = escapeBackReferences;
}
public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch)
{
var pattern = Url.Evaluate(context, ruleMatch, condMatch);
if (EscapeBackReferences)
{
// because escapebackreferences will be encapsulated by the pattern, just escape the pattern
pattern = Uri.EscapeDataString(pattern);
}
context.HttpContext.Response.StatusCode = StatusCode;
// url can either contain the full url or the path and query
// always add to location header.
// TODO check for false positives
var split = pattern.IndexOf('?');
if (split >= 0 && QueryStringAppend)
{
var query = context.HttpContext.Request.QueryString.Add(
QueryString.FromUriComponent(
pattern.Substring(split)));
// not using the response.redirect here because status codes may be 301, 302, 307, 308
context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query;
}
else
{
// If the request url has a query string and the target does not, append the query string
// by default.
if (QueryStringDelete)
{
context.HttpContext.Response.Headers[HeaderNames.Location] = pattern;
}
else
{
context.HttpContext.Response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString;
}
}
context.Result = RuleTermination.ResponseComplete;
}
}
}

View File

@ -1,113 +0,0 @@
// 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 Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
{
public class ModRewriteRewriteAction : UrlAction
{
private readonly string ForwardSlash = "/";
public RuleTermination Result { get; }
public bool QueryStringAppend { get; }
public bool QueryStringDelete { get; }
public bool EscapeBackReferences { get; }
public ModRewriteRewriteAction(
RuleTermination result,
Pattern pattern,
bool queryStringAppend,
bool queryStringDelete,
bool escapeBackReferences)
{
Result = result;
Url = pattern;
QueryStringAppend = queryStringAppend;
QueryStringDelete = queryStringDelete;
EscapeBackReferences = escapeBackReferences;
}
public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch)
{
var pattern = Url.Evaluate(context, ruleMatch, condMatch);
// TODO PERF, substrings, object creation, etc.
if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0)
{
string scheme;
HostString host;
PathString path;
QueryString query;
FragmentString fragment;
UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment);
if (query.HasValue)
{
if (QueryStringAppend)
{
context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(query);
}
else
{
context.HttpContext.Request.QueryString = query;
}
}
else if (QueryStringDelete)
{
context.HttpContext.Request.QueryString = QueryString.Empty;
}
context.HttpContext.Request.Scheme = scheme;
context.HttpContext.Request.Host = host;
context.HttpContext.Request.Path = path;
}
else
{
var split = pattern.IndexOf('?');
if (split >= 0)
{
var path = pattern.Substring(0, split);
if (path.StartsWith(ForwardSlash))
{
context.HttpContext.Request.Path = PathString.FromUriComponent(path);
}
else
{
context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path);
}
if (QueryStringAppend)
{
context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(
QueryString.FromUriComponent(
pattern.Substring(split)));
}
else
{
context.HttpContext.Request.QueryString = QueryString.FromUriComponent(
pattern.Substring(split));
}
}
else
{
if (pattern.StartsWith(ForwardSlash))
{
context.HttpContext.Request.Path = PathString.FromUriComponent(pattern);
}
else
{
context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern);
}
if (QueryStringDelete)
{
context.HttpContext.Request.QueryString = QueryString.Empty;
}
}
}
context.Result = Result;
}
}
}

View File

@ -210,13 +210,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
{ {
throw new FormatException(Resources.FormatError_InputParserInvalidInteger(statusCode, -1)); throw new FormatException(Resources.FormatError_InputParserInvalidInteger(statusCode, -1));
} }
_action = new ModRewriteRedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference); _action = new RedirectAction(res, pattern, queryStringAppend, queryStringDelete, escapeBackReference);
} }
else else
{ {
var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last); var last = flags.HasFlag(FlagType.End) || flags.HasFlag(FlagType.Last);
var termination = last ? RuleTermination.StopRules : RuleTermination.Continue; var termination = last ? RuleTermination.StopRules : RuleTermination.Continue;
_action = new ModRewriteRewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference); _action = new RewriteAction(termination, pattern, queryStringAppend, queryStringDelete, escapeBackReference);
} }
} }
} }

View File

@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
@ -10,41 +12,80 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
public class RedirectAction : UrlAction public class RedirectAction : UrlAction
{ {
public int StatusCode { get; } public int StatusCode { get; }
public bool AppendQueryString { get; } public bool QueryStringAppend { get; }
public bool QueryStringDelete { get; }
public bool EscapeBackReferences { get; }
public RedirectAction(int statusCode, Pattern pattern, bool appendQueryString) public RedirectAction(
int statusCode,
Pattern pattern,
bool queryStringAppend,
bool queryStringDelete,
bool escapeBackReferences)
{ {
StatusCode = statusCode; StatusCode = statusCode;
Url = pattern; Url = pattern;
AppendQueryString = appendQueryString; QueryStringAppend = queryStringAppend;
QueryStringDelete = queryStringDelete;
EscapeBackReferences = escapeBackReferences;
}
public RedirectAction(
int statusCode,
Pattern pattern,
bool queryStringAppend)
: this(
statusCode,
pattern,
queryStringAppend,
queryStringDelete: true,
escapeBackReferences: false)
{
} }
public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch)
{ {
var pattern = Url.Evaluate(context, ruleMatch, condMatch); var pattern = Url.Evaluate(context, ruleMatch, condMatch);
context.HttpContext.Response.StatusCode = StatusCode; var response = context.HttpContext.Response;
if (EscapeBackReferences)
{
// because escapebackreferences will be encapsulated by the pattern, just escape the pattern
pattern = Uri.EscapeDataString(pattern);
}
// TODO IIS guarantees that there will be a leading slash
if (pattern.IndexOf("://", StringComparison.Ordinal) == -1 && !pattern.StartsWith("/")) if (pattern.IndexOf("://", StringComparison.Ordinal) == -1 && !pattern.StartsWith("/"))
{ {
pattern = '/' + pattern; pattern = '/' + pattern;
} }
response.StatusCode = StatusCode;
// url can either contain the full url or the path and query // url can either contain the full url or the path and query
// always add to location header. // always add to location header.
// TODO check for false positives // TODO check for false positives
var split = pattern.IndexOf('?'); var split = pattern.IndexOf('?');
if (split >= 0 && AppendQueryString) if (split >= 0 && QueryStringAppend)
{ {
var query = context.HttpContext.Request.QueryString.Add( var query = context.HttpContext.Request.QueryString.Add(
QueryString.FromUriComponent( QueryString.FromUriComponent(
pattern.Substring(split))); pattern.Substring(split)));
// not using the HttpContext.Response.redirect here because status codes may be 301, 302, 307, 308
context.HttpContext.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query; // not using the response.redirect here because status codes may be 301, 302, 307, 308
response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query;
} }
else else
{ {
context.HttpContext.Response.Headers[HeaderNames.Location] = pattern; // If the request url has a query string and the target does not, append the query string
// by default.
if (QueryStringDelete)
{
response.Headers[HeaderNames.Location] = pattern;
}
else
{
response.Headers[HeaderNames.Location] = pattern + context.HttpContext.Request.QueryString;
}
} }
context.Result = RuleTermination.ResponseComplete; context.Result = RuleTermination.ResponseComplete;
} }

View File

@ -11,24 +11,48 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
{ {
private readonly string ForwardSlash = "/"; private readonly string ForwardSlash = "/";
public RuleTermination Result { get; } public RuleTermination Result { get; }
public bool ClearQuery { get; } public bool QueryStringAppend { get; }
public bool QueryStringDelete { get; }
public bool EscapeBackReferences { get; }
public RewriteAction(RuleTermination result, Pattern pattern, bool clearQuery) public RewriteAction(
RuleTermination result,
Pattern pattern,
bool queryStringAppend,
bool queryStringDelete,
bool escapeBackReferences)
{ {
Result = result; Result = result;
Url = pattern; Url = pattern;
ClearQuery = clearQuery; QueryStringAppend = queryStringAppend;
QueryStringDelete = queryStringDelete;
EscapeBackReferences = escapeBackReferences;
}
public RewriteAction(
RuleTermination result,
Pattern pattern,
bool queryStringAppend):
this (result,
pattern,
queryStringAppend,
queryStringDelete: false,
escapeBackReferences: false)
{
} }
public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) public override void ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch)
{ {
var pattern = Url.Evaluate(context, ruleMatch, condMatch); var pattern = Url.Evaluate(context, ruleMatch, condMatch);
var request = context.HttpContext.Request;
if (ClearQuery) if (EscapeBackReferences)
{ {
context.HttpContext.Request.QueryString = QueryString.Empty; // because escapebackreferences will be encapsulated by the pattern, just escape the pattern
pattern = Uri.EscapeDataString(pattern);
} }
// TODO PERF, substrings, object creation, etc.
if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0)
{ {
string scheme; string scheme;
@ -38,10 +62,25 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
FragmentString fragment; FragmentString fragment;
UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment); UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment);
context.HttpContext.Request.Scheme = scheme; if (query.HasValue)
context.HttpContext.Request.Host = host; {
context.HttpContext.Request.Path = path; if (QueryStringAppend)
context.HttpContext.Request.QueryString = query.Add(context.HttpContext.Request.QueryString); {
request.QueryString = request.QueryString.Add(query);
}
else
{
request.QueryString = query;
}
}
else if (QueryStringDelete)
{
request.QueryString = QueryString.Empty;
}
request.Scheme = scheme;
request.Host = host;
request.Path = path;
} }
else else
{ {
@ -51,25 +90,39 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions
var path = pattern.Substring(0, split); var path = pattern.Substring(0, split);
if (path.StartsWith(ForwardSlash)) if (path.StartsWith(ForwardSlash))
{ {
context.HttpContext.Request.Path = PathString.FromUriComponent(path); request.Path = PathString.FromUriComponent(path);
} }
else else
{ {
context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + path); request.Path = PathString.FromUriComponent(ForwardSlash + path);
}
if (QueryStringAppend)
{
request.QueryString = request.QueryString.Add(
QueryString.FromUriComponent(
pattern.Substring(split)));
}
else
{
request.QueryString = QueryString.FromUriComponent(
pattern.Substring(split));
} }
context.HttpContext.Request.QueryString = context.HttpContext.Request.QueryString.Add(
QueryString.FromUriComponent(
pattern.Substring(split)));
} }
else else
{ {
if (pattern.StartsWith(ForwardSlash)) if (pattern.StartsWith(ForwardSlash))
{ {
context.HttpContext.Request.Path = PathString.FromUriComponent(pattern); request.Path = PathString.FromUriComponent(pattern);
} }
else else
{ {
context.HttpContext.Request.Path = PathString.FromUriComponent(ForwardSlash + pattern); request.Path = PathString.FromUriComponent(ForwardSlash + pattern);
}
if (QueryStringDelete)
{
request.QueryString = QueryString.Empty;
} }
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions;
using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches;
@ -46,7 +47,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
break; break;
case ActionType.Rewrite: case ActionType.Rewrite:
_action = new RewriteAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue, _action = new RewriteAction(stopProcessing ? RuleTermination.StopRules : RuleTermination.Continue,
url, clearQuery: !appendQueryString); url, appendQueryString);
break; break;
case ActionType.Redirect: case ActionType.Redirect:
_action = new RedirectAction(statusCode, url, appendQueryString); _action = new RedirectAction(statusCode, url, appendQueryString);

View File

@ -42,11 +42,11 @@ namespace Microsoft.AspNetCore.Rewrite
/// </summary> /// </summary>
/// <param name="options">The Rewrite options.</param> /// <param name="options">The Rewrite options.</param>
/// <param name="regex">The regex string to compare with.</param> /// <param name="regex">The regex string to compare with.</param>
/// <param name="urlPattern">If the regex matches, what to replace HttpContext with.</param> /// <param name="replacement">If the regex matches, what to replace HttpContext with.</param>
/// <returns>The Rewrite options.</returns> /// <returns>The Rewrite options.</returns>
public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string urlPattern) public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string replacement)
{ {
return Rewrite(options, regex, urlPattern, stopProcessing: false); return Rewrite(options, regex, replacement, stopProcessing: false);
} }
/// <summary> /// <summary>
@ -54,17 +54,12 @@ namespace Microsoft.AspNetCore.Rewrite
/// </summary> /// </summary>
/// <param name="options">The Rewrite options.</param> /// <param name="options">The Rewrite options.</param>
/// <param name="regex">The regex string to compare with.</param> /// <param name="regex">The regex string to compare with.</param>
/// <param name="urlPattern">If the regex matches, what to replace the uri with.</param> /// <param name="replacement">If the regex matches, what to replace the uri with.</param>
/// <param name="stopProcessing">If the regex matches, conditionally stop processing other rules.</param> /// <param name="stopProcessing">If the regex matches, conditionally stop processing other rules.</param>
/// <returns>The Rewrite options.</returns> /// <returns>The Rewrite options.</returns>
public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string urlPattern, bool stopProcessing) public static RewriteOptions Rewrite(this RewriteOptions options, string regex, string replacement, bool stopProcessing)
{ {
var builder = new UrlRewriteRuleBuilder(); options.Rules.Add(new RewriteRule(regex, replacement, stopProcessing));
var pattern = new InputParser().ParseInputString(urlPattern);
builder.AddUrlMatch(regex);
builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing);
options.Rules.Add(builder.Build());
return options; return options;
} }
@ -73,11 +68,11 @@ namespace Microsoft.AspNetCore.Rewrite
/// </summary> /// </summary>
/// <param name="options">The Rewrite options.</param> /// <param name="options">The Rewrite options.</param>
/// <param name="regex">The regex string to compare with.</param> /// <param name="regex">The regex string to compare with.</param>
/// <param name="urlPattern">If the regex matches, what to replace the uri with.</param> /// <param name="replacement">If the regex matches, what to replace the uri with.</param>
/// <returns>The Rewrite options.</returns> /// <returns>The Rewrite options.</returns>
public static RewriteOptions Redirect(this RewriteOptions options, string regex, string urlPattern) public static RewriteOptions Redirect(this RewriteOptions options, string regex, string replacement)
{ {
return Redirect(options, regex, urlPattern, statusCode: 302); return Redirect(options, regex, replacement, statusCode: 302);
} }
/// <summary> /// <summary>
@ -85,21 +80,19 @@ namespace Microsoft.AspNetCore.Rewrite
/// </summary> /// </summary>
/// <param name="options">The Rewrite options.</param> /// <param name="options">The Rewrite options.</param>
/// <param name="regex">The regex string to compare with.</param> /// <param name="regex">The regex string to compare with.</param>
/// <param name="urlPattern">If the regex matches, what to replace the uri with.</param> /// <param name="replacement">If the regex matches, what to replace the uri with.</param>
/// <param name="statusCode">The status code to add to the response.</param> /// <param name="statusCode">The status code to add to the response.</param>
/// <returns>The Rewrite options.</returns> /// <returns>The Rewrite options.</returns>
public static RewriteOptions Redirect(this RewriteOptions options, string regex, string urlPattern, int statusCode) public static RewriteOptions Redirect(this RewriteOptions options, string regex, string replacement, int statusCode)
{ {
var builder = new UrlRewriteRuleBuilder(); options.Rules.Add(new RedirectRule(regex, replacement, statusCode));
var pattern = new InputParser().ParseInputString(urlPattern);
builder.AddUrlMatch(regex);
builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: false);
options.Rules.Add(builder.Build());
return options; return options;
} }
// TODO 301 overload public static RewriteOptions RedirectToHttpsPermanent(this RewriteOptions options)
{
return RedirectToHttps(options, statusCode: 301, sslPort: null);
}
/// <summary> /// <summary>
/// Redirect a request to https if the incoming request is http /// Redirect a request to https if the incoming request is http

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules
[Fact] [Fact]
public async Task CheckRewritePath() public async Task CheckRewritePath()
{ {
var options = new RewriteOptions().Rewrite("(.*)", "http://example.com/{R:1}"); var options = new RewriteOptions().Rewrite("(.*)", "http://example.com/$1");
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.Configure(app => .Configure(app =>
{ {
@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.CodeRules
[Fact] [Fact]
public async Task CheckRedirectPath() public async Task CheckRedirectPath()
{ {
var options = new RewriteOptions().Redirect("(.*)","http://example.com/{R:1}", statusCode: 301); var options = new RewriteOptions().Redirect("(.*)","http://example.com/$1", statusCode: 301);
var builder = new WebHostBuilder() var builder = new WebHostBuilder()
.Configure(app => .Configure(app =>
{ {

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal;
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions;
using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches;
using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite;
@ -146,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
) )
{ {
return new UrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions, return new UrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions,
new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), clearQuery: false)); new RewriteAction(RuleTermination.Continue, new InputParser().ParseInputString(url), queryStringAppend: false));
} }
// TODO make rules comparable? // TODO make rules comparable?