IIS UrlRewrite Rule Application
This commit is contained in:
parent
bb4f5420d3
commit
5052a94cf7
|
|
@ -1,4 +1,8 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
// 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.IO;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite;
|
||||
|
|
@ -9,7 +13,7 @@ namespace RewriteSample
|
|||
{
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment hostingEnv)
|
||||
{
|
||||
app.UseRewriter(new UrlRewriteOptions()
|
||||
app.UseRewriter(new RewriteOptions()
|
||||
.ImportFromUrlRewrite(hostingEnv, "UrlRewrite.xml")
|
||||
.ImportFromModRewrite(hostingEnv, "Rewrite.txt"));
|
||||
app.Run(context => context.Response.WriteAsync(context.Request.Path));
|
||||
|
|
@ -21,6 +25,7 @@ namespace RewriteSample
|
|||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseStartup<Startup>()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Fail bad requests">
|
||||
<match url=".*"/>
|
||||
<rule name="Query String Rewrite">
|
||||
<match url="page\.asp$" />
|
||||
<conditions>
|
||||
<add input="{HTTP_HOST}" pattern="localhost" negate="true" />
|
||||
<add input="{QUERY_STRING}" pattern="p1=(\d+)" />
|
||||
<add input="##{C:1}##_{QUERY_STRING}" pattern="##([^#]+)##_.*p2=(\d+)" />
|
||||
</conditions>
|
||||
<action type="AbortRequest" />
|
||||
</rule>
|
||||
<rule name="Redirect from blog">
|
||||
<match url="^blog/([_0-9a-z-]+)/([0-9]+)" />
|
||||
<action type="Redirect" url="article/{R:2}/{R:1}" redirectType="Found" />
|
||||
</rule>
|
||||
<rule name="Rewrite to article.aspx">
|
||||
<match url="^article/([0-9]+)/([_0-9a-z-]+)" />
|
||||
<action type="Rewrite" url="article.aspx?id={R:1}&title={R:2}" />
|
||||
<action type="rewrite" url="newpage.aspx?param1={C:1}&param2={C:2}" appendQueryString="false"/>
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
|
|
@ -4,21 +4,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Rewrite.RuleAbstraction;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// The builder to a list of rules for <see cref="UrlRewriteOptions"/> and <see cref="UrlRewriteMiddleware"/>
|
||||
/// The builder to a list of rules for <see cref="RewriteOptions"/> and <see cref="RewriteMiddleware"/>
|
||||
/// </summary>
|
||||
public static class UrlRewriteOptionsAddRulesExtensions
|
||||
public static class CodeRewriteExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a rule to the current rules.
|
||||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="rule">A rule to be added to the current rules.</param>
|
||||
public static UrlRewriteOptions AddRule(this UrlRewriteOptions options, Rule rule)
|
||||
public static RewriteOptions AddRule(this RewriteOptions options, Rule rule)
|
||||
{
|
||||
options.Rules.Add(rule);
|
||||
return options;
|
||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="rules">A list of rules.</param>
|
||||
public static UrlRewriteOptions AddRules(this UrlRewriteOptions options, List<Rule> rules)
|
||||
public static RewriteOptions AddRules(this RewriteOptions options, List<Rule> rules)
|
||||
{
|
||||
options.Rules.AddRange(rules);
|
||||
return options;
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <param name="newPath">The string to replace the path with (with capture parameters).</param>
|
||||
/// <param name="stopRewriteOnSuccess">Whether or not to stop rewriting on success of rule.</param>
|
||||
/// <returns></returns>
|
||||
public static UrlRewriteOptions RewritePath(this UrlRewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false)
|
||||
public static RewriteOptions RewritePath(this RewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false)
|
||||
{
|
||||
options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite });
|
||||
return options;
|
||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <param name="options">The Url rewrite options.</param>
|
||||
/// <param name="stopRewriteOnSuccess">Whether or not to stop rewriting on success of rule.</param>
|
||||
/// <returns></returns>
|
||||
public static UrlRewriteOptions RewriteScheme(this UrlRewriteOptions options, bool stopRewriteOnSuccess = false)
|
||||
public static RewriteOptions RewriteScheme(this RewriteOptions options, bool stopRewriteOnSuccess = false)
|
||||
{
|
||||
options.Rules.Add(new SchemeRule {OnCompletion = stopRewriteOnSuccess ? Transformation.TerminatingRewrite : Transformation.Rewrite });
|
||||
return options;
|
||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <param name="newPath">The string to replace the path with (with capture parameters).</param>
|
||||
/// <param name="stopRewriteOnSuccess">Whether or not to stop rewriting on success of rule.</param>
|
||||
/// <returns></returns>
|
||||
public static UrlRewriteOptions RedirectPath(this UrlRewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false)
|
||||
public static RewriteOptions RedirectPath(this RewriteOptions options, string regex, string newPath, bool stopRewriteOnSuccess = false)
|
||||
{
|
||||
options.Rules.Add(new PathRule { MatchPattern = new Regex(regex, RegexOptions.Compiled, TimeSpan.FromMilliseconds(1)), OnMatch = newPath, OnCompletion = Transformation.Redirect });
|
||||
return options;
|
||||
|
|
@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <param name="options">The Url rewrite options.</param>
|
||||
/// <param name="sslPort">The port to redirect the scheme to.</param>
|
||||
/// <returns></returns>
|
||||
public static UrlRewriteOptions RedirectScheme(this UrlRewriteOptions options, int? sslPort)
|
||||
public static RewriteOptions RedirectScheme(this RewriteOptions options, int? sslPort)
|
||||
{
|
||||
options.Rules.Add(new SchemeRule { SSLPort = sslPort, OnCompletion = Transformation.Redirect });
|
||||
return options;
|
||||
|
|
@ -95,7 +95,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <param name="transform"></param>
|
||||
/// <param name="description"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlRewriteOptions CustomRule(this UrlRewriteOptions options, Func<UrlRewriteContext, RuleResult> onApplyRule, Transformation transform, string description = null)
|
||||
public static RewriteOptions CustomRule(this RewriteOptions options, Func<RewriteContext, RuleResult> onApplyRule, Transformation transform, string description = null)
|
||||
{
|
||||
options.Rules.Add(new FunctionalRule { OnApplyRule = onApplyRule, OnCompletion = transform});
|
||||
return options;
|
||||
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public class FunctionalRule : Rule
|
||||
{
|
||||
public Func<UrlRewriteContext, RuleResult> OnApplyRule { get; set; }
|
||||
public Func<RewriteContext, RuleResult> OnApplyRule { get; set; }
|
||||
public Transformation OnCompletion { get; set; } = Transformation.Rewrite;
|
||||
public override RuleResult ApplyRule(UrlRewriteContext context) => OnApplyRule(context);
|
||||
public override RuleResult ApplyRule(RewriteContext context) => OnApplyRule(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public class Condition
|
||||
{
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public class ConditionBuilder
|
||||
{
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Rewrite.Operands;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the ConditionPattern for a mod_rewrite rule.
|
||||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
/// <param name="previous">The previous condition results (for backreferences).</param>
|
||||
/// <param name="testString">The testString created from the <see cref="Pattern"/>.</param>
|
||||
/// <returns>If the testString satisfies the condition</returns>
|
||||
public bool? CheckConditionExpression(UrlRewriteContext context, Match previous, string testString)
|
||||
public bool? CheckConditionExpression(RewriteContext context, Match previous, string testString)
|
||||
{
|
||||
return Operand.CheckOperation(previous, testString, context.FileProvider) ^ Invert;
|
||||
}
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public enum ConditionFlagType
|
||||
{
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
// TODO Refactor Condition Flags and Rule Flags under base flag class
|
||||
public class ConditionFlags
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses the "CondPattern" portion of the RewriteCond.
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses the TestString segment of the mod_rewrite condition.
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public enum ConditionType
|
||||
{
|
||||
|
|
@ -3,10 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Rewrite.Operands;
|
||||
using Microsoft.AspNetCore.Rewrite.RuleAbstraction;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a parsed expression into a mod_rewrite condition.
|
||||
|
|
@ -4,9 +4,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Rewrite.RuleAbstraction;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses the flags
|
||||
|
|
@ -6,7 +6,7 @@ using System.Globalization;
|
|||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public class IntegerOperand : Operand
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public enum IntegerOperationType
|
||||
{
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public abstract class Operand
|
||||
{
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public class PropertyOperand : Operand
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public enum PropertyOperationType
|
||||
{
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public class RegexOperand : Operand
|
||||
{
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public class StringOperand : Operand
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Operands
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands
|
||||
{
|
||||
public enum StringOperationType
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public enum OperationType
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public class ParsedModRewriteExpression
|
||||
{
|
||||
|
|
@ -1,14 +1,12 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.ModRewrite;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a sequence of pattern segments, which on obtaining the context, will create the appropriate
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// A Pattern segment contains a portion of the test string/ substitution segment with a type associated.
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public class RuleBuilder
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public enum RuleFlagType
|
||||
{
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public class RuleFlags
|
||||
{
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public static class RuleRegexParser
|
||||
{
|
||||
|
|
@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// mod_rewrite lookups for specific string constants.
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Tokenizes a mod_rewrite rule, delimited by spaces.
|
||||
|
|
@ -6,9 +6,8 @@ using System.Collections.Generic;
|
|||
using Microsoft.Net.Http.Headers;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.RuleAbstraction;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
|
||||
{
|
||||
public class ModRewriteRule : Rule
|
||||
{
|
||||
|
|
@ -28,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
Description = description;
|
||||
}
|
||||
|
||||
public override RuleResult ApplyRule(UrlRewriteContext context)
|
||||
public override RuleResult ApplyRule(RewriteContext context)
|
||||
{
|
||||
// 1. Figure out which section of the string to match for the initial rule.
|
||||
var results = InitialRule.Operand.RegexOperation.Match(context.HttpContext.Request.Path.ToString());
|
||||
|
|
@ -36,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
string flagRes = null;
|
||||
if (CheckMatchResult(results.Success))
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.Continue };
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
|
||||
if (Flags.HasFlag(RuleFlagType.EscapeBackreference))
|
||||
|
|
@ -49,7 +48,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
|
||||
if (!CheckCondition(context, results, previous))
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.Continue };
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
// TODO add chained flag
|
||||
|
||||
|
|
@ -82,12 +81,12 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
if (Flags.HasFlag(RuleFlagType.Forbidden))
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
return new RuleResult { Result = RuleTerminiation.ResponseComplete };
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
else if (Flags.HasFlag(RuleFlagType.Gone))
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCodes.Status410Gone;
|
||||
return new RuleResult { Result = RuleTerminiation.ResponseComplete };
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
else if (result == "-")
|
||||
{
|
||||
|
|
@ -124,7 +123,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
context.HttpContext.Response.Headers[HeaderNames.Location] = "/" + result + context.HttpContext.Request.QueryString;
|
||||
}
|
||||
}
|
||||
return new RuleResult { Result = RuleTerminiation.ResponseComplete };
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -145,11 +144,11 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
}
|
||||
if (Flags.HasFlag(RuleFlagType.Last) || Flags.HasFlag(RuleFlagType.End))
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.StopRules };
|
||||
return RuleResult.StopRules;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.Continue };
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,7 +162,7 @@ namespace Microsoft.AspNetCore.Rewrite.ModRewrite
|
|||
return !(result.Value ^ InitialRule.Invert);
|
||||
}
|
||||
|
||||
private bool CheckCondition(UrlRewriteContext context, Match results, Match previous)
|
||||
private bool CheckCondition(RewriteContext context, Match results, Match previous)
|
||||
{
|
||||
if (Conditions == null)
|
||||
{
|
||||
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public class PathRule : Rule
|
||||
{
|
||||
public Regex MatchPattern { get; set; }
|
||||
public string OnMatch { get; set; }
|
||||
public Transformation OnCompletion { get; set; } = Transformation.Rewrite;
|
||||
public override RuleResult ApplyRule(UrlRewriteContext context)
|
||||
public override RuleResult ApplyRule(RewriteContext context)
|
||||
{
|
||||
var matches = MatchPattern.Match(context.HttpContext.Request.Path);
|
||||
if (matches.Success)
|
||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
|||
path,
|
||||
req.QueryString);
|
||||
context.HttpContext.Response.Redirect(newUrl);
|
||||
return new RuleResult { Result = RuleTerminiation.ResponseComplete };
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -35,14 +35,14 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
|||
}
|
||||
if (OnCompletion == Transformation.TerminatingRewrite)
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.StopRules };
|
||||
return RuleResult.StopRules;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.Continue };
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
}
|
||||
return new RuleResult { Result = RuleTerminiation.Continue };
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public abstract class Rule
|
||||
{
|
||||
public abstract RuleResult ApplyRule(UrlRewriteContext context);
|
||||
public abstract RuleResult ApplyRule(RewriteContext context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
// 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 Microsoft.AspNetCore.Rewrite.Operands;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public class RuleExpression
|
||||
{
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public class RuleResult
|
||||
{
|
||||
public static RuleResult Continue = new RuleResult { Result = RuleTerminiation.Continue };
|
||||
public static RuleResult ResponseComplete = new RuleResult { Result = RuleTerminiation.ResponseComplete };
|
||||
public static RuleResult StopRules = new RuleResult { Result = RuleTerminiation.StopRules };
|
||||
|
||||
public RuleTerminiation Result { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public class ModRewriteCreatorTest
|
||||
public enum RuleTerminiation
|
||||
{
|
||||
Continue,
|
||||
ResponseComplete,
|
||||
StopRules
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,13 @@
|
|||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public class SchemeRule : Rule
|
||||
{
|
||||
public int? SSLPort { get; set; }
|
||||
public Transformation OnCompletion { get; set; } = Transformation.Rewrite;
|
||||
public override RuleResult ApplyRule(UrlRewriteContext context)
|
||||
public override RuleResult ApplyRule(RewriteContext context)
|
||||
{
|
||||
|
||||
// TODO this only does http to https, add more features in the future.
|
||||
|
|
@ -34,11 +34,11 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
|||
context.HttpContext.Request.Host = host;
|
||||
if (OnCompletion == Transformation.TerminatingRewrite)
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.StopRules };
|
||||
return RuleResult.StopRules;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new RuleResult { Result = RuleTerminiation.Continue };
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,9 +46,9 @@ namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
|||
|
||||
var newUrl = new StringBuilder().Append("https://").Append(host).Append(req.PathBase).Append(req.Path).Append(req.QueryString);
|
||||
context.HttpContext.Response.Redirect(newUrl.ToString());
|
||||
return new RuleResult { Result = RuleTerminiation.ResponseComplete };
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
return new RuleResult { Result = RuleTerminiation.Continue }; ;
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal
|
||||
{
|
||||
public enum Transformation
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public enum ActionType
|
||||
{
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class Condition
|
||||
{
|
||||
public Pattern Input { get; set; }
|
||||
public UrlMatch Match { get; set; }
|
||||
public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
var pattern = Input.Evaluate(context.HttpContext, ruleMatch, condMatch);
|
||||
return Match.Evaluate(pattern, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class Conditions
|
||||
{
|
||||
public List<Condition> ConditionList { get; set; } = new List<Condition>();
|
||||
public LogicalGrouping MatchType { get; set; } // default is MatchAll
|
||||
public bool TrackingAllCaptures { get; set; }
|
||||
|
||||
public MatchResults Evaluate(RewriteContext context, MatchResults ruleMatch)
|
||||
{
|
||||
MatchResults prevCond = null;
|
||||
var success = true;
|
||||
foreach (var condition in ConditionList)
|
||||
{
|
||||
var res = condition.Evaluate(context, ruleMatch, prevCond);
|
||||
success = (MatchType == LogicalGrouping.MatchAll ? (success && res.Success) : (success || res.Success));
|
||||
prevCond = res;
|
||||
}
|
||||
return new MatchResults { Success = success, BackReference = prevCond?.BackReference };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
using Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public enum LogicalGrouping
|
||||
{
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class MatchResults
|
||||
{
|
||||
public GroupCollection BackReference { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public enum MatchType
|
||||
{
|
||||
|
|
@ -1,14 +1,10 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class Condition
|
||||
public class ParsedCondition
|
||||
{
|
||||
public Pattern Input { get; set; }
|
||||
public Regex MatchPattern { get; set; }
|
||||
public bool Negate { get; set; }
|
||||
public bool IgnoreCase { get; set; } = true;
|
||||
public MatchType MatchType { get; set; } = MatchType.Pattern;
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class UrlAction
|
||||
public class ParsedUrlAction
|
||||
{
|
||||
public ActionType Type { get; set; }
|
||||
public Pattern Url { get; set; }
|
||||
public bool AppendQueryString { get; set; }
|
||||
public bool LogRewrittenUrl { get; set; }
|
||||
public bool AppendQueryString { get; set; } = true;
|
||||
public bool LogRewrittenUrl { get; set; } // Ignoring this flag.
|
||||
public RedirectType RedirectType { get; set; } = RedirectType.Permanent;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class RuleResult
|
||||
public class ParsedUrlMatch
|
||||
{
|
||||
public RuleTerminiation Result { get; set; }
|
||||
public bool IgnoreCase { get; set; }
|
||||
public bool Negate { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -3,23 +3,23 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class Pattern
|
||||
{
|
||||
public IList<PatternSegment> PatternSegments { get; }
|
||||
|
||||
public Pattern(List<PatternSegment> patternSegments)
|
||||
{
|
||||
PatternSegments = patternSegments;
|
||||
}
|
||||
|
||||
public string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
var strBuilder = new StringBuilder();
|
||||
|
||||
// TODO consider thread static for string builder - DAVID PERF
|
||||
foreach (var pattern in PatternSegments)
|
||||
{
|
||||
strBuilder.Append(pattern.Evaluate(context, ruleMatch, condMatch));
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public abstract class PatternSegment
|
||||
{
|
||||
// Match from prevRule, Match from prevCond
|
||||
public abstract string Evaluate(HttpContext context, Match ruleMatch, Match condMatch);
|
||||
public abstract string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class ConditionMatchSegment : PatternSegment
|
||||
{
|
||||
|
|
@ -15,9 +14,9 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
|||
Index = index;
|
||||
}
|
||||
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return condMatch?.Groups[Index]?.Value;
|
||||
return condMatch?.BackReference[Index]?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class HeaderSegment : PatternSegment
|
||||
{
|
||||
|
|
@ -15,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
|||
Header = header;
|
||||
}
|
||||
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Request.Headers[Header];
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class IsHttpsSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Request.IsHttps ? "ON" : "OFF";
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class LiteralSegment : PatternSegment
|
||||
{
|
||||
|
|
@ -15,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
|||
Literal = literal;
|
||||
}
|
||||
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return Literal;
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class LocalAddressSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Connection.LocalIpAddress?.ToString();
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class QueryStringSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Request.QueryString.ToString();
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class RemoteAddressSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
|
|
@ -2,14 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class RemotePortSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Connection.RemotePort.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class RequestFileNameSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Request.Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class RuleMatchSegment : PatternSegment
|
||||
{
|
||||
|
|
@ -15,9 +14,9 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
|||
Index = index;
|
||||
}
|
||||
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return ruleMatch?.Groups[Index]?.Value;
|
||||
return ruleMatch?.BackReference[Index]?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class ToLowerSegment : PatternSegment
|
||||
{
|
||||
|
|
@ -15,7 +14,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
|||
Pattern = pattern;
|
||||
}
|
||||
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
var pattern = Pattern.Evaluate(context, ruleMatch, condMatch);
|
||||
return pattern.ToLowerInvariant();
|
||||
|
|
@ -2,10 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class UrlEncodeSegment : PatternSegment
|
||||
{
|
||||
|
|
@ -16,7 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
|||
Pattern = pattern;
|
||||
}
|
||||
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
var pattern = Pattern.Evaluate(context, ruleMatch, condMatch);
|
||||
return UrlEncoder.Default.Encode(pattern);
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments
|
||||
{
|
||||
public class UrlSegment : PatternSegment
|
||||
{
|
||||
public override string Evaluate(HttpContext context, Match ruleMatch, Match condMatch)
|
||||
public override string Evaluate(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return context.Request.Path.ToString();
|
||||
return context.Request.Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public enum PatternSyntax
|
||||
{
|
||||
|
|
@ -1,7 +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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public enum RedirectType
|
||||
{
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public static class RewriteTags
|
||||
{
|
||||
// TODO More strings to be added later once further implementations are added.
|
||||
public const string Rewrite = "rewrite";
|
||||
public const string GlobalRules = "globalRules";
|
||||
public const string Rules = "rules";
|
||||
|
|
@ -27,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
|||
public const string Input = "input";
|
||||
public const string Pattern = "pattern";
|
||||
public const string Type = "type";
|
||||
public const string AppendQuery = "appendQuery";
|
||||
public const string AppendQuery = "appendQueryString";
|
||||
public const string LogRewrittenUrl = "logRewrittenUrl";
|
||||
public const string RedirectType = "redirectType";
|
||||
}
|
||||
|
|
@ -2,16 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.UrlRewrite.PatternSegments;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.PatternSegments;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public static class ServerVariables
|
||||
{
|
||||
{
|
||||
public static PatternSegment FindServerVariable(string serverVariable)
|
||||
{
|
||||
switch(serverVariable)
|
||||
|
|
@ -53,6 +50,8 @@ namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
|||
throw new NotImplementedException();
|
||||
case "REMOTE_PORT":
|
||||
return new RemotePortSegment();
|
||||
case "REQUEST_FILENAME":
|
||||
return new RequestFileNameSegment();
|
||||
default:
|
||||
throw new FormatException("Unrecognized server variable.");
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public abstract class UrlAction
|
||||
{
|
||||
public Pattern Url { get; set; }
|
||||
|
||||
public abstract RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions
|
||||
{
|
||||
public class RedirectAction : UrlAction
|
||||
{
|
||||
public int StatusCode { get; }
|
||||
public RedirectAction(int statusCode, Pattern pattern)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Url = pattern;
|
||||
}
|
||||
|
||||
public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
|
||||
var pattern = Url.Evaluate(context, ruleMatch, condMatch);
|
||||
context.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)
|
||||
{
|
||||
var query = context.Request.QueryString.Add(new QueryString(pattern.Substring(split)));
|
||||
// not using the response.redirect here because status codes may be 301, 302, 307, 308
|
||||
context.Response.Headers[HeaderNames.Location] = pattern.Substring(0, split) + query;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Headers[HeaderNames.Location] = pattern;
|
||||
}
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions
|
||||
{
|
||||
public class RedirectClearQueryAction : UrlAction
|
||||
{
|
||||
public int StatusCode { get; }
|
||||
public RedirectClearQueryAction(int statusCode, Pattern pattern)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Url = pattern;
|
||||
}
|
||||
|
||||
public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
var pattern = Url.Evaluate(context, ruleMatch, condMatch);
|
||||
context.Response.StatusCode = StatusCode;
|
||||
|
||||
// we are clearing the query, so just put the pattern in the location header
|
||||
context.Response.Headers[HeaderNames.Location] = pattern;
|
||||
return RuleResult.ResponseComplete;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions
|
||||
{
|
||||
public class RewriteAction : UrlAction
|
||||
{
|
||||
public RuleTerminiation Result { get; }
|
||||
public bool ClearQuery { get; }
|
||||
|
||||
public RewriteAction(RuleTerminiation result, Pattern pattern, bool clearQuery)
|
||||
{
|
||||
Result = result;
|
||||
Url = pattern;
|
||||
ClearQuery = clearQuery;
|
||||
}
|
||||
|
||||
public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
var pattern = Url.Evaluate(context, ruleMatch, condMatch);
|
||||
|
||||
if (ClearQuery)
|
||||
{
|
||||
context.Request.QueryString = new QueryString();
|
||||
}
|
||||
// TODO PERF, substrings, object creation, etc.
|
||||
if (pattern.IndexOf("://") >= 0)
|
||||
{
|
||||
string scheme = null;
|
||||
var host = new HostString();
|
||||
var path = new PathString();
|
||||
var query = new QueryString();
|
||||
var fragment = new FragmentString();
|
||||
UriHelper.FromAbsolute(pattern, out scheme, out host, out path, out query, out fragment);
|
||||
|
||||
context.Request.Scheme = scheme;
|
||||
context.Request.Host = host;
|
||||
context.Request.Path = path;
|
||||
context.Request.QueryString = query.Add(context.Request.QueryString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var split = pattern.IndexOf('?');
|
||||
if (split >= 0)
|
||||
{
|
||||
context.Request.Path = new PathString("/" + pattern.Substring(0, split));
|
||||
context.Request.QueryString = context.Request.QueryString.Add(new QueryString(pattern.Substring(split)));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Request.Path = new PathString("/" + pattern);
|
||||
}
|
||||
}
|
||||
return new RuleResult { Result = Result };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions
|
||||
{
|
||||
public class VoidAction : UrlAction
|
||||
{
|
||||
// Explicitly say that nothing happens
|
||||
public override RuleResult ApplyAction(HttpContext context, MatchResults ruleMatch, MatchResults condMatch)
|
||||
{
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public abstract class UrlMatch
|
||||
{
|
||||
public bool Negate { get; set; }
|
||||
public abstract MatchResults Evaluate(string input, RewriteContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches
|
||||
{
|
||||
public class ExactMatch : UrlMatch
|
||||
{
|
||||
public bool IgnoreCase { get; }
|
||||
public string StringMatch { get; }
|
||||
|
||||
public ExactMatch(bool ignoreCase, string input, bool negate)
|
||||
{
|
||||
IgnoreCase = ignoreCase;
|
||||
StringMatch = input;
|
||||
Negate = negate;
|
||||
}
|
||||
|
||||
public override MatchResults Evaluate(string pattern, RewriteContext context)
|
||||
{
|
||||
var pathMatch = string.Compare(pattern, StringMatch, IgnoreCase);
|
||||
return new MatchResults { Success = ((pathMatch == 0) != Negate) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches
|
||||
{
|
||||
public class IsDirectoryMatch : UrlMatch
|
||||
{
|
||||
public IsDirectoryMatch( bool negate)
|
||||
{
|
||||
Negate = negate;
|
||||
}
|
||||
|
||||
public override MatchResults Evaluate(string pattern, RewriteContext context)
|
||||
{
|
||||
var res = context.FileProvider.GetFileInfo(pattern).IsDirectory;
|
||||
return new MatchResults { Success = (res != Negate) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches
|
||||
{
|
||||
public class IsFileMatch : UrlMatch
|
||||
{
|
||||
public IsFileMatch(bool negate)
|
||||
{
|
||||
Negate = negate;
|
||||
}
|
||||
|
||||
public override MatchResults Evaluate(string pattern, RewriteContext context)
|
||||
{
|
||||
var res = context.FileProvider.GetFileInfo(pattern).Exists;
|
||||
return new MatchResults { Success = (res != Negate) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches
|
||||
{
|
||||
public class RegexMatch : UrlMatch
|
||||
{
|
||||
private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1);
|
||||
|
||||
public Regex Match { get; }
|
||||
|
||||
public RegexMatch(Regex match, bool negate)
|
||||
{
|
||||
Match = match;
|
||||
Negate = negate;
|
||||
}
|
||||
|
||||
public override MatchResults Evaluate(string pattern, RewriteContext context)
|
||||
{
|
||||
var res = Match.Match(pattern);
|
||||
return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public static class UrlRewriteFileParser
|
||||
{
|
||||
private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1);
|
||||
|
||||
public static List<UrlRewriteRule> Parse(TextReader reader)
|
||||
{
|
||||
var temp = XDocument.Load(reader);
|
||||
var xmlRoot = temp.Descendants(RewriteTags.Rewrite).FirstOrDefault();
|
||||
|
||||
if (xmlRoot != null)
|
||||
{
|
||||
var result = new List<UrlRewriteRule>();
|
||||
// TODO Global rules are currently not treated differently than normal rules, fix.
|
||||
// See: https://github.com/aspnet/BasicMiddleware/issues/59
|
||||
ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, isGlobalRule: true);
|
||||
ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, isGlobalRule: false);
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void ParseRules(XElement rules, List<UrlRewriteRule> result, bool isGlobalRule)
|
||||
{
|
||||
if (rules == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var rule in rules.Elements(RewriteTags.Rule))
|
||||
{
|
||||
var res = new UrlRewriteRule();
|
||||
SetRuleAttributes(rule, res);
|
||||
CreateUrlAction(rule.Element(RewriteTags.Action), res, isGlobalRule);
|
||||
if (res.Enabled)
|
||||
{
|
||||
result.Add(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetRuleAttributes(XElement rule, UrlRewriteRule res)
|
||||
{
|
||||
|
||||
res.Name = rule.Attribute(RewriteTags.Name)?.Value;
|
||||
|
||||
bool enabled;
|
||||
if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled))
|
||||
{
|
||||
res.Enabled = enabled;
|
||||
}
|
||||
|
||||
PatternSyntax patternSyntax;
|
||||
if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax))
|
||||
{
|
||||
res.PatternSyntax = patternSyntax;
|
||||
}
|
||||
|
||||
bool stopProcessing;
|
||||
if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing))
|
||||
{
|
||||
res.StopProcessing = stopProcessing;
|
||||
}
|
||||
|
||||
CreateMatch(rule.Element(RewriteTags.Match), res);
|
||||
CreateConditions(rule.Element(RewriteTags.Conditions), res);
|
||||
}
|
||||
|
||||
private static void CreateMatch(XElement match, UrlRewriteRule res)
|
||||
{
|
||||
if (match == null)
|
||||
{
|
||||
throw new FormatException("Rules must have an associated match.");
|
||||
}
|
||||
|
||||
var matchRes = new ParsedUrlMatch();
|
||||
|
||||
bool parBool;
|
||||
if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool))
|
||||
{
|
||||
matchRes.IgnoreCase = parBool;
|
||||
}
|
||||
|
||||
if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool))
|
||||
{
|
||||
matchRes.Negate = parBool;
|
||||
}
|
||||
|
||||
var parsedInputString = match.Attribute(RewriteTags.Url)?.Value;
|
||||
|
||||
switch (res.PatternSyntax)
|
||||
{
|
||||
case PatternSyntax.ECMAScript:
|
||||
{
|
||||
if (matchRes.IgnoreCase)
|
||||
{
|
||||
var regex = new Regex(parsedInputString, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout);
|
||||
res.InitialMatch = new RegexMatch(regex, matchRes.Negate);
|
||||
}
|
||||
else
|
||||
{
|
||||
var regex = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout);
|
||||
res.InitialMatch = new RegexMatch(regex, matchRes.Negate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PatternSyntax.WildCard:
|
||||
throw new NotImplementedException("Wildcard syntax is not supported.");
|
||||
case PatternSyntax.ExactMatch:
|
||||
res.InitialMatch = new ExactMatch(matchRes.IgnoreCase, parsedInputString, matchRes.Negate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void CreateConditions(XElement conditions, UrlRewriteRule res)
|
||||
{
|
||||
// This is to avoid nullptr exception on referencing conditions.
|
||||
res.Conditions = new Conditions();
|
||||
if (conditions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LogicalGrouping grouping;
|
||||
if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping))
|
||||
{
|
||||
res.Conditions.MatchType = grouping;
|
||||
}
|
||||
|
||||
bool parBool;
|
||||
if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool))
|
||||
{
|
||||
res.Conditions.TrackingAllCaptures = parBool;
|
||||
}
|
||||
|
||||
foreach (var cond in conditions.Elements(RewriteTags.Add))
|
||||
{
|
||||
CreateCondition(cond, res);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateCondition(XElement condition, UrlRewriteRule res)
|
||||
{
|
||||
|
||||
var parsedCondRes = new ParsedCondition();
|
||||
|
||||
bool parBool;
|
||||
if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool))
|
||||
{
|
||||
parsedCondRes.IgnoreCase = parBool;
|
||||
}
|
||||
|
||||
if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool))
|
||||
{
|
||||
parsedCondRes.Negate = parBool;
|
||||
}
|
||||
|
||||
MatchType matchType;
|
||||
if (Enum.TryParse(condition.Attribute(RewriteTags.MatchType)?.Value, out matchType))
|
||||
{
|
||||
parsedCondRes.MatchType = matchType;
|
||||
}
|
||||
|
||||
var parsedString = condition.Attribute(RewriteTags.Input)?.Value;
|
||||
if (parsedString == null)
|
||||
{
|
||||
throw new FormatException("Null input for condition");
|
||||
}
|
||||
|
||||
var input = InputParser.ParseInputString(parsedString);
|
||||
|
||||
switch (res.PatternSyntax)
|
||||
{
|
||||
case PatternSyntax.ECMAScript:
|
||||
{
|
||||
switch (parsedCondRes.MatchType)
|
||||
{
|
||||
case MatchType.Pattern:
|
||||
{
|
||||
parsedString = condition.Attribute(RewriteTags.Pattern)?.Value;
|
||||
if (parsedString == null)
|
||||
{
|
||||
throw new FormatException("Pattern match does not have an associated pattern attribute in condition.");
|
||||
}
|
||||
Regex regex = null;
|
||||
|
||||
if (parsedCondRes.IgnoreCase)
|
||||
{
|
||||
regex = new Regex(parsedString, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
regex = new Regex(parsedString, RegexOptions.Compiled, RegexTimeout);
|
||||
}
|
||||
|
||||
res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, parsedCondRes.Negate) });
|
||||
}
|
||||
break;
|
||||
case MatchType.IsDirectory:
|
||||
{
|
||||
res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new IsDirectoryMatch(parsedCondRes.Negate) });
|
||||
}
|
||||
break;
|
||||
case MatchType.IsFile:
|
||||
{
|
||||
res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new IsFileMatch(parsedCondRes.Negate) });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new FormatException("Unrecognized matchType.");
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case PatternSyntax.WildCard:
|
||||
throw new NotImplementedException("Wildcard syntax is not supported.");
|
||||
case PatternSyntax.ExactMatch:
|
||||
parsedString = condition.Attribute(RewriteTags.Pattern)?.Value;
|
||||
if (parsedString == null)
|
||||
{
|
||||
throw new FormatException("Pattern match does not have an associated pattern attribute in condition.");
|
||||
}
|
||||
res.Conditions.ConditionList.Add(new Condition { Input = input, Match = new ExactMatch(parsedCondRes.IgnoreCase, parsedString, parsedCondRes.Negate) });
|
||||
break;
|
||||
default:
|
||||
throw new FormatException("Unrecognized pattern syntax.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateUrlAction(XElement urlAction, UrlRewriteRule res, bool globalRule)
|
||||
{
|
||||
if (urlAction == null)
|
||||
{
|
||||
throw new FormatException("Action is a required element of a rule.");
|
||||
}
|
||||
|
||||
var actionRes = new ParsedUrlAction();
|
||||
|
||||
ActionType actionType;
|
||||
if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType))
|
||||
{
|
||||
actionRes.Type = actionType;
|
||||
}
|
||||
|
||||
bool parseBool;
|
||||
if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool))
|
||||
{
|
||||
actionRes.AppendQueryString = parseBool;
|
||||
}
|
||||
|
||||
if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool))
|
||||
{
|
||||
actionRes.LogRewrittenUrl = parseBool;
|
||||
}
|
||||
|
||||
RedirectType redirectType;
|
||||
if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType))
|
||||
{
|
||||
actionRes.RedirectType = redirectType;
|
||||
}
|
||||
|
||||
actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value);
|
||||
|
||||
CreateUrlActionFromParsedAction(actionRes, globalRule, res);
|
||||
}
|
||||
|
||||
public static void CreateUrlActionFromParsedAction(ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res)
|
||||
{
|
||||
switch (actionRes.Type)
|
||||
{
|
||||
case ActionType.None:
|
||||
res.Action = new VoidAction();
|
||||
break;
|
||||
case ActionType.Rewrite:
|
||||
if (actionRes.AppendQueryString)
|
||||
{
|
||||
res.Action = new RewriteAction(res.StopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, actionRes.Url, clearQuery: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.Action = new RewriteAction(res.StopProcessing ? RuleTerminiation.StopRules : RuleTerminiation.Continue, actionRes.Url, clearQuery: true);
|
||||
}
|
||||
break;
|
||||
case ActionType.Redirect:
|
||||
if (actionRes.AppendQueryString)
|
||||
{
|
||||
res.Action = new RedirectAction((int)actionRes.RedirectType, actionRes.Url);
|
||||
}
|
||||
else
|
||||
{
|
||||
res.Action = new RedirectClearQueryAction((int)actionRes.RedirectType, actionRes.Url);
|
||||
}
|
||||
break;
|
||||
case ActionType.AbortRequest:
|
||||
throw new FormatException("Abort requests are not supported.");
|
||||
case ActionType.CustomResponse:
|
||||
// TODO
|
||||
throw new FormatException("Custom Responses are not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite
|
||||
{
|
||||
public class UrlRewriteRule : Rule
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool Enabled { get; set; } = true;
|
||||
public PatternSyntax PatternSyntax { get; set; }
|
||||
public bool StopProcessing { get; set; }
|
||||
public UrlMatch InitialMatch { get; set; }
|
||||
public Conditions Conditions { get; set; }
|
||||
public UrlAction Action { get; set; }
|
||||
|
||||
public override RuleResult ApplyRule(RewriteContext context)
|
||||
{
|
||||
if (!Enabled)
|
||||
{
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
// Due to the path string always having a leading slash,
|
||||
// remove it from the path before regex comparison
|
||||
var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path.ToString().Substring(1), context);
|
||||
|
||||
if (!initMatchRes.Success)
|
||||
{
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
|
||||
var condMatchRes = Conditions.Evaluate(context, initMatchRes);
|
||||
if (!condMatchRes.Success)
|
||||
{
|
||||
return RuleResult.Continue;
|
||||
}
|
||||
|
||||
// at this point we know the rule passed, evaluate the replacement.
|
||||
return Action.ApplyAction(context.HttpContext, initMatchRes, condMatchRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>0e7ca1a7-1dc3-4ce6-b9c7-1688fe1410f1</ProjectGuid>
|
||||
<RootNamespace>Microsoft.AspNetCore.Rewrite</RootNamespace>
|
||||
|
|
@ -17,5 +17,5 @@
|
|||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Rewrite.ModRewrite;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
{
|
||||
|
|
@ -16,16 +16,16 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="hostingEnv"></param>
|
||||
/// <param name="filePath">The path to the file containing mod_rewrite rules.</param>
|
||||
public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, IHostingEnvironment hostingEnv, string filePath)
|
||||
public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, IHostingEnvironment hostingEnv, string filePath)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException("UrlRewriteOptions is null");
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (hostingEnv == null)
|
||||
{
|
||||
throw new ArgumentNullException("HostingEnvironment is null");
|
||||
throw new ArgumentNullException(nameof(hostingEnv));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
|
|
@ -46,36 +46,39 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="reader">Text reader containing a stream of mod_rewrite rules.</param>
|
||||
public static UrlRewriteOptions ImportFromModRewrite(this UrlRewriteOptions options, TextReader reader)
|
||||
public static RewriteOptions ImportFromModRewrite(this RewriteOptions options, TextReader reader)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reader));
|
||||
}
|
||||
options.Rules.AddRange(FileParser.Parse(reader));
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a mod_rewrite rule to the current rules.
|
||||
/// Additional properties (conditions, flags) for the rule can be added through the action.
|
||||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="rule">The literal string of a mod_rewrite rule:
|
||||
/// "RewriteRule Pattern Substitution [Flags]"</param>
|
||||
/// <param name="action">Action to perform on the <see cref="RuleBuilder"/> </param>
|
||||
public static UrlRewriteOptions AddModRewriteRule(this UrlRewriteOptions options, string rule, Action<RuleBuilder> action)
|
||||
public static RewriteOptions AddModRewriteRule(this RewriteOptions options, string rule)
|
||||
{
|
||||
var builder = new RuleBuilder(rule);
|
||||
action(builder);
|
||||
options.Rules.Add(builder.Build());
|
||||
return options;
|
||||
}
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(rule));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a mod_rewrite rule to the current rules.
|
||||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="rule">The literal string of a mod_rewrite rule:
|
||||
/// "RewriteRule Pattern Substitution [Flags]"</param>
|
||||
public static UrlRewriteOptions AddModRewriteRule(this UrlRewriteOptions options, string rule)
|
||||
{
|
||||
var builder = new RuleBuilder(rule);
|
||||
options.Rules.Add(builder.Build());
|
||||
return options;
|
||||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <summary>
|
||||
/// The UrlRewrite Context contains the HttpContext of the request and the file provider to check conditions.
|
||||
/// </summary>
|
||||
public class UrlRewriteContext
|
||||
public class RewriteContext
|
||||
{
|
||||
public HttpContext HttpContext { get; set; }
|
||||
public IFileProvider FileProvider { get; set; }
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// 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.Rewrite;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for the <see cref="RewriteMiddleware"/>
|
||||
/// </summary>
|
||||
public static class RewriteExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match.
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="options">Options for urlrewrite.</param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, RewriteOptions options)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
// put middleware in pipeline
|
||||
return app.UseMiddleware<RewriteMiddleware>(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Rewrite.RuleAbstraction;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
|
|
@ -13,19 +13,19 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
/// <summary>
|
||||
/// Represents a middleware that rewrites urls imported from mod_rewrite, UrlRewrite, and code.
|
||||
/// </summary>
|
||||
public class UrlRewriteMiddleware
|
||||
public class RewriteMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly UrlRewriteOptions _options;
|
||||
private readonly RewriteOptions _options;
|
||||
private readonly IFileProvider _fileProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="UrlRewriteMiddleware"/>
|
||||
/// Creates a new instance of <see cref="RewriteMiddleware"/>
|
||||
/// </summary>
|
||||
/// <param name="next">The delegate representing the next middleware in the request pipeline.</param>
|
||||
/// <param name="hostingEnv">The Hosting Environment.</param>
|
||||
/// <param name="options">The middleware options, containing the rules to apply.</param>
|
||||
public UrlRewriteMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, UrlRewriteOptions options)
|
||||
public RewriteMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, RewriteOptions options)
|
||||
{
|
||||
if (next == null)
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Rewrite
|
|||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
var urlContext = new UrlRewriteContext { HttpContext = context, FileProvider = _fileProvider };
|
||||
var urlContext = new RewriteContext { HttpContext = context, FileProvider = _fileProvider };
|
||||
foreach (var rule in _options.Rules)
|
||||
{
|
||||
// Apply the rule
|
||||
|
|
@ -2,15 +2,15 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Rewrite.RuleAbstraction;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for the <see cref="UrlRewriteMiddleware"/>
|
||||
/// Options for the <see cref="RewriteMiddleware"/>
|
||||
/// </summary>
|
||||
public class UrlRewriteOptions
|
||||
public class RewriteOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The ordered list of rules to apply to the context.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.RuleAbstraction
|
||||
{
|
||||
public enum RuleTerminiation
|
||||
{
|
||||
Continue,
|
||||
ResponseComplete,
|
||||
StopRules
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +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.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
{
|
||||
public class Conditions
|
||||
{
|
||||
public List<Condition> ConditionList { get; set; } = new List<Condition>();
|
||||
public LogicalGrouping MatchType { get; set; } // default is MatchAll
|
||||
public bool TrackingAllCaptures { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +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.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
{
|
||||
public class InitialMatch
|
||||
{
|
||||
public Regex Url { get; set; } // TODO must be a non-empty string, throw in check after parsing?
|
||||
public bool IgnoreCase { get; set; } = true;
|
||||
public bool Negate { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +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 System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Rewrite.UrlRewrite;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
{
|
||||
public static class UrlRewriteExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Imports rules from a mod_rewrite file and adds the rules to current rules.
|
||||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="hostingEnv"></param>
|
||||
/// <param name="filePath">The path to the file containing urlrewrite rules.</param>
|
||||
public static UrlRewriteOptions ImportFromUrlRewrite(this UrlRewriteOptions options, IHostingEnvironment hostingEnv, string filePath)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException("UrlRewriteOptions is null");
|
||||
}
|
||||
|
||||
if (hostingEnv == null)
|
||||
{
|
||||
throw new ArgumentNullException("HostingEnvironment is null");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
throw new ArgumentException(nameof(filePath));
|
||||
}
|
||||
|
||||
var path = Path.Combine(hostingEnv.ContentRootPath, filePath);
|
||||
using (var stream = File.OpenRead(path))
|
||||
{
|
||||
options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream)));
|
||||
};
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,228 +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 System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
{
|
||||
// TODO rename
|
||||
public static class UrlRewriteFileParser
|
||||
{
|
||||
private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1);
|
||||
public static List<UrlRewriteRule> Parse(TextReader reader)
|
||||
{
|
||||
var temp = XDocument.Load(reader);
|
||||
var xmlRoot = temp.Descendants(RewriteTags.Rewrite);
|
||||
var rules = new List<UrlRewriteRule>();
|
||||
|
||||
if (xmlRoot != null)
|
||||
{
|
||||
// there is a valid rewrite block, go through each rule and process
|
||||
GetGlobalRules(xmlRoot.Descendants(RewriteTags.GlobalRules), rules);
|
||||
GetRules(xmlRoot.Descendants(RewriteTags.Rules), rules);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
private static void GetGlobalRules(IEnumerable<XElement> globalRules, List<UrlRewriteRule> result)
|
||||
{
|
||||
foreach (var rule in globalRules.Elements(RewriteTags.Rule) ?? Enumerable.Empty<XElement>())
|
||||
{
|
||||
var res = new UrlRewriteRule();
|
||||
SetRuleAttributes(rule, res);
|
||||
// TODO handle full url with global rules - may or may not support
|
||||
res.Action = CreateUrlAction(rule.Element(RewriteTags.Action));
|
||||
result.Add(res);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetRules(IEnumerable<XElement> rules, List<UrlRewriteRule> result)
|
||||
{
|
||||
// TODO Better null check?
|
||||
foreach (var rule in rules.Elements(RewriteTags.Rule) ?? Enumerable.Empty<XElement>())
|
||||
{
|
||||
var res = new UrlRewriteRule();
|
||||
SetRuleAttributes(rule, res);
|
||||
res.Action = CreateUrlAction(rule.Element(RewriteTags.Action));
|
||||
result.Add(res);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetRuleAttributes(XElement rule, UrlRewriteRule res)
|
||||
{
|
||||
if (rule == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
res.Name = rule.Attribute(RewriteTags.Name)?.Value;
|
||||
|
||||
bool enabled;
|
||||
if (bool.TryParse(rule.Attribute(RewriteTags.Enabled)?.Value, out enabled))
|
||||
{
|
||||
res.Enabled = enabled;
|
||||
}
|
||||
|
||||
PatternSyntax patternSyntax;
|
||||
if (Enum.TryParse(rule.Attribute(RewriteTags.PatternSyntax)?.Value, out patternSyntax))
|
||||
{
|
||||
res.PatternSyntax = patternSyntax;
|
||||
}
|
||||
|
||||
bool stopProcessing;
|
||||
if (bool.TryParse(rule.Attribute(RewriteTags.StopProcessing)?.Value, out stopProcessing))
|
||||
{
|
||||
res.StopProcessing = stopProcessing;
|
||||
}
|
||||
|
||||
res.Match = CreateMatch(rule.Element(RewriteTags.Match));
|
||||
res.Conditions = CreateConditions(rule.Element(RewriteTags.Conditions));
|
||||
}
|
||||
|
||||
private static InitialMatch CreateMatch(XElement match)
|
||||
{
|
||||
if (match == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var matchRes = new InitialMatch();
|
||||
|
||||
bool parBool;
|
||||
if (bool.TryParse(match.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool))
|
||||
{
|
||||
matchRes.IgnoreCase = parBool;
|
||||
}
|
||||
|
||||
if (bool.TryParse(match.Attribute(RewriteTags.Negate)?.Value, out parBool))
|
||||
{
|
||||
matchRes.Negate = parBool;
|
||||
}
|
||||
|
||||
var parsedInputString = match.Attribute(RewriteTags.Url)?.Value;
|
||||
|
||||
if (matchRes.IgnoreCase)
|
||||
{
|
||||
matchRes.Url = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchRes.Url = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout);
|
||||
}
|
||||
return matchRes;
|
||||
}
|
||||
|
||||
|
||||
private static Conditions CreateConditions(XElement conditions)
|
||||
{
|
||||
var condRes = new Conditions();
|
||||
if (conditions == null)
|
||||
{
|
||||
return condRes; // TODO make sure no null exception on Conditions
|
||||
}
|
||||
|
||||
LogicalGrouping grouping;
|
||||
if (Enum.TryParse(conditions.Attribute(RewriteTags.MatchType)?.Value, out grouping))
|
||||
{
|
||||
condRes.MatchType = grouping;
|
||||
}
|
||||
|
||||
bool parBool;
|
||||
if (bool.TryParse(conditions.Attribute(RewriteTags.TrackingAllCaptures)?.Value, out parBool))
|
||||
{
|
||||
condRes.TrackingAllCaptures = parBool;
|
||||
}
|
||||
|
||||
foreach (var cond in conditions.Elements(RewriteTags.Add))
|
||||
{
|
||||
condRes.ConditionList.Add(CreateCondition(cond));
|
||||
}
|
||||
return condRes;
|
||||
}
|
||||
|
||||
private static Condition CreateCondition(XElement condition)
|
||||
{
|
||||
if (condition == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var condRes = new Condition();
|
||||
|
||||
bool parBool;
|
||||
if (bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out parBool))
|
||||
{
|
||||
condRes.IgnoreCase = parBool;
|
||||
}
|
||||
|
||||
if (bool.TryParse(condition.Attribute(RewriteTags.Negate)?.Value, out parBool))
|
||||
{
|
||||
condRes.Negate = parBool;
|
||||
}
|
||||
|
||||
MatchType matchType;
|
||||
if (Enum.TryParse(condition.Attribute(RewriteTags.MatchPattern)?.Value, out matchType))
|
||||
{
|
||||
condRes.MatchType = matchType;
|
||||
}
|
||||
|
||||
var parsedInputString = condition.Attribute(RewriteTags.Input)?.Value;
|
||||
if (parsedInputString != null)
|
||||
{
|
||||
condRes.Input = InputParser.ParseInputString(parsedInputString);
|
||||
}
|
||||
|
||||
parsedInputString = condition.Attribute(RewriteTags.Pattern)?.Value;
|
||||
|
||||
if (condRes.IgnoreCase)
|
||||
{
|
||||
condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.IgnoreCase | RegexOptions.Compiled, RegexTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
condRes.MatchPattern = new Regex(parsedInputString, RegexOptions.Compiled, RegexTimeout);
|
||||
}
|
||||
return condRes;
|
||||
}
|
||||
|
||||
private static UrlAction CreateUrlAction(XElement urlAction)
|
||||
{
|
||||
if (urlAction == null)
|
||||
{
|
||||
throw new FormatException("Action is a required element of a rule.");
|
||||
}
|
||||
var actionRes = new UrlAction();
|
||||
|
||||
ActionType actionType;
|
||||
if (Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType))
|
||||
{
|
||||
actionRes.Type = actionType;
|
||||
}
|
||||
|
||||
bool parseBool;
|
||||
if (bool.TryParse(urlAction.Attribute(RewriteTags.AppendQuery)?.Value, out parseBool))
|
||||
{
|
||||
actionRes.AppendQueryString = parseBool;
|
||||
}
|
||||
|
||||
if (bool.TryParse(urlAction.Attribute(RewriteTags.LogRewrittenUrl)?.Value, out parseBool))
|
||||
{
|
||||
actionRes.LogRewrittenUrl = parseBool;
|
||||
}
|
||||
|
||||
RedirectType redirectType;
|
||||
if (Enum.TryParse(urlAction.Attribute(RewriteTags.RedirectType)?.Value, out redirectType))
|
||||
{
|
||||
actionRes.RedirectType = redirectType;
|
||||
}
|
||||
|
||||
actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value);
|
||||
return actionRes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +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.Rewrite.RuleAbstraction;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite.UrlRewrite
|
||||
{
|
||||
public class UrlRewriteRule : Rule
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public bool Enabled { get; set; } = true;
|
||||
public PatternSyntax PatternSyntax { get; set; }
|
||||
public bool StopProcessing { get; set; }
|
||||
public InitialMatch Match { get; set; }
|
||||
public Conditions Conditions { get; set; }
|
||||
public UrlAction Action { get; set; }
|
||||
|
||||
public override RuleResult ApplyRule(UrlRewriteContext context)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,34 +2,67 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Rewrite;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for the <see cref="UrlRewriteMiddleware"/>
|
||||
/// </summary>
|
||||
public static class UrlRewriteExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a given Url matches rules and conditions, and modifies the HttpContext on match.
|
||||
/// Imports rules from a mod_rewrite file and adds the rules to current rules.
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="options">Options for urlrewrite.</param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseRewriter(this IApplicationBuilder app, UrlRewriteOptions options)
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="hostingEnv"></param>
|
||||
/// <param name="filePath">The path to the file containing urlrewrite rules.</param>
|
||||
public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, IHostingEnvironment hostingEnv, string filePath)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
// put middleware in pipeline
|
||||
return app.UseMiddleware<UrlRewriteMiddleware>(options);
|
||||
|
||||
if (hostingEnv == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(hostingEnv));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
throw new ArgumentException(nameof(filePath));
|
||||
}
|
||||
|
||||
var path = Path.Combine(hostingEnv.ContentRootPath, filePath);
|
||||
using (var stream = File.OpenRead(path))
|
||||
{
|
||||
options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream)));
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports rules from a mod_rewrite file and adds the rules to current rules.
|
||||
/// </summary>
|
||||
/// <param name="options">The UrlRewrite options.</param>
|
||||
/// <param name="stream">The text reader stream.</param>
|
||||
public static RewriteOptions ImportFromUrlRewrite(this RewriteOptions options, TextReader stream)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentException(nameof(stream));
|
||||
}
|
||||
|
||||
using (stream)
|
||||
{
|
||||
options.Rules.AddRange(UrlRewriteFileParser.Parse(stream));
|
||||
};
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// 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 Microsoft.AspNetCore.Rewrite.ModRewrite;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
|
||||
{
|
||||
public class ConditionActionTest
|
||||
{
|
||||
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Rewrite.ModRewrite;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Rewrite
|
||||
namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
|
||||
{
|
||||
public class FlagParserTest
|
||||
{
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
// 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 Microsoft.AspNetCore.Rewrite.ModRewrite;
|
||||
using Microsoft.AspNetCore.Rewrite.Operands;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
|
||||
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite.Operands;
|
||||
using Xunit;
|
||||
|
||||
namespace RewriteTest
|
||||
namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
|
||||
{
|
||||
// This file tests an input of a list of tokens and verifies that the appropriate condition is obtained
|
||||
public class ModRewriteConditionBuilderTest
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue