Added support for IIS global rules (#169)

This commit is contained in:
David Peden 2017-02-03 18:20:41 -06:00 committed by Mikael Mengistu
parent 24a95f6c5d
commit 4fa6ed3792
14 changed files with 219 additions and 69 deletions

View File

@ -14,18 +14,30 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
public IList<Condition> Conditions { get; }
public UrlAction Action { get; }
public bool TrackAllCaptures { get; }
public bool Global { get; }
public IISUrlRewriteRule(string name,
UrlMatch initialMatch,
IList<Condition> conditions,
UrlAction action,
bool trackAllCaptures)
: this(name, initialMatch, conditions, action, trackAllCaptures, false)
{
}
public IISUrlRewriteRule(string name,
UrlMatch initialMatch,
IList<Condition> conditions,
UrlAction action,
bool trackAllCaptures,
bool global)
{
Name = name;
InitialMatch = initialMatch;
Conditions = conditions;
Action = action;
TrackAllCaptures = trackAllCaptures;
Global = global;
}
public virtual void ApplyRule(RewriteContext context)

View File

@ -18,8 +18,9 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
/// compare to the condition. Can contain server variables, back references, etc.
/// </summary>
/// <param name="testString"></param>
/// <param name="global"></param>
/// <returns>A new <see cref="Pattern"/>, containing a list of <see cref="PatternSegment"/></returns>
public Pattern ParseInputString(string testString)
public Pattern ParseInputString(string testString, bool global)
{
if (testString == null)
{
@ -27,10 +28,10 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
}
var context = new ParserContext(testString);
return ParseString(context);
return ParseString(context, global);
}
private static Pattern ParseString(ParserContext context)
private static Pattern ParseString(ParserContext context, bool global)
{
var results = new List<PatternSegment>();
while (context.Next())
@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
// missing {
throw new FormatException(Resources.FormatError_InputParserMissingCloseBrace(context.Index));
}
ParseParameter(context, results);
ParseParameter(context, results, global);
}
else if (context.Current == CloseBrace)
{
@ -59,7 +60,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
return new Pattern(results);
}
private static void ParseParameter(ParserContext context, IList<PatternSegment> results)
private static void ParseParameter(ParserContext context, IList<PatternSegment> results, bool global)
{
context.Mark();
// Four main cases:
@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
{
// This is just a server variable, so we do a lookup and verify the server variable exists.
parameter = context.Capture();
results.Add(ServerVariables.FindServerVariable(parameter, context));
results.Add(ServerVariables.FindServerVariable(parameter, context, global));
return;
}
else if (context.Current == Colon)
@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
{
case "ToLower":
{
var pattern = ParseString(context);
var pattern = ParseString(context, global);
results.Add(new ToLowerSegment(pattern));
// at this point, we expect our context to be on the ending closing brace,
@ -105,7 +106,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
}
case "UrlEncode":
{
var pattern = ParseString(context);
var pattern = ParseString(context, global);
results.Add(new UrlEncodeSegment(pattern));
if (context.Current != CloseBrace)

View File

@ -9,7 +9,15 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
{
public static class ServerVariables
{
public static PatternSegment FindServerVariable(string serverVariable, ParserContext context)
/// <summary>
/// Returns the matching <see cref="PatternSegment"/> for the given <paramref name="serverVariable"/>
/// </summary>
/// <param name="serverVariable">The server variable</param>
/// <param name="context">The parser context which is utilized when an exception is thrown</param>
/// <param name="global">Indicates if the rule being parsed is a global rule</param>
/// <exception cref="FormatException">Thrown when the server variable is unknown</exception>
/// <returns>The matching <see cref="PatternSegment"/></returns>
public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, bool global)
{
switch (serverVariable)
{
@ -35,7 +43,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
case "HTTP_CONNECTION":
return new HeaderSegment(HeaderNames.Connection);
case "HTTP_URL":
return new UrlSegment();
return global ? (PatternSegment)new GlobalRuleUrlSegment() : (PatternSegment)new UrlSegment();
case "HTTPS":
return new IsHttpsUrlSegment();
case "LOCAL_ADDR":
@ -53,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
case "REQUEST_FILENAME":
return new RequestFileNameSegment();
case "REQUEST_URI":
return new UrlSegment();
return global ? (PatternSegment)new GlobalRuleUrlSegment() : (PatternSegment)new UrlSegment();
default:
throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index));
}

View File

@ -22,40 +22,33 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
if (xmlRoot != null)
{
var result = new List<IISUrlRewriteRule>();
// TODO Global rules are currently not treated differently than normal rules, fix.
// See: https://github.com/aspnet/BasicMiddleware/issues/59
ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result);
ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result);
ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true);
ParseRules(xmlRoot.Descendants(RewriteTags.Rules).FirstOrDefault(), result, global: false);
return result;
}
return null;
}
private void ParseRules(XElement rules, IList<IISUrlRewriteRule> result)
private void ParseRules(XElement rules, IList<IISUrlRewriteRule> result, bool global)
{
if (rules == null)
{
return;
}
if (string.Equals(rules.Name.ToString(), "GlobalRules", StringComparison.OrdinalIgnoreCase))
{
throw new NotSupportedException("Support for global rules has not been implemented yet");
}
foreach (var rule in rules.Elements(RewriteTags.Rule))
{
var builder = new UrlRewriteRuleBuilder();
ParseRuleAttributes(rule, builder);
ParseRuleAttributes(rule, builder, global);
if (builder.Enabled)
{
result.Add(builder.Build());
result.Add(builder.Build(global));
}
}
}
private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder)
private void ParseRuleAttributes(XElement rule, UrlRewriteRuleBuilder builder, bool global)
{
builder.Name = rule.Attribute(RewriteTags.Name)?.Value;
@ -84,8 +77,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
}
ParseMatch(match, builder, patternSyntax);
ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax);
ParseUrlAction(action, builder, stopProcessing);
ParseConditions(rule.Element(RewriteTags.Conditions), builder, patternSyntax, global);
ParseUrlAction(action, builder, stopProcessing, global);
}
private void ParseMatch(XElement match, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax)
@ -101,7 +94,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
builder.AddUrlMatch(parsedInputString, ignoreCase, negate, patternSyntax);
}
private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax)
private void ParseConditions(XElement conditions, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool global)
{
if (conditions == null)
{
@ -114,11 +107,11 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
foreach (var cond in conditions.Elements(RewriteTags.Add))
{
ParseCondition(cond, builder, patternSyntax, trackAllCaptures);
ParseCondition(cond, builder, patternSyntax, trackAllCaptures, global);
}
}
private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool trackAllCaptures)
private void ParseCondition(XElement condition, UrlRewriteRuleBuilder builder, PatternSyntax patternSyntax, bool trackAllCaptures, bool global)
{
var ignoreCase = ParseBool(condition, RewriteTags.IgnoreCase, defaultValue: true);
var negate = ParseBool(condition, RewriteTags.Negate, defaultValue: false);
@ -133,7 +126,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
var parsedPatternString = condition.Attribute(RewriteTags.Pattern)?.Value;
try
{
var input = _inputParser.ParseInputString(parsedInputString);
var input = _inputParser.ParseInputString(parsedInputString, global);
builder.AddUrlCondition(input, parsedPatternString, patternSyntax, matchType, ignoreCase, negate, trackAllCaptures);
}
catch (FormatException formatException)
@ -142,7 +135,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
}
}
private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing)
private void ParseUrlAction(XElement urlAction, UrlRewriteRuleBuilder builder, bool stopProcessing, bool global)
{
var actionType = ParseEnum(urlAction, RewriteTags.Type, ActionType.None);
var redirectType = ParseEnum(urlAction, RewriteTags.RedirectType, RedirectType.Permanent);
@ -160,7 +153,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
try
{
var input = _inputParser.ParseInputString(url);
var input = _inputParser.ParseInputString(url, global);
builder.AddUrlAction(input, actionType, appendQuery, stopProcessing, (int)redirectType);
}
catch (FormatException formatException)

View File

@ -23,14 +23,14 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
private bool _matchAny;
private bool _trackAllCaptures;
public IISUrlRewriteRule Build()
public IISUrlRewriteRule Build(bool global)
{
if (_initialMatch == null || _action == null)
{
throw new InvalidOperationException("Cannot create UrlRewriteRule without action and match");
}
return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures);
return new IISUrlRewriteRule(Name, _initialMatch, _conditions, _action, _trackAllCaptures, global);
}
public void AddUrlAction(

View File

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http.Extensions;
namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments
{
public class GlobalRuleUrlSegment : PatternSegment
{
public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences)
{
return context.HttpContext.Request.GetEncodedUrl();
}
}
}

