From 0cb7445921a7eb077e42895b4ab3e3f7833e19a2 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 23 Aug 2016 13:46:39 -0700 Subject: [PATCH] General bugfixes and style cleanup --- samples/RewriteSample/Startup.cs | 2 +- .../CodeRewriteExtensions.cs | 2 +- .../Internal/CodeRules/RewriteToHttpsRule.cs | 4 +- .../ModRewrite/ConditionPatternParser.cs | 36 ++-- .../Internal/ModRewrite/FileParser.cs | 2 +- .../Internal/ModRewrite/FlagParser.cs | 2 +- .../ModRewrite/ModRewriteRewriteAction.cs | 5 +- .../Internal/ModRewrite/RuleBuilder.cs | 171 +++++++++--------- .../Internal/ModRewrite/RuleRegexParser.cs | 2 +- .../Internal/ModRewrite/TestStringParser.cs | 69 ++++--- .../Internal/ModRewrite/Tokenizer.cs | 73 ++++---- .../Internal/ParserContext.cs | 10 +- .../Internal/Pattern.cs | 2 +- .../PatternSegments/ConditionMatchSegment.cs | 6 +- .../PatternSegments/DateTimeSegment.cs | 2 +- .../Internal/PatternSegments/HeaderSegment.cs | 6 +- .../PatternSegments/LiteralSegment.cs | 6 +- .../PatternSegments/RuleMatchSegment.cs | 6 +- .../PatternSegments/ToLowerSegment.cs | 6 +- .../PatternSegments/UrlEncodeSegment.cs | 6 +- .../Internal/PreAction.cs | 5 +- .../Internal/UrlActions/RewriteAction.cs | 3 +- .../Internal/UrlActions/VoidAction.cs | 8 +- .../Internal/UrlMatch.cs | 2 +- .../Internal/UrlMatches/ExactMatch.cs | 10 +- .../Internal/UrlMatches/IntegerMatch.cs | 26 +-- .../Internal/UrlMatches/IsDirectoryMatch.cs | 2 +- .../Internal/UrlMatches/RegexMatch.cs | 9 +- .../Internal/UrlMatches/StringMatch.cs | 26 +-- .../Internal/UrlRewrite/FileParser.cs | 12 +- .../Internal/UrlRewrite/InputParser.cs | 3 +- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 10 +- .../Internal/UrlRewriteRule.cs | 22 ++- .../RewriteMiddleware.cs | 2 + .../UrlRewrite/UrlRewriteApplicationTests.cs | 56 ++++++ 35 files changed, 333 insertions(+), 281 deletions(-) create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs diff --git a/samples/RewriteSample/Startup.cs b/samples/RewriteSample/Startup.cs index 1dbcb048e5..a232a4bf45 100644 --- a/samples/RewriteSample/Startup.cs +++ b/samples/RewriteSample/Startup.cs @@ -37,7 +37,7 @@ namespace RewriteSample return RuleResult.Continue; })); - app.Run(context => context.Response.WriteAsync(context.Request.Path)); + app.Run(context => context.Response.WriteAsync($"Rewritten Url: {context.Request.Path + context.Request.QueryString}")); } public static void Main(string[] args) diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index 0a76169605..983ae1e36a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -91,7 +91,7 @@ namespace Microsoft.AspNetCore.Rewrite public static RewriteOptions RewriteToHttps(this RewriteOptions options, int? sslPort, bool stopProcessing) { - options.Rules.Add(new RewriteToHttpsRule {SSLPort = sslPort, stopProcessing = stopProcessing }); + options.Rules.Add(new RewriteToHttpsRule {SSLPort = sslPort, StopProcessing = stopProcessing }); return options; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs index fb5744e8c2..bcb15fda25 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public class RewriteToHttpsRule : Rule { - public bool stopProcessing { get; set; } + public bool StopProcessing { get; set; } public int? SSLPort { get; set; } public override RuleResult ApplyRule(RewriteContext context) @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules context.HttpContext.Request.Scheme = "https"; context.HttpContext.Request.Host = host; - return stopProcessing ? RuleResult.StopRules: RuleResult.Continue; + return StopProcessing ? RuleResult.StopRules: RuleResult.Continue; } return RuleResult.Continue; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index ea678502de..dc9c8328be 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -172,19 +172,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case 'g': if (!context.Next()) { - throw new FormatException(context.Error()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } - if (context.Current == 't') + switch (context.Current) { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Greater, operand: null); - } - else if (context.Current == 'e') - { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.GreaterEqual, operand: null); - } - else - { - throw new FormatException(context.Error()); + case 't': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Greater, operand: null); + case 'e': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.GreaterEqual, operand: null); + default: + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } case 'l': // name conflict with -l and -lt/-le, so the assumption is if there is no @@ -193,17 +190,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { return new ParsedModRewriteInput(invert, ConditionType.PropertyTest, OperationType.SymbolicLink, operand: null); } - if (context.Current == 't') + switch (context.Current) { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Less, operand: null); - } - else if (context.Current == 'e') - { - return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.LessEqual, operand: null); - } - else - { - throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); + case 't': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.Less, operand: null); + case 'e': + return new ParsedModRewriteInput(invert, ConditionType.IntComp, OperationType.LessEqual, operand: null); + default: + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index)); } case 'n': if (!context.Next() || context.Current != 'e') diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index 4610619ebf..2f16c8af08 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public List Parse(TextReader input) { - string line = null; + string line; var rules = new List(); var builder = new RuleBuilder(); var lineNum = 0; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index d06085df59..895dcb16d4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // Invalid syntax to have any spaces. var tokens = flagString.Substring(1, flagString.Length - 2).Split(','); var flags = new Flags(); - foreach (string token in tokens) + foreach (var token in tokens) { var hasPayload = token.Split('='); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 10404e1f20..419bd0f440 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; @@ -33,9 +34,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var pattern = Url.Evaluate(context, ruleMatch, condMatch); // TODO PERF, substrings, object creation, etc. - if (pattern.IndexOf("://") >= 0) + if (pattern.IndexOf("://", StringComparison.Ordinal) >= 0) { - string scheme = null; + string scheme; HostString host; PathString path; QueryString query; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index e19cf3cdda..db0490745c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -62,91 +62,90 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite condition.OrNext = flags.HasFlag(FlagType.Or); condition.Input = pattern; - if (input.ConditionType == ConditionType.Regex) + switch (input.ConditionType) { - if (flags.HasFlag(FlagType.NoCase)) - { - condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); - } - else - { - condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled, RegexTimeout), input.Invert); - } - } - else if (input.ConditionType == ConditionType.IntComp) - { - switch (input.OperationType) - { - case OperationType.Equal: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Equal); - break; - case OperationType.Greater: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Greater); - break; - case OperationType.GreaterEqual: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.GreaterEqual); - break; - case OperationType.Less: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Less); - break; - case OperationType.LessEqual: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.LessEqual); - break; - case OperationType.NotEqual: - condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.NotEqual); - break; - default: - throw new ArgumentException("Invalid operation for integer comparison."); - } - } - else if (input.ConditionType == ConditionType.StringComp) - { - switch (input.OperationType) - { - case OperationType.Equal: - condition.Match = new StringMatch(input.Operand, StringOperationType.Equal); - break; - case OperationType.Greater: - condition.Match = new StringMatch(input.Operand, StringOperationType.Greater); - break; - case OperationType.GreaterEqual: - condition.Match = new StringMatch(input.Operand, StringOperationType.GreaterEqual); - break; - case OperationType.Less: - condition.Match = new StringMatch(input.Operand, StringOperationType.Less); - break; - case OperationType.LessEqual: - condition.Match = new StringMatch(input.Operand, StringOperationType.LessEqual); - break; - default: - throw new ArgumentException("Invalid operation for string comparison."); - } - } - else - { - switch (input.OperationType) - { - case OperationType.Directory: - condition.Match = new IsDirectoryMatch(input.Invert); - break; - case OperationType.RegularFile: - condition.Match = new IsFileMatch(input.Invert); - break; - case OperationType.ExistingFile: - condition.Match = new IsFileMatch(input.Invert); - break; - case OperationType.SymbolicLink: - throw new NotImplementedException("Symbolic links are not implemented"); - case OperationType.Size: - condition.Match = new FileSizeMatch(input.Invert); - break; - case OperationType.ExistingUrl: - throw new NotImplementedException("Existing Url lookups not implemented"); - case OperationType.Executable: - throw new NotImplementedException("Executable Property search is not implemented"); - default: - throw new ArgumentException("Invalid operation for property comparison."); - } + case ConditionType.Regex: + if (flags.HasFlag(FlagType.NoCase)) + { + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + } + else + { + condition.Match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout), input.Invert); + } + break; + case ConditionType.IntComp: + switch (input.OperationType) + { + case OperationType.Equal: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Equal); + break; + case OperationType.Greater: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Greater); + break; + case OperationType.GreaterEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.GreaterEqual); + break; + case OperationType.Less: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.Less); + break; + case OperationType.LessEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.LessEqual); + break; + case OperationType.NotEqual: + condition.Match = new IntegerMatch(input.Operand, IntegerOperationType.NotEqual); + break; + default: + throw new ArgumentException("Invalid operation for integer comparison."); + } + break; + case ConditionType.StringComp: + switch (input.OperationType) + { + case OperationType.Equal: + condition.Match = new StringMatch(input.Operand, StringOperationType.Equal, input.Invert); + break; + case OperationType.Greater: + condition.Match = new StringMatch(input.Operand, StringOperationType.Greater, input.Invert); + break; + case OperationType.GreaterEqual: + condition.Match = new StringMatch(input.Operand, StringOperationType.GreaterEqual, input.Invert); + break; + case OperationType.Less: + condition.Match = new StringMatch(input.Operand, StringOperationType.Less, input.Invert); + break; + case OperationType.LessEqual: + condition.Match = new StringMatch(input.Operand, StringOperationType.LessEqual, input.Invert); + break; + default: + throw new ArgumentException("Invalid operation for string comparison."); + } + break; + default: + switch (input.OperationType) + { + case OperationType.Directory: + condition.Match = new IsDirectoryMatch(input.Invert); + break; + case OperationType.RegularFile: + condition.Match = new IsFileMatch(input.Invert); + break; + case OperationType.ExistingFile: + condition.Match = new IsFileMatch(input.Invert); + break; + case OperationType.SymbolicLink: + throw new NotImplementedException("Symbolic links are not implemented"); + case OperationType.Size: + condition.Match = new FileSizeMatch(input.Invert); + break; + case OperationType.ExistingUrl: + throw new NotImplementedException("Existing Url lookups not implemented"); + case OperationType.Executable: + throw new NotImplementedException("Executable Property search is not implemented"); + default: + throw new ArgumentException("Invalid operation for property comparison."); + } + break; } _conditions.ConditionList.Add(condition); } @@ -157,11 +156,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { if (flags.HasFlag(FlagType.NoCase)) { - _match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout), input.Invert); } else { - _match = new RegexMatch(new Regex(input.Operand, RegexOptions.Compiled, RegexTimeout), input.Invert); + _match = new RegexMatch(new Regex(input.Operand, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout), input.Invert); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index 272faf96e0..67368cc6df 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public ParsedModRewriteInput ParseRuleRegex(string regex) { - if (regex == null || regex == string.Empty) + if (string.IsNullOrEmpty(regex)) { throw new FormatException("Regex expression is null"); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index 557cc0bf24..002c69fa40 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -14,7 +14,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { private const char Percent = '%'; private const char Dollar = '$'; - private const char Space = ' '; private const char Colon = ':'; private const char OpenBrace = '{'; private const char CloseBrace = '}'; @@ -41,43 +40,41 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var results = new List(); while (context.Next()) { - if (context.Current == Percent) + switch (context.Current) { - // This is a server parameter, parse for a condition variable - if (!context.Next()) - { - throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(testString, context.Index)); - } - ParseConditionParameter(context, results); - } - else if (context.Current == Dollar) - { - // This is a parameter from the rule, verify that it is a number from 0 to 9 directly after it - // and create a new Pattern Segment. - if (!context.Next()) - { - throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); - } - context.Mark(); - if (context.Current >= '0' && context.Current <= '9') - { - context.Next(); - var ruleVariable = context.Capture(); - context.Back(); - var parsedIndex = int.Parse(ruleVariable); + case Percent: + // This is a server parameter, parse for a condition variable + if (!context.Next()) + { + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(testString, context.Index)); + } + ParseConditionParameter(context, results); + break; + case Dollar: + // This is a parameter from the rule, verify that it is a number from 0 to 9 directly after it + // and create a new Pattern Segment. + if (!context.Next()) + { + throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); + } + context.Mark(); + if (context.Current >= '0' && context.Current <= '9') + { + context.Next(); + var ruleVariable = context.Capture(); + context.Back(); + var parsedIndex = int.Parse(ruleVariable); - results.Add(new RuleMatchSegment(parsedIndex)); - } - else - { - throw new FormatException(Resources.FormatError_InputParserInvalidInteger(testString, context.Index)); - } - } - else - { - // Parse for literals, which will return on either the end of the test string - // or when it hits a special character - ParseLiteral(context, results); + results.Add(new RuleMatchSegment(parsedIndex)); + } + else + { + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(testString, context.Index)); + } + break; + default: + ParseLiteral(context, results); + break; } } return new Pattern(results); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index 529d8e23b5..6b51553dbb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -15,6 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite private const char Space = ' '; private const char Escape = '\\'; private const char Tab = '\t'; + private const char Quote = '"'; /// /// Splits a string on whitespace, ignoring spaces, creating into a list of strings. @@ -36,49 +37,51 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite context.Mark(); while (true) { - if (context.Current == Escape) + switch (context.Current) { - // Need to progress such that the next character is not evaluated. - if (!context.Next()) - { - // Means that a character was not escaped appropriately Ex: "foo\" - throw new FormatException($"Invalid escaper character in string: {rule}"); - } - } - else if (context.Current == '"') - { - // Ignore all characters until the next quote is hit - if (!context.Next()) - { - throw new FormatException($"Mismatched number of quotes: {rule}"); - } - while (context.Current != '"') - { + case Escape: + // Need to progress such that the next character is not evaluated. + if (!context.Next()) + { + // Means that a character was not escaped appropriately Ex: "foo\" + throw new FormatException($"Invalid escaper character in string: {rule}"); + } + break; + case Quote: + // Ignore all characters until the next quote is hit if (!context.Next()) { throw new FormatException($"Mismatched number of quotes: {rule}"); } - } - } - else if (context.Current == Space || context.Current == Tab) - { - // time to capture! - var token = context.Capture(); - if (!string.IsNullOrEmpty(token)) - { - tokens.Add(token); - while (context.Current == Space || context.Current == Tab) + + while (context.Current != Quote) { if (!context.Next()) { - // At end of string, we can return at this point. - RemoveQuotesAndEscapeCharacters(tokens); - return tokens; + throw new FormatException($"Mismatched number of quotes: {rule}"); } } - context.Mark(); - context.Back(); - } + break; + case Space: + case Tab: + // time to capture! + var token = context.Capture(); + if (!string.IsNullOrEmpty(token)) + { + tokens.Add(token); + do + { + if (!context.Next()) + { + // At end of string, we can return at this point. + RemoveQuotesAndEscapeCharacters(tokens); + return tokens; + } + } while (context.Current == Space || context.Current == Tab); + context.Mark(); + context.Back(); + } + break; } if (!context.Next()) { @@ -99,9 +102,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // Need to remove leading and trailing slashes if they exist. // This is on start-up, so more forgivening towards substrings/ new strings // If this is a perf/memory problem, discuss later. - private void RemoveQuotesAndEscapeCharacters(List tokens) + private static void RemoveQuotesAndEscapeCharacters(IList tokens) { - for (int i = 0; i < tokens.Count; i++) + for (var i = 0; i < tokens.Count; i++) { var token = tokens[i]; var trimmed = token.Trim('\"'); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs index e394ddc4d4..50d0d3998a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs @@ -18,10 +18,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal Index = -1; } - public char Current - { - get { return (Index < Template.Length && Index >= 0) ? Template[Index] : (char)0; } - } + public char Current => (Index < Template.Length && Index >= 0) ? Template[Index] : (char)0; public bool Back() { @@ -62,10 +59,5 @@ namespace Microsoft.AspNetCore.Rewrite.Internal return null; } } - - public string Error() - { - return string.Format("Syntax Error at index: ", Index, " with character: ", Current); - } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs index 99f8f014f4..590bdccdb4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public class Pattern { public IList PatternSegments { get; } - public Pattern(List patternSegments) + public Pattern(IList patternSegments) { PatternSegments = patternSegments; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs index 057164a4cc..5ca4cc2b97 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ConditionMatchSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ConditionMatchSegment : PatternSegment { - public int Index { get; set; } + private readonly int _index; public ConditionMatchSegment(int index) { - Index = index; + _index = index; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return condMatch?.BackReference[Index]?.Value; + return condMatch?.BackReference[_index].Value; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs index bb535d5178..4238ebb0fb 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/DateTimeSegment.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class DateTimeSegment : PatternSegment { - private DateTimePortion _portion; + private readonly DateTimePortion _portion; public DateTimeSegment(string segment) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs index 116dca22c4..cd506c75d2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/HeaderSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class HeaderSegment : PatternSegment { - public string Header { get; set; } + private readonly string _header; public HeaderSegment(string header) { - Header = header; + _header = header; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return context.HttpContext.Request.Headers[Header]; + return context.HttpContext.Request.Headers[_header]; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs index 676a9e3d29..17d240db4a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/LiteralSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class LiteralSegment : PatternSegment { - public string Literal { get; set; } + private readonly string _literal; public LiteralSegment(string literal) { - Literal = literal; + _literal = literal; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return Literal; + return _literal; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs index e54c08000b..2b008c6109 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/RuleMatchSegment.cs @@ -5,16 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class RuleMatchSegment : PatternSegment { - public int Index { get; set; } + private readonly int _index; public RuleMatchSegment(int index) { - Index = index; + _index = index; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return ruleMatch?.BackReference[Index]?.Value; + return ruleMatch?.BackReference[_index].Value; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs index c61e056331..0588b2b526 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/ToLowerSegment.cs @@ -7,11 +7,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class ToLowerSegment : PatternSegment { - public Pattern Pattern { get; set; } + private readonly Pattern _pattern; public ToLowerSegment(Pattern pattern) { - Pattern = pattern; + _pattern = pattern; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments // lowercase segments. var tempBuilder = context.Builder; context.Builder = new StringBuilder(64); - var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); context.Builder = tempBuilder; return pattern.ToLowerInvariant(); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs index f64bb33cc6..5bca22d5ff 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PatternSegments/UrlEncodeSegment.cs @@ -8,18 +8,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments { public class UrlEncodeSegment : PatternSegment { - public Pattern Pattern { get; set; } + private readonly Pattern _pattern; public UrlEncodeSegment(Pattern pattern) { - Pattern = pattern; + _pattern = pattern; } public override string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { var tempBuilder = context.Builder; context.Builder = new StringBuilder(64); - var pattern = Pattern.Evaluate(context, ruleMatch, condMatch); + var pattern = _pattern.Evaluate(context, ruleMatch, condMatch); context.Builder = tempBuilder; return UrlEncoder.Default.Encode(pattern); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs index 08b1014c1c..e86bc03f3c 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/PreAction.cs @@ -1,6 +1,7 @@ - +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; namespace Microsoft.AspNetCore.Rewrite.Internal { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs index ef16e84e76..eb8d59dda2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/RewriteAction.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; @@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions // TODO PERF, substrings, object creation, etc. if (pattern.IndexOf("://") >= 0) { - string scheme = null; + string scheme; HostString host; PathString path; QueryString query; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs index 82825872eb..c58c6e94cd 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlActions/VoidAction.cs @@ -5,10 +5,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlActions { public class VoidAction : UrlAction { + private readonly RuleResult _results; + + public VoidAction(RuleResult results) + { + _results = results; + } // Explicitly say that nothing happens public override RuleResult ApplyAction(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - return RuleResult.Continue; + return _results; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs index 428c24ea75..9d78d63d67 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatch.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal { public abstract class UrlMatch { - public bool Negate { get; set; } + protected bool Negate { get; set; } public abstract MatchResults Evaluate(string input, RewriteContext context); } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs index 39b6449524..58cc914b84 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/ExactMatch.cs @@ -5,19 +5,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class ExactMatch : UrlMatch { - public bool IgnoreCase { get; } - public string StringMatch { get; } + private readonly bool _ignoreCase; + private readonly string _stringMatch; public ExactMatch(bool ignoreCase, string input, bool negate) { - IgnoreCase = ignoreCase; - StringMatch = input; + _ignoreCase = ignoreCase; + _stringMatch = input; Negate = negate; } public override MatchResults Evaluate(string pattern, RewriteContext context) { - var pathMatch = string.Compare(pattern, StringMatch, IgnoreCase); + var pathMatch = string.Compare(pattern, _stringMatch, _ignoreCase); return new MatchResults { Success = ((pathMatch == 0) != Negate) }; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs index 185c8de53e..770bbbd6d1 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IntegerMatch.cs @@ -8,12 +8,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IntegerMatch : UrlMatch { - public int Value { get; } - public IntegerOperationType Operation { get; } + private readonly int _value; + private readonly IntegerOperationType _operation; public IntegerMatch(int value, IntegerOperationType operation) { - Value = value; - Operation = operation; + _value = value; + _operation = operation; } public IntegerMatch(string value, IntegerOperationType operation) @@ -23,8 +23,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { throw new FormatException("Syntax error for integers in comparison."); } - Value = compValue; - Operation = operation; + _value = compValue; + _operation = operation; } public override MatchResults Evaluate(string input, RewriteContext context) @@ -35,20 +35,20 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches return MatchResults.EmptyFailure; } - switch (Operation) + switch (_operation) { case IntegerOperationType.Equal: - return compValue == Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue == _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.Greater: - return compValue > Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue > _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.GreaterEqual: - return compValue >= Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue >= _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.Less: - return compValue < Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue < _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.LessEqual: - return compValue <= Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue <= _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case IntegerOperationType.NotEqual: - return compValue != Value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return compValue != _value ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; default: return null; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs index 97d1177714..113ff88e2e 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/IsDirectoryMatch.cs @@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class IsDirectoryMatch : UrlMatch { - public IsDirectoryMatch( bool negate) + public IsDirectoryMatch(bool negate) { Negate = negate; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs index a932d869f6..b869285b20 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/RegexMatch.cs @@ -1,26 +1,23 @@ // 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.UrlMatches { public class RegexMatch : UrlMatch { - private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - - public Regex Match { get; } + private readonly Regex _match; public RegexMatch(Regex match, bool negate) { - Match = match; + _match = match; Negate = negate; } public override MatchResults Evaluate(string pattern, RewriteContext context) { - var res = Match.Match(pattern); + var res = _match.Match(pattern); return new MatchResults { BackReference = res.Groups, Success = (res.Success != Negate)}; } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs index 81332401fe..e991144f2d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlMatches/StringMatch.cs @@ -5,29 +5,31 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlMatches { public class StringMatch : UrlMatch { - public string Value { get; set; } - public StringOperationType Operation { get; set; } - public bool IgnoreCase { get; set; } - public StringMatch(string value, StringOperationType operation) + private readonly string _value; + private readonly StringOperationType _operation; + private readonly bool _ignoreCase; + + public StringMatch(string value, StringOperationType operation, bool ignoreCase) { - Value = value; - Operation = operation; + _value = value; + _operation = operation; + _ignoreCase = ignoreCase; } public override MatchResults Evaluate(string input, RewriteContext context) { - switch (Operation) + switch (_operation) { case StringOperationType.Equal: - return string.Compare(input, Value, IgnoreCase) == 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) == 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.Greater: - return string.Compare(input, Value, IgnoreCase) > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) > 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.GreaterEqual: - return string.Compare(input, Value, IgnoreCase) >= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) >= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.Less: - return string.Compare(input, Value, IgnoreCase) < 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) < 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; case StringOperationType.LessEqual: - return string.Compare(input, Value, IgnoreCase) <= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; + return string.Compare(input, _value, _ignoreCase) <= 0 ? MatchResults.EmptySuccess : MatchResults.EmptyFailure; default: return null; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs index b6b9d5ae16..6e6cd6419d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs @@ -12,9 +12,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { public class FileParser { - private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - - private InputParser _inputParser = new InputParser(); + private readonly InputParser _inputParser = new InputParser(); public List Parse(TextReader reader) { @@ -168,12 +166,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value; - Pattern input = null; try { - input = _inputParser.ParseInputString(parsedInputString); + var input = _inputParser.ParseInputString(parsedInputString); builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate); - } catch (FormatException formatException) { @@ -212,14 +208,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private void ThrowUrlFormatException(XElement element, string message) + private static void ThrowUrlFormatException(XElement element, string message) { var line = ((IXmlLineInfo)element).LineNumber; var col = ((IXmlLineInfo)element).LinePosition; throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col)); } - private void ThrowUrlFormatException(XElement element, string message, Exception ex) + private static void ThrowUrlFormatException(XElement element, string message, Exception ex) { var line = ((IXmlLineInfo)element).LineNumber; var col = ((IXmlLineInfo)element).LinePosition; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index c721657b25..5fe5038eef 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -165,7 +165,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return index; } - private static bool ParseLiteral(ParserContext context, List results) + private static void ParseLiteral(ParserContext context, List results) { context.Mark(); string literal; @@ -186,7 +186,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } results.Add(new LiteralSegment(literal)); - return true; } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 413b81076a..2dad4efcd0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite switch (actionType) { case ActionType.None: - _action = new VoidAction(); + _action = new VoidAction(stopProcessing ? RuleResult.StopRules : RuleResult.Continue); break; case ActionType.Rewrite: if (appendQueryString) @@ -79,12 +79,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { if (ignoreCase) { - var regex = new Regex(input, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); _initialMatch = new RegexMatch(regex, negate); } else { - var regex = new Regex(input, RegexOptions.Compiled, RegexTimeout); + var regex = new Regex(input, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); _initialMatch = new RegexMatch(regex, negate); } break; @@ -121,11 +121,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite Regex regex = null; if (ignoreCase) { - regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); + regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase, RegexTimeout); } else { - regex = new Regex(pattern, RegexOptions.Compiled, RegexTimeout); + regex = new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled, RegexTimeout); } _conditions.ConditionList.Add(new Condition { Input = input, Match = new RegexMatch(regex, negate), OrNext = _matchAny}); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs index 35ed34065f..736290b4fa 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewriteRule.cs @@ -1,10 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Diagnostics; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Rewrite.Internal { @@ -26,9 +23,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal // Due to the path string always having a leading slash, // remove it from the path before regex comparison // TODO may need to check if there is a leading slash and remove conditionally - var initMatchRes = InitialMatch.Evaluate(context.HttpContext.Request.Path.ToString().Substring(1), context); + var path = context.HttpContext.Request.Path; + MatchResults initMatchResults; + if (path == PathString.Empty) + { + initMatchResults = InitialMatch.Evaluate(path.ToString(), context); + } + else + { + initMatchResults = InitialMatch.Evaluate(path.ToString().Substring(1), context); + } - if (!initMatchRes.Success) + if (!initMatchResults.Success) { return RuleResult.Continue; } @@ -36,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal MatchResults condMatchRes = null; if (Conditions != null) { - condMatchRes = Conditions.Evaluate(context, initMatchRes); + condMatchRes = Conditions.Evaluate(context, initMatchResults); if (!condMatchRes.Success) { return RuleResult.Continue; @@ -44,7 +50,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } // at this point we know the rule passed, evaluate the replacement. - return Action.ApplyAction(context, initMatchRes, condMatchRes); + return Action.ApplyAction(context, initMatchResults, condMatchRes); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs index eebc8e9ffc..61c332b7c6 100644 --- a/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs +++ b/src/Microsoft.AspNetCore.Rewrite/RewriteMiddleware.cs @@ -69,6 +69,8 @@ namespace Microsoft.AspNetCore.Rewrite return CompletedTask; case RuleTerminiation.StopRules: return _next(context); + default: + throw new ArgumentOutOfRangeException($"Invalid rule termination {result}"); } } return _next(context); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs new file mode 100644 index 0000000000..6c5abfedb5 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/UrlRewriteApplicationTests.cs @@ -0,0 +1,56 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite.Internal; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.AspNetCore.TestHost; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + // TODO add more of these + public class UrlRewriteApplicationTests + { + [Fact] + public void ApplyRule_AssertStopProcessingFlagWillTerminateOnNoAction() + { + var xml = new StringReader(@" + + + + + + + "); + var rules = new FileParser().Parse(xml); + + Assert.Equal(rules.Count, 1); + var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext {HttpContext = new DefaultHttpContext()}); + Assert.Equal(ruleResults.Result, RuleTerminiation.StopRules); + } + + [Fact] + public void ApplyRule_AssertNoTerminateFlagWillNotTerminateOnNoAction() + { + var xml = new StringReader(@" + + + + + + + "); + var rules = new FileParser().Parse(xml); + + Assert.Equal(rules.Count, 1); + var ruleResults = rules.FirstOrDefault().ApplyRule(new RewriteContext { HttpContext = new DefaultHttpContext() }); + Assert.Equal(ruleResults.Result, RuleTerminiation.Continue); + } + } +}