From 4ce3b8da6a2c4baa7473355e4f13aa7ee25bc27c Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 5 Aug 2016 16:43:56 -0700 Subject: [PATCH] Updating tests, Exception handling cleanup. --- .../Internal/ParserContext.cs | 20 +-- .../Internal/UrlRewrite/InputParser.cs | 22 +-- .../Internal/UrlRewrite/ServerVariables.cs | 6 +- .../UrlRewrite/UrlActions/RewriteAction.cs | 20 ++- .../UrlRewrite/UrlRewriteFileParser.cs | 92 ++++++++---- .../Properties/Resources.Designer.cs | 126 ++++++++++++++++ .../Resources.resx | 138 ++++++++++++++++++ .../FormatExceptionHandlingTests.cs | 120 +++++++++++++++ .../UrlRewrite/InputParserTests.cs | 1 + .../UrlRewrite/ServerVariableTests.cs | 63 ++++++++ 10 files changed, 557 insertions(+), 51 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs create mode 100644 src/Microsoft.AspNetCore.Rewrite/Resources.resx create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs create mode 100644 test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs index 34b78f5b67..18b7833889 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/ParserContext.cs @@ -9,43 +9,43 @@ namespace Microsoft.AspNetCore.Rewrite.Internal public class ParserContext { private readonly string _template; - private int _index; + public int Index { get; set; } private int? _mark; public ParserContext(string condition) { _template = condition; - _index = -1; + Index = -1; } public char Current { - get { return (_index < _template.Length && _index >= 0) ? _template[_index] : (char)0; } + get { return (Index < _template.Length && Index >= 0) ? _template[Index] : (char)0; } } public bool Back() { - return --_index >= 0; + return --Index >= 0; } public bool Next() { - return ++_index < _template.Length; + return ++Index < _template.Length; } public bool HasNext() { - return (_index + 1) < _template.Length; + return (Index + 1) < _template.Length; } public void Mark() { - _mark = _index; + _mark = Index; } public int GetIndex() { - return _index; + return Index; } public string Capture() @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal // TODO make this return a range rather than a string. if (_mark.HasValue) { - var value = _template.Substring(_mark.Value, _index - _mark.Value); + var value = _template.Substring(_mark.Value, Index - _mark.Value); _mark = null; return value; } @@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal } public string Error() { - return string.Format("Syntax Error at index: ", _index, " with character: ", Current); + return string.Format("Syntax Error at index: ", Index, " with character: ", Current); } } } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs index 8d45ac0433..08b666634b 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/InputParser.cs @@ -42,7 +42,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite // This is a server parameter, parse for a condition variable if (!context.Next()) { - throw new FormatException(context.Error()); + // missing { + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } ParseParameter(context, results); } @@ -100,10 +101,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite // has processed the new string. if (context.Current != CloseBrace) { - throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } + return; } - break; case "UrlDecode": { throw new NotImplementedException("UrlDecode is not supported."); @@ -115,10 +116,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite if (context.Current != CloseBrace) { - throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } + return; } - break; case "R": { var index = GetBackReferenceIndex(context); @@ -132,17 +133,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return; } default: - throw new FormatException("Unrecognized parameter type: " + parameter + ", terminated at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(parameter, context.Index)); } } } + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } private static int GetBackReferenceIndex(ParserContext context) { if (!context.Next()) { - throw new FormatException("No index avaible for backreference at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserNoBackreference(context.Index)); } context.Mark(); @@ -150,7 +152,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { if (!context.Next()) { - throw new FormatException("Lacking close brace for parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index)); } } @@ -158,12 +160,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite int index; if (!int.TryParse(res, out index)) { - throw new FormatException("Syntax error, invalid integer in response parameter at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserInvalidInteger(res, context.Index)); } if (index > 9 || index < 0) { - throw new FormatException("Invalid integer into backreference " + index + "at index: " + context.GetIndex()); + throw new FormatException(Resources.FormatError_InputParserIndexOutOfRange(res, context.Index)); } return index; } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs index 2b0fcad556..9fa1a84bcc 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/ServerVariables.cs @@ -28,8 +28,6 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new HeaderSegment(HeaderNames.Cookie); case "HTTP_HOST": return new HeaderSegment(HeaderNames.Host); - case "HTTP_PROXY_CONNECTION": - return new HeaderSegment(HeaderNames.ProxyAuthenticate); case "HTTP_REFERER": return new HeaderSegment(HeaderNames.Referer); case "HTTP_USER_AGENT": @@ -42,6 +40,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new IsHttpsSegment(); case "LOCAL_ADDR": return new LocalAddressSegment(); + case "HTTP_PROXY_CONNECTION": + throw new NotSupportedException("Proxy Connections not supported"); case "QUERY_STRING": return new QueryStringSegment(); case "REMOTE_ADDR": @@ -52,6 +52,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite return new RemotePortSegment(); case "REQUEST_FILENAME": return new RequestFileNameSegment(); + case "REQUEST_URI": + return new UrlSegment(); default: throw new FormatException("Unrecognized server variable."); } diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs index 9c7c463b82..105b023dd8 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlActions/RewriteAction.cs @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions { public class RewriteAction : UrlAction { + private readonly string ForwardSlash = "/"; public RuleTerminiation Result { get; } public bool ClearQuery { get; } @@ -46,12 +47,27 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions var split = pattern.IndexOf('?'); if (split >= 0) { - context.Request.Path = new PathString("/" + pattern.Substring(0, split)); + var path = pattern.Substring(0, split); + if (path.StartsWith(ForwardSlash)) + { + context.Request.Path = new PathString(path); + } + else + { + context.Request.Path = new PathString(ForwardSlash + path); + } context.Request.QueryString = context.Request.QueryString.Add(new QueryString(pattern.Substring(split))); } else { - context.Request.Path = new PathString("/" + pattern); + if (pattern.StartsWith(ForwardSlash)) + { + context.Request.Path = new PathString(pattern); + } + else + { + context.Request.Path = new PathString(ForwardSlash + pattern); + } } } return new RuleResult { Result = Result }; diff --git a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs index 289d9567e9..b5acf1c00f 100644 --- a/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs +++ b/src/Microsoft.AspNetCore.Rewrite/Internal/UrlRewrite/UrlRewriteFileParser.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Xml; using System.Xml.Linq; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlActions; using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite.UrlMatches; @@ -18,8 +19,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite public static List Parse(TextReader reader) { - var temp = XDocument.Load(reader); - var xmlRoot = temp.Descendants(RewriteTags.Rewrite).FirstOrDefault(); + var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo); + var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); if (xmlRoot != null) { @@ -44,7 +45,12 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { var res = new UrlRewriteRule(); SetRuleAttributes(rule, res); - CreateUrlAction(rule.Element(RewriteTags.Action), res, isGlobalRule); + var action = rule.Element(RewriteTags.Action); + if (action == null) + { + ThrowUrlFormatException(rule, "Rule does not have an associated action attribute"); + } + CreateUrlAction(action, res, isGlobalRule); if (res.Enabled) { result.Add(res); @@ -74,18 +80,17 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite { res.StopProcessing = stopProcessing; } - - CreateMatch(rule.Element(RewriteTags.Match), res); + var match = rule.Element(RewriteTags.Match); + if (match == null) + { + ThrowUrlFormatException(rule, "Cannot have rule without match"); + } + CreateMatch(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; @@ -100,6 +105,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } var parsedInputString = match.Attribute(RewriteTags.Url)?.Value; + if (parsedInputString == null) + { + ThrowUrlFormatException(match, "Match must have Url Attribute"); + } switch (res.PatternSyntax) { @@ -178,10 +187,18 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite var parsedString = condition.Attribute(RewriteTags.Input)?.Value; if (parsedString == null) { - throw new FormatException("Null input for condition"); + ThrowUrlFormatException(condition, "Conditions must have an input attribute"); } - var input = InputParser.ParseInputString(parsedString); + Pattern input = null; + try + { + input = InputParser.ParseInputString(parsedString); + } + catch (FormatException fe) + { + ThrowUrlFormatException(condition, fe.Message, fe); + } switch (res.PatternSyntax) { @@ -194,7 +211,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite parsedString = condition.Attribute(RewriteTags.Pattern)?.Value; if (parsedString == null) { - throw new FormatException("Pattern match does not have an associated pattern attribute in condition."); + ThrowUrlFormatException(condition, "Match does not have an associated pattern attribute in condition"); + } Regex regex = null; @@ -221,32 +239,30 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } break; default: - throw new FormatException("Unrecognized matchType."); + // TODO don't this this can ever be thrown + ThrowUrlFormatException(condition, "Unrecognized matchType"); + break; } - } break; case PatternSyntax.WildCard: - throw new NotImplementedException("Wildcard syntax is not supported."); + 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."); + ThrowUrlFormatException(condition, "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."); + ThrowUrlFormatException(condition, "Unrecognized pattern syntax"); + break; } } 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(); @@ -273,12 +289,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite actionRes.RedirectType = redirectType; } - actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + try + { + actionRes.Url = InputParser.ParseInputString(urlAction.Attribute(RewriteTags.Url)?.Value); + } + catch (FormatException fe) + { + ThrowUrlFormatException(urlAction, fe.Message, fe); + } - CreateUrlActionFromParsedAction(actionRes, globalRule, res); + CreateUrlActionFromParsedAction(urlAction, actionRes, globalRule, res); } - public static void CreateUrlActionFromParsedAction(ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res) + private static void CreateUrlActionFromParsedAction(XElement urlAction, ParsedUrlAction actionRes, bool globalRule, UrlRewriteRule res) { switch (actionRes.Type) { @@ -306,11 +329,26 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite } break; case ActionType.AbortRequest: - throw new FormatException("Abort requests are not supported."); + ThrowUrlFormatException(urlAction, "Abort Requests are not supported."); + break; case ActionType.CustomResponse: // TODO - throw new FormatException("Custom Responses are not supported"); + ThrowUrlFormatException(urlAction, "Custom Responses are not supported"); + break; } } + + 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 static void ThrowUrlFormatException(XElement element, string message, Exception ex) + { + var line = ((IXmlLineInfo)element).LineNumber; + var col = ((IXmlLineInfo)element).LinePosition; + throw new FormatException(Resources.FormatError_UrlRewriteParseError(message, line, col), ex); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..3be99059c0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Properties/Resources.Designer.cs @@ -0,0 +1,126 @@ +// +namespace Microsoft.AspNetCore.Rewrite +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNetCore.Rewrite.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + /// + internal static string Error_UrlRewriteParseError + { + get { return GetString("Error_UrlRewriteParseError"); } + } + + /// + /// Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + /// + internal static string FormatError_UrlRewriteParseError(object p0, object p1, object p2) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_UrlRewriteParseError"), p0, p1, p2); + } + + /// + /// Index out of range for backreference: '{0}' at string index: '{1}' + /// + internal static string Error_InputParserIndexOutOfRange + { + get { return GetString("Error_InputParserIndexOutOfRange"); } + } + + /// + /// Index out of range for backreference: '{0}' at string index: '{1}' + /// + internal static string FormatError_InputParserIndexOutOfRange(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserIndexOutOfRange"), p0, p1); + } + + /// + /// Cannot parse '{0}' to integer at string index: '{1}' + /// + internal static string Error_InputParserInvalidInteger + { + get { return GetString("Error_InputParserInvalidInteger"); } + } + + /// + /// Cannot parse '{0}' to integer at string index: '{1}' + /// + internal static string FormatError_InputParserInvalidInteger(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserInvalidInteger"), p0, p1); + } + + /// + /// Missing close brace for parameter at string index: '{0}' + /// + internal static string Error_InputParserMissingCloseBrace + { + get { return GetString("Error_InputParserMissingCloseBrace"); } + } + + /// + /// Missing close brace for parameter at string index: '{0}' + /// + internal static string FormatError_InputParserMissingCloseBrace(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserMissingCloseBrace"), p0); + } + + /// + /// Missing backreference for parameter at string index: '{0}' + /// + internal static string Error_InputParserNoBackreference + { + get { return GetString("Error_InputParserNoBackreference"); } + } + + /// + /// Missing backreference for parameter at string index: '{0}' + /// + internal static string FormatError_InputParserNoBackreference(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserNoBackreference"), p0); + } + + /// + /// Unrecognized parameter type: '{0}', terminated at string index: '{1}' + /// + internal static string Error_InputParserUnrecognizedParameter + { + get { return GetString("Error_InputParserUnrecognizedParameter"); } + } + + /// + /// Unrecognized parameter type: '{0}', terminated at string index: '{1}' + /// + internal static string FormatError_InputParserUnrecognizedParameter(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Error_InputParserUnrecognizedParameter"), p0, p1); + } + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) + { + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + } + + return value; + } + } +} diff --git a/src/Microsoft.AspNetCore.Rewrite/Resources.resx b/src/Microsoft.AspNetCore.Rewrite/Resources.resx new file mode 100644 index 0000000000..ae034489ee --- /dev/null +++ b/src/Microsoft.AspNetCore.Rewrite/Resources.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Could not parse the UrlRewrite file. Message: '{0}'. Line number '{1}': '{2}'. + + + Index out of range for backreference: '{0}' at string index: '{1}' + + + Cannot parse '{0}' to integer at string index: '{1}' + + + Missing close brace for parameter at string index: '{0}' + + + Missing backreference for parameter at string index: '{0}' + + + Unrecognized parameter type: '{0}', terminated at string index: '{1}' + + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs new file mode 100644 index 0000000000..6a4f5f47e0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/FormatExceptionHandlingTests.cs @@ -0,0 +1,120 @@ +// 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.Rewrite.Internal.UrlRewrite; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class FormatExceptionHandlingTests + { + [Theory] + [InlineData( +@" + + + + +", + "Could not parse the UrlRewrite file. Message: 'Cannot have rule without match'. Line number '3': '10'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '1''. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Abort Requests are not supported.'. Line number '5': '14'.")] + [InlineData( +@" + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Custom Responses are not supported'. Line number '5': '14'.")] + [InlineData( +@" + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match must have Url Attribute'. Line number '4': '14'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Missing close brace for parameter at string index: '6''. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Conditions must have an input attribute'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + [InlineData( +@" + + + + + + + + + +", + "Could not parse the UrlRewrite file. Message: 'Match does not have an associated pattern attribute in condition'. Line number '6': '18'.")] + public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) + { + // Arrange, Act, Assert + var ex = Assert.Throws(() => UrlRewriteFileParser.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 bfcc08fc6d..31f6a2e984 100644 --- a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/InputParserTests.cs @@ -82,6 +82,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite [InlineData("{foo:1")] [InlineData("{UrlEncode:{R:}}")] [InlineData("{UrlEncode:{R:1}")] + [InlineData("{HTTPS")] public void FormatExceptionsOnBadSyntax(string testString) { Assert.Throws(() => InputParser.ParseInputString(testString)); diff --git a/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs new file mode 100644 index 0000000000..6f11a3c21f --- /dev/null +++ b/test/Microsoft.AspNetCore.Rewrite.Tests/UrlRewrite/ServerVariableTests.cs @@ -0,0 +1,63 @@ +// 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; +using Microsoft.AspNetCore.Rewrite.Internal.UrlRewrite; +using Microsoft.Net.Http.Headers; +using Xunit; + +namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite +{ + public class ServerVariableTests + { + [Theory] + [InlineData("CONTENT_LENGTH", "10")] + [InlineData("CONTENT_TYPE", "json")] + [InlineData("HTTP_ACCEPT", "accept")] + [InlineData("HTTP_COOKIE", "cookie")] + [InlineData("HTTP_HOST", "example.com")] + [InlineData("HTTP_REFERER", "referer")] + [InlineData("HTTP_USER_AGENT", "useragent")] + [InlineData("HTTP_CONNECTION", "connection")] + [InlineData("HTTP_URL", "/foo")] + [InlineData("QUERY_STRING", "?bar=1")] + [InlineData("REQUEST_FILENAME", "/foo")] + public void CheckServerVariableParsingAndApplication(string variable, string expected) + { + // Arrange and Act + var serverVar = ServerVariables.FindServerVariable(variable); + var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch(), CreateTestCondMatch()); + // Assert + Assert.Equal(expected, lookup); + } + + private HttpContext CreateTestHttpContext() + { + var context = new DefaultHttpContext(); + context.Request.Host = new HostString("example.com"); + context.Request.Path = new PathString("/foo"); + context.Request.QueryString = new QueryString("?bar=1"); + context.Request.ContentLength = 10; + context.Request.ContentType = "json"; + context.Request.Headers[HeaderNames.Accept] = "accept"; + context.Request.Headers[HeaderNames.Cookie] = "cookie"; + context.Request.Headers[HeaderNames.Referer] = "referer"; + context.Request.Headers[HeaderNames.UserAgent] = "useragent"; + context.Request.Headers[HeaderNames.Connection] = "connection"; + return context; + } + + private MatchResults CreateTestRuleMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return new MatchResults { BackReference = match.Groups, Success = match.Success }; + } + + private MatchResults CreateTestCondMatch() + { + var match = Regex.Match("foo/bar/baz", "(.*)/(.*)/(.*)"); + return new MatchResults { BackReference = match.Groups, Success = match.Success }; + } + } +}