View File

@ -10,4 +10,4 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments
return context.HttpContext.Request.Path;
}
}
}
}

View File

@ -5,6 +5,8 @@ using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
using Microsoft.AspNetCore.Rewrite.Logging;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Internal;
@ -75,11 +77,10 @@ namespace Microsoft.AspNetCore.Rewrite
foreach (var rule in _options.Rules)
{
rule.ApplyRule(rewriteContext);
var currentUrl = new Lazy<string>(() => context.Request.Path + context.Request.QueryString);
switch (rewriteContext.Result)
{
case RuleResult.ContinueRules:
_logger.RewriteMiddlewareRequestContinueResults(currentUrl.Value);
_logger.RewriteMiddlewareRequestContinueResults(context.Request.GetEncodedUrl());
break;
case RuleResult.EndResponse:
_logger.RewriteMiddlewareRequestResponseComplete(
@ -87,7 +88,7 @@ namespace Microsoft.AspNetCore.Rewrite
context.Response.StatusCode);
return TaskCache.CompletedTask;
case RuleResult.SkipRemainingRules:
_logger.RewriteMiddlewareRequestStopRules(currentUrl.Value);
_logger.RewriteMiddlewareRequestStopRules(context.Request.GetEncodedUrl());
return _next(context);
default:
throw new ArgumentOutOfRangeException($"Invalid rule termination {rewriteContext.Result}");

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
var condList = new List<Condition>();
condList.Add(new Condition
{
Input = new InputParser().ParseInputString("{HTTPS}"),
Input = new InputParser().ParseInputString("{HTTPS}", global: false),
Match = new RegexMatch(new Regex("^OFF$"), false)
});
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
var condList = new List<Condition>();
condList.Add(new Condition
{
Input = new InputParser().ParseInputString("{HTTPS}"),
Input = new InputParser().ParseInputString("{HTTPS}", global: false),
Match = new RegexMatch(new Regex("^OFF$"), false)
});
@ -128,6 +128,37 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
AssertUrlRewriteRuleEquality(expected, res);
}
[Fact]
public void Should_parse_global_rules()
{
// arrange
var xml = @"<rewrite>
<globalRules>
<rule name=""httpsOnly"" patternSyntax=""ECMAScript"" stopProcessing=""true"">
<match url="".*"" />
<conditions logicalGrouping=""MatchAll"" trackAllCaptures=""false"">
<add input=""{HTTPS}"" pattern=""off"" />
</conditions>
<action type=""Redirect"" url=""https://{HTTP_HOST}{REQUEST_URI}"" />
</rule>
</globalRules>
<rules>
<rule name=""Rewrite to article.aspx"">
<match url = ""^article/([0-9]+)/([_0-9a-z-]+)"" />
<action type=""Rewrite"" url =""article.aspx?id={R:1}&amp;title={R:2}"" />
</rule>
</rules>
</rewrite>";
// act
var rules = new UrlRewriteFileParser().Parse(new StringReader(xml));
// assert
Assert.Equal(2, rules.Count);
Assert.True(rules[0].Global);
Assert.False(rules[1].Global);
}
// Creates a rule with appropriate default values of the url rewrite rule.
private IISUrlRewriteRule CreateTestRule(List<Condition> conditions,
LogicalGrouping condGrouping = LogicalGrouping.MatchAll,
@ -147,7 +178,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
)
{
return new IISUrlRewriteRule(name, new RegexMatch(new Regex("^OFF$"), false), conditions,
new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url), queryStringAppend: false), trackAllCaptures: false);
new RewriteAction(RuleResult.ContinueRules, new InputParser().ParseInputString(url, global: false), queryStringAppend: false), trackAllCaptures: false);
}
// TODO make rules comparable?

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
public void InputParser_ParseLiteralString()
{
var testString = "hello/hey/what";
var result = new InputParser().ParseInputString(testString);
var result = new InputParser().ParseInputString(testString, global: false);
Assert.Equal(1, result.PatternSegments.Count);
}
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
[InlineData("foo/", 1)]
public void InputParser_ParseStringWithBackReference(string testString, int expected)
{
var result = new InputParser().ParseInputString(testString);
var result = new InputParser().ParseInputString(testString, global: false);
Assert.Equal(expected, result.PatternSegments.Count);
}
@ -44,7 +44,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 = new InputParser().ParseInputString(testString);
var middle = new InputParser().ParseInputString(testString, global: false);
var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences());
Assert.Equal(expected, result);
}
@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
[InlineData("hey/ToLower:/what", "hey/ToLower:/what")]
public void EvaluatToLowerRule(string testString, string expected)
{
var middle = new InputParser().ParseInputString(testString);
var middle = new InputParser().ParseInputString(testString, global: false);
var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences());
Assert.Equal(expected, result);
}
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
[InlineData("hey/{UrlEncode:<hey>}", "hey/%3Chey%3E")]
public void EvaluatUriEncodeRule(string testString, string expected)
{
var middle = new InputParser().ParseInputString(testString);
var middle = new InputParser().ParseInputString(testString, global: false);
var result = middle.Evaluate(CreateTestRewriteContext(), CreateTestRuleBackReferences(), CreateTestCondBackReferences());
Assert.Equal(expected, result);
}
@ -85,7 +85,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
[InlineData("{HTTPS")]
public void FormatExceptionsOnBadSyntax(string testString)
{
Assert.Throws<FormatException>(() => new InputParser().ParseInputString(testString));
Assert.Throws<FormatException>(() => new InputParser().ParseInputString(testString, global: false));
}
private RewriteContext CreateTestRewriteContext()

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Net.Http.Headers;
using Xunit;
@ -451,5 +452,33 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
Assert.Equal("Cannot access back reference at index 9. Only 5 back references were captured.", ex.Message);
}
[Fact]
public async Task Invoke_GlobalRuleConditionMatchesAgainstFullUri()
{
var xml = @"<rewrite>
<globalRules>
<rule name=""Test"" patternSyntax=""ECMAScript"" stopProcessing=""true"">
<match url="".*"" />
<conditions logicalGrouping=""MatchAll"" trackAllCaptures=""false"">
<add input=""{REQUEST_URI}"" pattern=""^http://localhost/([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})(/.*)"" />
</conditions>
<action type=""Rewrite"" url=""http://www.test.com{C:2}"" />
</rule>
</globalRules>
</rewrite>";
var options = new RewriteOptions().AddIISUrlRewrite(new StringReader(xml));
var builder = new WebHostBuilder()
.Configure(app =>
{
app.UseRewriter(options);
app.Run(context => context.Response.WriteAsync(context.Request.GetEncodedUrl()));
});
var server = new TestServer(builder);
var response = await server.CreateClient().GetStringAsync($"http://localhost/{Guid.NewGuid()}/foo/bar");
Assert.Equal("http://www.test.com/foo/bar", response);
}
}
}

