From d1ab35db87b729b7f135259dd184f0787f4fbece Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 18 Aug 2016 10:18:15 -0700 Subject: [PATCH] Parsers are now non-static (when appropriate) --- .../CodeRewriteExtensions.cs | 4 +- .../Internal/CodeRules/RedirectToHttpsRule.cs | 1 + .../Internal/CodeRules/RewriteToHttpsRule.cs | 1 + .../ModRewrite/ConditionPatternParser.cs | 9 ++- .../Internal/ModRewrite/FileParser.cs | 29 +++++--- .../Internal/ModRewrite/FlagParser.cs | 67 +++++++++++++++++-- .../Internal/ModRewrite/Flags.cs | 56 ---------------- .../ModRewrite/ModRewriteRedirectAction.cs | 1 - .../ModRewrite/ModRewriteRewriteAction.cs | 1 - .../Internal/ModRewrite/RuleBuilder.cs | 16 +++-- .../Internal/ModRewrite/RuleRegexParser.cs | 4 +- .../Internal/ModRewrite/ServerVariables.cs | 1 - .../Internal/ModRewrite/TestStringParser.cs | 3 +- .../Internal/ModRewrite/Tokenizer.cs | 4 +- .../Internal/Pattern.cs | 1 - ...{UrlRewriteFileParser.cs => FileParser.cs} | 27 ++++---- .../Internal/UrlRewrite/InputParser.cs | 2 +- .../UrlRewrite/UrlRewriteRuleBuilder.cs | 1 - .../UrlRewriteExtensions.cs | 4 +- .../ModRewrite/ConditionActionTest.cs | 10 +-- .../ModRewrite/FlagParserTest.cs | 6 +- .../ModRewrite/RewriteTokenizerTest.cs | 4 +- .../ModRewrite/RuleRegexParserTest.cs | 6 +- .../UrlRewrite/FileParserTests.cs | 15 +++-- .../FormatExceptionHandlingTests.cs | 2 +- .../UrlRewrite/InputParserTests.cs | 12 ++-- 26 files changed, 149 insertions(+), 138 deletions(-) rename src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/{UrlRewriteFileParser.cs => FileParser.cs} (86%) diff --git a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs index 9da5101c96..b31cf14cad 100644 --- a/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/CodeRewriteExtensions.cs @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite public static RewriteOptions RewriteRule(this RewriteOptions options, string regex, string onMatch, bool stopProcessing) { var builder = new UrlRewriteRuleBuilder(); - var pattern = InputParser.ParseInputString(onMatch); + var pattern = new InputParser().ParseInputString(onMatch); builder.AddUrlMatch(regex); builder.AddUrlAction(pattern, actionType: ActionType.Rewrite, stopProcessing: stopProcessing); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite public static RewriteOptions RedirectRule(this RewriteOptions options, string regex, string onMatch, int statusCode, bool stopProcessing) { var builder = new UrlRewriteRuleBuilder(); - var pattern = InputParser.ParseInputString(onMatch); + var pattern = new InputParser().ParseInputString(onMatch); builder.AddUrlMatch(regex); builder.AddUrlAction(pattern, actionType: ActionType.Redirect, stopProcessing: stopProcessing); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs index 04b1c8dd97..558810b50a 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RedirectToHttpsRule.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules { public int? SSLPort { get; set; } public int StatusCode { get; set; } + public override RuleResult ApplyRule(RewriteContext context) { if (!context.HttpContext.Request.IsHttps) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs index e276baa85b..c4fa07f54d 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/CodeRules/RewriteToHttpsRule.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.CodeRules public bool stopProcessing { get; set; } public int? SSLPort { get; set; } + public override RuleResult ApplyRule(RewriteContext context) { if (!context.HttpContext.Request.IsHttps) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs index 8279da7831..ea678502de 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ConditionPatternParser.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { @@ -10,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// Parses the "CondPattern" portion of the RewriteCond. /// RewriteCond TestString CondPattern /// - public static class ConditionPatternParser + public class ConditionPatternParser { private const char Not = '!'; private const char Dash = '-'; @@ -26,7 +25,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// The CondPattern portion of a mod_rewrite RewriteCond. /// A new parsed condition. - public static ParsedModRewriteInput ParseActionCondition(string condition) + public ParsedModRewriteInput ParseActionCondition(string condition) { if (condition == null) { @@ -39,7 +38,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(condition, context.Index)); } - // If we hit a !, make sure the condition is inverted when resolving the string + // If we hit a !, invert the condition if (context.Current == Not) { results.Invert = true; @@ -139,7 +138,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// /// - public static ParsedModRewriteInput ParseProperty(ParserContext context, bool invert) + private static ParsedModRewriteInput ParseProperty(ParserContext context, bool invert) { if (!context.Next()) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs index de38c0ce3b..4610619ebf 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FileParser.cs @@ -15,6 +15,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite var rules = new List(); var builder = new RuleBuilder(); var lineNum = 0; + + // parsers + var testStringParser = new TestStringParser(); + var conditionParser = new ConditionPatternParser(); + var regexParser = new RuleRegexParser(); + var flagsParser = new FlagParser(); + var tokenizer = new Tokenizer(); + while ((line = input.ReadLine()) != null) { lineNum++; @@ -26,7 +34,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { continue; } - var tokens = Tokenizer.Tokenize(line); + var tokens = tokenizer.Tokenize(line); if (tokens.Count > 4) { // This means the line didn't have an appropriate format, throw format exception @@ -40,13 +48,13 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "RewriteCond": try { - var pattern = TestStringParser.Parse(tokens[1]); - var condActionParsed = ConditionPatternParser.ParseActionCondition(tokens[2]); + var pattern = testStringParser.Parse(tokens[1]); + var condActionParsed = conditionParser.ParseActionCondition(tokens[2]); var flags = new Flags(); if (tokens.Count == 4) { - flags = FlagParser.Parse(tokens[3]); + flags = flagsParser.Parse(tokens[3]); } builder.AddConditionFromParts(pattern, condActionParsed, flags); @@ -59,14 +67,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite case "RewriteRule": try { - var regex = RuleRegexParser.ParseRuleRegex(tokens[1]); - var pattern = TestStringParser.Parse(tokens[2]); + var regex = regexParser.ParseRuleRegex(tokens[1]); + var pattern = testStringParser.Parse(tokens[2]); - // TODO see if we can have flags be null. - var flags = new Flags(); + Flags flags; if (tokens.Count == 4) { - flags = FlagParser.Parse(tokens[3]); + flags = flagsParser.Parse(tokens[3]); + } + else + { + flags = new Flags(); } builder.AddMatch(regex, flags); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs index 8252c89637..16a0900815 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/FlagParser.cs @@ -2,22 +2,68 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { public class FlagParser - { - public static Flags Parse(string flagString) + { + private readonly IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "b", FlagType.EscapeBackreference}, + { "c", FlagType.Chain }, + { "chain", FlagType.Chain}, + { "co", FlagType.Cookie }, + { "cookie", FlagType.Cookie }, + { "dpi", FlagType.DiscardPath }, + { "discardpath", FlagType.DiscardPath }, + { "e", FlagType.Env}, + { "env", FlagType.Env}, + { "end", FlagType.End }, + { "f", FlagType.Forbidden }, + { "forbidden", FlagType.Forbidden }, + { "g", FlagType.Gone }, + { "gone", FlagType.Gone }, + { "h", FlagType.Handler }, + { "handler", FlagType.Handler }, + { "l", FlagType.Last }, + { "last", FlagType.Last }, + { "n", FlagType.Next }, + { "next", FlagType.Next }, + { "nc", FlagType.NoCase }, + { "nocase", FlagType.NoCase }, + { "ne", FlagType.NoEscape }, + { "noescape", FlagType.NoEscape }, + { "ns", FlagType.NoSubReq }, + { "nosubreq", FlagType.NoSubReq }, + { "p", FlagType.Proxy }, + { "proxy", FlagType.Proxy }, + { "pt", FlagType.PassThrough }, + { "passthrough", FlagType.PassThrough }, + { "qsa", FlagType.QSAppend }, + { "qsappend", FlagType.QSAppend }, + { "qsd", FlagType.QSDiscard }, + { "qsdiscard", FlagType.QSDiscard }, + { "qsl", FlagType.QSLast }, + { "qslast", FlagType.QSLast }, + { "r", FlagType.Redirect }, + { "redirect", FlagType.Redirect }, + { "s", FlagType.Skip }, + { "skip", FlagType.Skip }, + { "t", FlagType.Type }, + { "type", FlagType.Type }, + }; + + public Flags Parse(string flagString) { if (string.IsNullOrEmpty(flagString)) { - return null; + throw new ArgumentNullException(nameof(flagString)); } // Check that flags are contained within [] - if (!flagString.StartsWith("[") || !flagString.EndsWith("]")) + if (!(flagString.StartsWith("[") && flagString.EndsWith("]"))) { - throw new FormatException(); + throw new FormatException("Flags should start and end with square brackets: [flags]"); } // Lexing esque step to split all flags. @@ -27,13 +73,20 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite foreach (string token in tokens) { var hasPayload = token.Split('='); + + FlagType flag; + if (!_ruleFlagLookup.TryGetValue(hasPayload[0], out flag)) + { + throw new FormatException($"Unrecognized flag: {hasPayload[0]}"); + } + if (hasPayload.Length == 2) { - flags.SetFlag(hasPayload[0], hasPayload[1]); + flags.SetFlag(flag, hasPayload[1]); } else { - flags.SetFlag(hasPayload[0], string.Empty); + flags.SetFlag(flag, string.Empty); } } return flags; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs index 29d3ea5fc5..5df8cc09be 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Flags.cs @@ -1,7 +1,6 @@ // 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; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite @@ -11,51 +10,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite // http://httpd.apache.org/docs/current/expr.html#vars public class Flags { - private static IDictionary _ruleFlagLookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { - { "b", FlagType.EscapeBackreference}, - { "c", FlagType.Chain }, - { "chain", FlagType.Chain}, - { "co", FlagType.Cookie }, - { "cookie", FlagType.Cookie }, - { "dpi", FlagType.DiscardPath }, - { "discardpath", FlagType.DiscardPath }, - { "e", FlagType.Env}, - { "env", FlagType.Env}, - { "end", FlagType.End }, - { "f", FlagType.Forbidden }, - { "forbidden", FlagType.Forbidden }, - { "g", FlagType.Gone }, - { "gone", FlagType.Gone }, - { "h", FlagType.Handler }, - { "handler", FlagType.Handler }, - { "l", FlagType.Last }, - { "last", FlagType.Last }, - { "n", FlagType.Next }, - { "next", FlagType.Next }, - { "nc", FlagType.NoCase }, - { "nocase", FlagType.NoCase }, - { "ne", FlagType.NoEscape }, - { "noescape", FlagType.NoEscape }, - { "ns", FlagType.NoSubReq }, - { "nosubreq", FlagType.NoSubReq }, - { "p", FlagType.Proxy }, - { "proxy", FlagType.Proxy }, - { "pt", FlagType.PassThrough }, - { "passthrough", FlagType.PassThrough }, - { "qsa", FlagType.QSAppend }, - { "qsappend", FlagType.QSAppend }, - { "qsd", FlagType.QSDiscard }, - { "qsdiscard", FlagType.QSDiscard }, - { "qsl", FlagType.QSLast }, - { "qslast", FlagType.QSLast }, - { "r", FlagType.Redirect }, - { "redirect", FlagType.Redirect }, - { "s", FlagType.Skip }, - { "skip", FlagType.Skip }, - { "t", FlagType.Type }, - { "type", FlagType.Type }, - }; - public IDictionary FlagDictionary { get; } public Flags(IDictionary flags) @@ -68,16 +22,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite FlagDictionary = new Dictionary(); } - public void SetFlag(string flag, string value) - { - FlagType res; - if (!_ruleFlagLookup.TryGetValue(flag, out res)) - { - throw new FormatException("Unrecognized flag"); - } - SetFlag(res, value); - } - public void SetFlag(FlagType flag, string value) { if (value == null) diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs index 35c2ecd0df..a935946829 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRedirectAction.cs @@ -3,7 +3,6 @@ using System; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs index 2fd6a0940c..23b4be1eed 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ModRewriteRewriteAction.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs index 0510803c4f..4095fb3da4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleBuilder.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PreActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; @@ -32,13 +31,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite public void AddRule(string rule) { // TODO - var tokens = Tokenizer.Tokenize(rule); - var regex = RuleRegexParser.ParseRuleRegex(tokens[1]); - var pattern = TestStringParser.Parse(tokens[2]); - var flags = new Flags(); + var tokens = new Tokenizer().Tokenize(rule); + var regex = new RuleRegexParser().ParseRuleRegex(tokens[1]); + var pattern = new TestStringParser().Parse(tokens[2]); + + Flags flags; if (tokens.Count == 4) { - flags = FlagParser.Parse(tokens[3]); + flags = new FlagParser().Parse(tokens[3]); + } + else + { + flags = new Flags(); } AddMatch(regex, flags); AddAction(pattern, flags); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs index e063b36bc4..272faf96e0 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/RuleRegexParser.cs @@ -5,9 +5,9 @@ using System; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite { - public static class RuleRegexParser + public class RuleRegexParser { - public static ParsedModRewriteInput ParseRuleRegex(string regex) + public ParsedModRewriteInput ParseRuleRegex(string regex) { if (regex == null || regex == string.Empty) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs index 5b664f4172..863fd44bba 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/ServerVariables.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; using Microsoft.Net.Http.Headers; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs index 4564c3cba1..bcedbb214f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/TestStringParser.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments; namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite @@ -32,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// $1 /// A new , containing a list of /// http://httpd.apache.org/docs/current/mod/mod_rewrite.html - public static Pattern Parse(string testString) + public Pattern Parse(string testString) { if (testString == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs index a13bdeb9ef..69c7880f50 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ModRewrite/Tokenizer.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// Tokenizes a mod_rewrite rule, delimited by spaces. /// - public static class Tokenizer + public class Tokenizer { private const char Space = ' '; private const char Escape = '\\'; @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite /// /// The rule to tokenize. /// A list of tokens. - public static List Tokenize(string rule) + public List Tokenize(string rule) { // TODO make list of strings a reference to the original rule? (run into problems with escaped spaces). // TODO handle "s and probably replace \ character with no slash. diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs index 2c6367ea67..99f8f014f4 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/Pattern.cs @@ -15,7 +15,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public string Evaluate(RewriteContext context, MatchResults ruleMatch, MatchResults condMatch) { - // TODO consider thread static for string builder - DAVID PERF foreach (var pattern in PatternSegments) { context.Builder.Append(pattern.Evaluate(context, ruleMatch, condMatch)); diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs similarity index 86% rename from src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs rename to src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs index 39703c5e2e..b6b9d5ae16 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/FileParser.cs @@ -7,15 +7,16 @@ using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; -using Microsoft.AspNetCore.Rewrite.Internal; namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { - public static class UrlRewriteFileParser + public class FileParser { private static readonly TimeSpan RegexTimeout = TimeSpan.FromMilliseconds(1); - public static List Parse(TextReader reader) + private InputParser _inputParser = new InputParser(); + + public List Parse(TextReader reader) { var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); @@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return null; } - private static void ParseRules(XElement rules, List result) + private void ParseRules(XElement rules, List result) { if (rules == null) { @@ -51,7 +52,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) + private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder) { builder.Name = rule.Attribute(RewriteTags.Name)?.Value; @@ -90,7 +91,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite ParseUrlAction(action, builder, stopProcessing); } - private static void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; if (parsedInputString == null) @@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax); } - private static void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { if (conditions == null) { @@ -139,7 +140,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) + private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax) { bool ignoreCase; if (!bool.TryParse(condition.Attribute(RewriteTags.IgnoreCase)?.Value, out ignoreCase)) @@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite Pattern input = null; try { - input = InputParser.ParseInputString(parsedInputString); + input = _inputParser.ParseInputString(parsedInputString); builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate); } @@ -180,7 +181,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) + private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing) { ActionType actionType; if (!Enum.TryParse(urlAction.Attribute(RewriteTags.Type)?.Value, out actionType)) @@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite try { - var input = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + var input = _inputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType); } catch (FormatException formatException) @@ -211,14 +212,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } } - private static void ThrowUrlFormatException(XElement element, string message) + private 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 static void ThrowUrlFormatException(XElement element, string message, Exception ex) + private 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 a4e33665a3..2e03d415f2 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite /// /// /// A new , containing a list of - public static Pattern ParseInputString(string testString) + public Pattern ParseInputString(string testString) { if (testString == null) { diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs index 2c4b9814ab..b8803c116b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteRuleBuilder.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlMatches; diff --git a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs index 944426b055..fb362718a5 100644 --- a/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs +++ b/src/Microsoft.AspNetCore.Rewrite/UrlRewriteExtensions.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Rewrite var path = Path.Combine(hostingEnv.ContentRootPath, filePath); using (var stream = File.OpenRead(path)) { - options.Rules.AddRange(UrlRewriteFileParser.Parse(new StreamReader(stream))); + options.Rules.AddRange(new FileParser().Parse(new StreamReader(stream))); }; return options; } @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite using (stream) { - options.Rules.AddRange(UrlRewriteFileParser.Parse(stream)); + options.Rules.AddRange(new FileParser().Parse(stream)); }; return options; } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs index d0d7ac7f57..c1a47b26da 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/ConditionActionTest.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("=hey", OperationType.Equal, "hey", ConditionType.StringComp)] public void ConditionParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { OperationType = operation, ConditionType = conditionType, Operand = variable, Invert = false }; Assert.True(CompareConditions(results, expected)); @@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public void ConditionParser_CheckRegexEqual() { var condition = @"(.*)"; - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false }; Assert.True(CompareConditions(results, expected)); @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("-x", OperationType.Executable, ConditionType.PropertyTest)] public void ConditionParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation , Invert = false }; Assert.True(CompareConditions(results, expected)); @@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("!-x", OperationType.Executable, ConditionType.PropertyTest)] public void ConditionParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = true }; Assert.True(CompareConditions(results, expected)); @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [InlineData("-ne1", OperationType.NotEqual, "1", ConditionType.IntComp)] public void ConditionParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond) { - var results = ConditionPatternParser.ParseActionCondition(condition); + var results = new ConditionPatternParser().ParseActionCondition(condition); var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false, Operand = variable }; Assert.True(CompareConditions(results, expected)); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs index 39c6cedb24..1cc8aa9a6f 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/FlagParserTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckSingleTerm() { - var results = FlagParser.Parse("[NC]"); + var results = new FlagParser().Parse("[NC]"); var dict = new Dictionary(); dict.Add(FlagType.NoCase, string.Empty); var expected = new Flags(dict); @@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckManyTerms() { - var results = FlagParser.Parse("[NC,F,L]"); + var results = new FlagParser().Parse("[NC,F,L]"); var dict = new Dictionary(); dict.Add(FlagType.NoCase, string.Empty); dict.Add(FlagType.Forbidden, string.Empty); @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void FlagParser_CheckManyTermsWithEquals() { - var results = FlagParser.Parse("[NC,F,R=301]"); + var results = new FlagParser().Parse("[NC,F,R=301]"); var dict = new Dictionary(); dict.Add(FlagType.NoCase, string.Empty); dict.Add(FlagType.Forbidden, string.Empty); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs index fdcaf6b35d..7b8b5a74f5 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RewriteTokenizerTest.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite public void Tokenize_RewriteCondtion() { var testString = "RewriteCond %{HTTPS} !-f"; - var tokens = Tokenizer.Tokenize(testString); + var tokens = new Tokenizer().Tokenize(testString); var expected = new List(); expected.Add("RewriteCond"); @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite { // TODO need consultation on escape characters. var testString = @"RewriteCond %{HTTPS}\ what !-f"; - var tokens = Tokenizer.Tokenize(testString); + var tokens = new Tokenizer().Tokenize(testString); var expected = new List(); expected.Add("RewriteCond"); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs index 5b3081a220..16a7954700 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/ModRewrite/RuleRegexParserTest.cs @@ -12,19 +12,19 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite [Fact] public void RuleRegexParser_ShouldThrowOnNull() { - Assert.Throws(() => RuleRegexParser.ParseRuleRegex(null)); + Assert.Throws(() => new RuleRegexParser().ParseRuleRegex(null)); } [Fact] public void RuleRegexParser_ShouldThrowOnEmpty() { - Assert.Throws(() => RuleRegexParser.ParseRuleRegex(string.Empty)); + Assert.Throws(() => new RuleRegexParser().ParseRuleRegex(string.Empty)); } [Fact] public void RuleRegexParser_RegularRegexExpression() { - var results = RuleRegexParser.ParseRuleRegex("(.*)"); + var results = new RuleRegexParser().ParseRuleRegex("(.*)"); Assert.False(results.Invert); Assert.Equal(results.Operand, "(.*)"); } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs index e9599a43d4..450c840f5d 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FileParserTests.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + var res = new FileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condList = new List(); condList.Add(new Condition { - Input = InputParser.ParseInputString("{HTTPS}"), + Input = new InputParser().ParseInputString("{HTTPS}"), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + var res = new FileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite var condList = new List(); condList.Add(new Condition { - Input = InputParser.ParseInputString("{HTTPS}"), + Input = new InputParser().ParseInputString("{HTTPS}"), Match = new RegexMatch(new Regex("^OFF$"), false) }); @@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite pattern: "article.aspx?id={R:1}&title={R:2}")); // act - var res = UrlRewriteFileParser.Parse(new StringReader(xml)); + var res = new FileParser().Parse(new StringReader(xml)); // assert AssertUrlRewriteRuleEquality(res, expected); @@ -147,7 +147,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite { return new UrlRewriteRule { - Action = new RewriteAction(RuleTerminiation.Continue, InputParser.ParseInputString(Url), clearQuery: false), + Action = new RewriteAction(RuleTerminiation.Continue, new InputParser().ParseInputString(Url), clearQuery: false), Name = name, Enabled = enabled, InitialMatch = new RegexMatch(new Regex("^OFF$"), false) @@ -190,6 +190,9 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite Assert.Equal(c1.Input.PatternSegments.Count, c2.Input.PatternSegments.Count); } } + + Assert.Equal(r1.Action.GetType(), r2.Action.GetType()); + Assert.Equal(r1.InitialMatch.GetType(), r2.InitialMatch.GetType()); } } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs index 7ba0bc07a0..18011f4d40 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) { // Arrange, Act, Assert - var ex = Assert.Throws(() => UrlRewriteFileParser.Parse(new StringReader(input))); + var ex = Assert.Throws(() => new FileParser().Parse(new StringReader(input))); Assert.Equal(ex.Message, expected); } } diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs index 0fa95393c0..4ed8edf88a 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite public void InputParser_ParseLiteralString() { var testString = "hello/hey/what"; - var result = InputParser.ParseInputString(testString); + var result = new InputParser().ParseInputString(testString); Assert.Equal(result.PatternSegments.Count, 1); } @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("foo/", 1)] public void InputParser_ParseStringWithBackReference(string testString, int expected) { - var result = InputParser.ParseInputString(testString); + var result = new InputParser().ParseInputString(testString); Assert.Equal(result.PatternSegments.Count, expected); } @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{R:1}/{C:1}", "hey/foo/foo")] public void EvaluateBackReferenceRule(string testString, string expected) { - var middle = InputParser.ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/ToLower:/what", "hey/ToLower:/what")] public void EvaluatToLowerRule(string testString, string expected) { - var middle = InputParser.ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("hey/{UrlEncode:}", "hey/%3Chey%3E")] public void EvaluatUriEncodeRule(string testString, string expected) { - var middle = InputParser.ParseInputString(testString); + var middle = new InputParser().ParseInputString(testString); var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch(), CreateTestCondMatch()); Assert.Equal(result, expected); } @@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("{HTTPS")] public void FormatExceptionsOnBadSyntax(string testString) { - Assert.Throws(() => InputParser.ParseInputString(testString)); + Assert.Throws(() => new InputParser().ParseInputString(testString)); } private RewriteContext CreateTestRewriteContext()