View File

@ -13,22 +13,25 @@ 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)
[InlineData("CONTENT_LENGTH", "10", false)]
[InlineData("CONTENT_TYPE", "json", false)]
[InlineData("HTTP_ACCEPT", "accept", false)]
[InlineData("HTTP_COOKIE", "cookie", false)]
[InlineData("HTTP_HOST", "example.com", false)]
[InlineData("HTTP_REFERER", "referer", false)]
[InlineData("HTTP_USER_AGENT", "useragent", false)]
[InlineData("HTTP_CONNECTION", "connection", false)]
[InlineData("HTTP_URL", "/foo", false)]
[InlineData("HTTP_URL", "http://example.com/foo?bar=1", true)]
[InlineData("QUERY_STRING", "bar=1", false)]
[InlineData("REQUEST_FILENAME", "/foo", false)]
[InlineData("REQUEST_URI", "/foo", false)]
[InlineData("REQUEST_URI", "http://example.com/foo?bar=1", true)]
public void CheckServerVariableParsingAndApplication(string variable, string expected, bool global)
{
// Arrange and Act
var testParserContext = new ParserContext("test");
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext);
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, global);
var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
// Assert
Assert.Equal(expected, lookup);
@ -37,6 +40,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
private RewriteContext CreateTestHttpContext()
{
var context = new DefaultHttpContext();
context.Request.Scheme = "http";
context.Request.Host = new HostString("example.com");
context.Request.Path = PathString.FromUriComponent("/foo");
context.Request.QueryString = QueryString.FromUriComponent("?bar=1");
@ -68,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
var context = new DefaultHttpContext();
var rewriteContext = new RewriteContext { HttpContext = context };
var testParserContext = new ParserContext("test");
var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext);
var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext, global: false);
var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
Assert.Equal(string.Empty, lookup);

View File

@ -0,0 +1,47 @@
// 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.PatternSegments;
using Xunit;
namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments
{
public class GlobalRuleUrlSegmentTests
{
[Theory]
[InlineData("http", "localhost", 80, null, null, "http://localhost:80/")]
[InlineData("http", "localhost", 80, "/foo/bar", null, "http://localhost:80/foo/bar")]
[InlineData("http", "localhost", 80, "/foo bar", null, "http://localhost:80/foo%20bar")]
[InlineData("http", "localhost", 81, "/foo/bar", null, "http://localhost:81/foo/bar")]
[InlineData("http", "localhost", 80, null, "?foo=bar", "http://localhost:80/?foo=bar")]
[InlineData("https", "localhost", 443, "/foo/bar", null, "https://localhost:443/foo/bar")]
public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, string queryString, string expectedResult)
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.Scheme = scheme;
httpContext.Request.Host = new HostString(host, port);
if (!string.IsNullOrEmpty(path))
{
httpContext.Request.Path = new PathString(path);
}
if (!string.IsNullOrEmpty(queryString))
{
httpContext.Request.QueryString = new QueryString(queryString);
}
var context = new RewriteContext { HttpContext = httpContext };
context.HttpContext = httpContext;
// Act
var segment = new GlobalRuleUrlSegment();
var results = segment.Evaluate(context, null, null);
// Assert
Assert.Equal(expectedResult, results);
}
}
}

View File

@ -9,18 +9,27 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.PatternSegments
{
public class UrlSegmentTests
{
[Fact]
public void LocalPortSegment_AssertSegmentIsCorrect()
[Theory]
[InlineData("http", "localhost", 80, "/foo/bar", "/foo/bar")]
[InlineData("http", "localhost", 80, "/foo:bar", "/foo:bar")]
[InlineData("http", "localhost", 80, "/foo bar", "/foo%20bar")]
public void AssertSegmentIsCorrect(string scheme, string host, int port, string path, string expectedResult)
{
// Arrange
var segement = new UrlSegment();
var context = new RewriteContext { HttpContext = new DefaultHttpContext() };
context.HttpContext.Request.Path = new PathString("/foo/bar");
var httpContext = new DefaultHttpContext();
httpContext.Request.Scheme = scheme;
httpContext.Request.Host = new HostString(host, port);
httpContext.Request.Path = new PathString(path);
var context = new RewriteContext { HttpContext = httpContext };
context.HttpContext = httpContext;
// Act
var results = segement.Evaluate(context, null, null);
var segment = new UrlSegment();
var results = segment.Evaluate(context, null, null);
// Assert
Assert.Equal("/foo/bar", results);
Assert.Equal(expectedResult, results);
}
}
}
}