Source server variables from IIS when running ANCM in-proc (#10022)

This commit is contained in:
Mickaël Derriey 2019-05-16 01:26:29 +10:00 committed by Justin Kotalik
parent 2c58d82d44
commit 4a2bd2adbf
16 changed files with 269 additions and 66 deletions

View File

@ -281,6 +281,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{179A
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeaderPropagationSample", "HeaderPropagation\samples\HeaderPropagationSample\HeaderPropagationSample.csproj", "{CDE2E736-A034-4748-98C4-0DEDAAC8063D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IIS", "..\Servers\IIS\IIS\src\Microsoft.AspNetCore.Server.IIS.csproj", "{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1527,6 +1529,18 @@ Global
{CDE2E736-A034-4748-98C4-0DEDAAC8063D}.Release|x64.Build.0 = Release|Any CPU
{CDE2E736-A034-4748-98C4-0DEDAAC8063D}.Release|x86.ActiveCfg = Release|Any CPU
{CDE2E736-A034-4748-98C4-0DEDAAC8063D}.Release|x86.Build.0 = Release|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x64.ActiveCfg = Debug|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x64.Build.0 = Debug|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x86.ActiveCfg = Debug|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x86.Build.0 = Debug|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|Any CPU.Build.0 = Release|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x64.ActiveCfg = Release|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x64.Build.0 = Release|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x86.ActiveCfg = Release|Any CPU
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1648,6 +1662,7 @@ Global
{8CDBD9C6-96D8-4987-AFCD-D248FBC7F02D} = {0437D207-864E-429C-92B4-9D08D290188C}
{179A159B-87EA-4353-BE92-4FB6CC05BC7D} = {0437D207-864E-429C-92B4-9D08D290188C}
{CDE2E736-A034-4748-98C4-0DEDAAC8063D} = {179A159B-87EA-4353-BE92-4FB6CC05BC7D}
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861} = {ACA6DDB9-7592-47CE-A740-D15BF307E9E0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {83786312-A93B-4BB4-AB06-7C6913A59AFA}

View File

@ -7,6 +7,7 @@
<Compile Include="Microsoft.AspNetCore.Rewrite.netcoreapp3.0.cs" />
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
<Reference Include="Microsoft.AspNetCore.Http.Extensions" />
<Reference Include="Microsoft.AspNetCore.Server.IIS" />
<Reference Include="Microsoft.Extensions.Configuration.Abstractions" />
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions" />
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />

View File

@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Rewrite
}
public static partial class IISUrlRewriteOptionsExtensions
{
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, Microsoft.Extensions.FileProviders.IFileProvider fileProvider, string filePath) { throw null; }
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, System.IO.TextReader reader) { throw null; }
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, Microsoft.Extensions.FileProviders.IFileProvider fileProvider, string filePath, bool alwaysUseManagedServerVariables = false) { throw null; }
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, System.IO.TextReader reader, bool alwaysUseManagedServerVariables = false) { throw null; }
}
public partial interface IRule
{
@ -371,7 +371,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
public partial class InputParser
{
public InputParser() { }
public InputParser(Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection rewriteMaps) { }
public InputParser(Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection rewriteMaps, bool alwaysUseManagedServerVariables) { }
public Microsoft.AspNetCore.Rewrite.Internal.Pattern ParseInputString(string testString) { throw null; }
public Microsoft.AspNetCore.Rewrite.Internal.Pattern ParseInputString(string testString, Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart uriMatchPart) { throw null; }
}
@ -448,7 +448,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
}
public static partial class ServerVariables
{
public static Microsoft.AspNetCore.Rewrite.Internal.PatternSegment FindServerVariable(string serverVariable, Microsoft.AspNetCore.Rewrite.Internal.ParserContext context, Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart uriMatchPart) { throw null; }
public static Microsoft.AspNetCore.Rewrite.Internal.PatternSegment FindServerVariable(string serverVariable, Microsoft.AspNetCore.Rewrite.Internal.ParserContext context, Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart uriMatchPart, bool alwaysUseManagedServerVariables) { throw null; }
}
public partial class UriMatchCondition : Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition
{
@ -462,7 +462,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
public partial class UrlRewriteFileParser
{
public UrlRewriteFileParser() { }
public System.Collections.Generic.IList<Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule> Parse(System.IO.TextReader reader) { throw null; }
public System.Collections.Generic.IList<Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule> Parse(System.IO.TextReader reader, bool alwaysUseManagedServerVariables) { throw null; }
}
public partial class UrlRewriteRuleBuilder
{

View File

@ -1,8 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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.Http.Features;
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
using Microsoft.Extensions.FileProviders;
@ -19,7 +20,8 @@ namespace Microsoft.AspNetCore.Rewrite
/// <param name="options">The <see cref="RewriteOptions"/></param>
/// <param name="fileProvider">The <see cref="IFileProvider"/> </param>
/// <param name="filePath">The path to the file containing UrlRewrite rules.</param>
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFileProvider fileProvider, string filePath)
/// <param name="alwaysUseManagedServerVariables">Server variables are by default sourced from the server if it supports the <see cref="IServerVariablesFeature"/> feature. Use <c>true</c> to disable that behavior</param>
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFileProvider fileProvider, string filePath, bool alwaysUseManagedServerVariables = false)
{
if (options == null)
{
@ -35,7 +37,7 @@ namespace Microsoft.AspNetCore.Rewrite
using (var stream = file.CreateReadStream())
{
return AddIISUrlRewrite(options, new StreamReader(stream));
return AddIISUrlRewrite(options, new StreamReader(stream), alwaysUseManagedServerVariables);
}
}
@ -44,7 +46,8 @@ namespace Microsoft.AspNetCore.Rewrite
/// </summary>
/// <param name="options">The <see cref="RewriteOptions"/></param>
/// <param name="reader">The text reader stream.</param>
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader)
/// <param name="alwaysUseManagedServerVariables">Server variables are by default sourced from the server if it supports the <see cref="IServerVariablesFeature"/> feature. Use <c>true</c> to disable that behavior</param>
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader, bool alwaysUseManagedServerVariables = false)
{
if (options == null)
{
@ -56,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite
throw new ArgumentException(nameof(reader));
}
var rules = new UrlRewriteFileParser().Parse(reader);
var rules = new UrlRewriteFileParser().Parse(reader, alwaysUseManagedServerVariables);
foreach (var rule in rules)
{
@ -66,4 +69,4 @@ namespace Microsoft.AspNetCore.Rewrite
return options;
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -14,14 +14,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
private const char OpenBrace = '{';
private const char CloseBrace = '}';
private readonly IISRewriteMapCollection _rewriteMaps;
private readonly bool _alwaysUseManagedServerVariables;
public InputParser()
{
}
public InputParser(IISRewriteMapCollection rewriteMaps)
public InputParser(IISRewriteMapCollection rewriteMaps, bool alwaysUseManagedServerVariables)
{
_rewriteMaps = rewriteMaps;
_alwaysUseManagedServerVariables = alwaysUseManagedServerVariables;
}
/// <summary>
@ -98,7 +100,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, uriMatchPart));
results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart, _alwaysUseManagedServerVariables));
return;
}
else if (context.Current == Colon)

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -15,58 +15,89 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
/// <param name="serverVariable">The server variable</param>
/// <param name="context">The parser context which is utilized when an exception is thrown</param>
/// <param name="uriMatchPart">Indicates whether the full URI or the path should be evaluated for URL segments</param>
/// <param name="alwaysUseManagedServerVariables">Determines whether server variables are sourced from the managed server</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, UriMatchPart uriMatchPart)
public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, UriMatchPart uriMatchPart, bool alwaysUseManagedServerVariables)
{
Func<PatternSegment> managedVariableThunk = default;
switch (serverVariable)
{
// TODO Add all server variables here.
case "ALL_RAW":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "APP_POOL_ID":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "CONTENT_LENGTH":
return new HeaderSegment(HeaderNames.ContentLength);
managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentLength);
break;
case "CONTENT_TYPE":
return new HeaderSegment(HeaderNames.ContentType);
managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentType);
break;
case "HTTP_ACCEPT":
return new HeaderSegment(HeaderNames.Accept);
managedVariableThunk = () => new HeaderSegment(HeaderNames.Accept);
break;
case "HTTP_COOKIE":
return new HeaderSegment(HeaderNames.Cookie);
managedVariableThunk = () => new HeaderSegment(HeaderNames.Cookie);
break;
case "HTTP_HOST":
return new HeaderSegment(HeaderNames.Host);
managedVariableThunk = () => new HeaderSegment(HeaderNames.Host);
break;
case "HTTP_REFERER":
return new HeaderSegment(HeaderNames.Referer);
managedVariableThunk = () => new HeaderSegment(HeaderNames.Referer);
break;
case "HTTP_USER_AGENT":
return new HeaderSegment(HeaderNames.UserAgent);
managedVariableThunk = () => new HeaderSegment(HeaderNames.UserAgent);
break;
case "HTTP_CONNECTION":
return new HeaderSegment(HeaderNames.Connection);
managedVariableThunk = () => new HeaderSegment(HeaderNames.Connection);
break;
case "HTTP_URL":
return new UrlSegment(uriMatchPart);
managedVariableThunk = () => new UrlSegment(uriMatchPart);
break;
case "HTTPS":
return new IsHttpsUrlSegment();
managedVariableThunk = () => new IsHttpsUrlSegment();
break;
case "LOCAL_ADDR":
return new LocalAddressSegment();
managedVariableThunk = () => new LocalAddressSegment();
break;
case "HTTP_PROXY_CONNECTION":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "QUERY_STRING":
return new QueryStringSegment();
managedVariableThunk = () => new QueryStringSegment();
break;
case "REMOTE_ADDR":
return new RemoteAddressSegment();
managedVariableThunk = () => new RemoteAddressSegment();
break;
case "REMOTE_HOST":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "REMOTE_PORT":
return new RemotePortSegment();
managedVariableThunk = () => new RemotePortSegment();
break;
case "REQUEST_FILENAME":
return new RequestFileNameSegment();
managedVariableThunk = () => new RequestFileNameSegment();
break;
case "REQUEST_METHOD":
return new RequestMethodSegment();
managedVariableThunk = () => new RequestMethodSegment();
break;
case "REQUEST_URI":
return new UrlSegment(uriMatchPart);
managedVariableThunk = () => new UrlSegment(uriMatchPart);
break;
default:
throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index));
}
if (alwaysUseManagedServerVariables)
{
return managedVariableThunk();
}
return new IISServerVariableSegment(serverVariable, managedVariableThunk);
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -20,7 +20,8 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
/// Parse an IIS rewrite section into a list of <see cref="IISUrlRewriteRule"/>s.
/// </summary>
/// <param name="reader">The reader containing the rewrite XML</param>
public IList<IISUrlRewriteRule> Parse(TextReader reader)
/// <param name="alwaysUseManagedServerVariables">Determines whether server variables will be sourced from the managed server</param>
public IList<IISUrlRewriteRule> Parse(TextReader reader, bool alwaysUseManagedServerVariables)
{
var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo);
var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault();
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
return null;
}
_inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot));
_inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot), alwaysUseManagedServerVariables);
var result = new List<IISUrlRewriteRule>();
ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true);

View File

@ -0,0 +1,25 @@
// 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.Server.IIS;
namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments
{
internal class IISServerVariableSegment : PatternSegment
{
private readonly string _variableName;
private readonly Func<PatternSegment> _fallbackThunk;
public IISServerVariableSegment(string variableName, Func<PatternSegment> fallbackThunk)
{
_variableName = variableName;
_fallbackThunk = fallbackThunk;
}
public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences)
{
return context.HttpContext.GetIISServerVariable(_variableName) ?? _fallbackThunk().Evaluate(context, ruleBackReferences, conditionBackReferences);
}
}
}

View File

@ -15,6 +15,7 @@
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
<Reference Include="Microsoft.AspNetCore.Http.Extensions" />
<Reference Include="Microsoft.AspNetCore.Server.IIS" />
<Reference Include="Microsoft.Extensions.Configuration.Abstractions" />
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions" />
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
pattern: "article.aspx?id={R:1}&amp;title={R:2}"));
// act
var res = new UrlRewriteFileParser().Parse(new StringReader(xml));
var res = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert
AssertUrlRewriteRuleEquality(expected, res);
@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
pattern: "article.aspx?id={R:1}&amp;title={R:2}"));
// act
var res = new UrlRewriteFileParser().Parse(new StringReader(xml));
var res = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert
AssertUrlRewriteRuleEquality(expected, res);
@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
pattern: "article.aspx?id={R:1}&amp;title={R:2}"));
// act
var res = new UrlRewriteFileParser().Parse(new StringReader(xml));
var res = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert
AssertUrlRewriteRuleEquality(expected, res);
@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rewrite>";
// act
var rules = new UrlRewriteFileParser().Parse(new StringReader(xml));
var rules = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert
Assert.Equal(2, rules.Count);
@ -219,4 +219,4 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
}
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -63,8 +63,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
public void ThrowFormatExceptionWithCorrectMessage(string input, string expected)
{
// Arrange, Act, Assert
var ex = Assert.Throws<FormatException>(() => new UrlRewriteFileParser().Parse(new StringReader(input)));
var ex = Assert.Throws<FormatException>(() => new UrlRewriteFileParser().Parse(new StringReader(input), false));
Assert.Equal(expected, ex.Message);
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
[Fact]
public void Should_throw_FormatException_if_no_rewrite_maps_are_defined()
{
Assert.Throws<FormatException>(() => new InputParser(null).ParseInputString("{apiMap:{R:1}}", UriMatchPart.Path));
Assert.Throws<FormatException>(() => new InputParser(null, false).ParseInputString("{apiMap:{R:1}}", UriMatchPart.Path));
}
[Fact]
@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
const string undefinedMapName = "apiMap";
var map = new IISRewriteMap(definedMapName);
var maps = new IISRewriteMapCollection { map };
Assert.Throws<FormatException>(() => new InputParser(maps).ParseInputString($"{{{undefinedMapName}:{{R:1}}}}", UriMatchPart.Path));
Assert.Throws<FormatException>(() => new InputParser(maps, false).ParseInputString($"{{{undefinedMapName}:{{R:1}}}}", UriMatchPart.Path));
}
[Fact]
@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
var maps = new IISRewriteMapCollection { map };
var inputString = $"{{{expectedMapName}:{{R:1}}}}";
var pattern = new InputParser(maps).ParseInputString(inputString, UriMatchPart.Path);
var pattern = new InputParser(maps, false).ParseInputString(inputString, UriMatchPart.Path);
Assert.Equal(1, pattern.PatternSegments.Count);
var segment = pattern.PatternSegments.Single();

View File

@ -211,8 +211,8 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
public void ThrowInvalidUrlRewriteFormatExceptionWithCorrectMessage(string input, string expected)
{
// Arrange, Act, Assert
var ex = Assert.Throws<InvalidUrlRewriteFormatException>(() => new UrlRewriteFileParser().Parse(new StringReader(input)));
var ex = Assert.Throws<InvalidUrlRewriteFormatException>(() => new UrlRewriteFileParser().Parse(new StringReader(input), false));
Assert.Equal(expected, ex.Message);
}
}
}
}

View File

@ -1,14 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Rewrite.Internal;
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
namespace Microsoft.AspNetCore.Rewrite.Tests.IISUrlRewrite
{
public class ServerVariableTests
{
@ -32,13 +34,105 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
{
// Arrange and Act
var testParserContext = new ParserContext("test");
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart);
var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart, true);
var lookup = serverVar.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
// Assert
Assert.Equal(expected, lookup);
}
private RewriteContext CreateTestHttpContext()
[Theory]
[InlineData("CONTENT_LENGTH", "20", UriMatchPart.Path)]
[InlineData("CONTENT_TYPE", "text/xml", UriMatchPart.Path)]
[InlineData("HTTP_ACCEPT", "other-accept", UriMatchPart.Path)]
[InlineData("HTTP_COOKIE", "other-cookie", UriMatchPart.Path)]
[InlineData("HTTP_HOST", "otherexample.com", UriMatchPart.Path)]
[InlineData("HTTP_REFERER", "other-referer", UriMatchPart.Path)]
[InlineData("HTTP_USER_AGENT", "other-useragent", UriMatchPart.Path)]
[InlineData("HTTP_CONNECTION", "other-connection", UriMatchPart.Path)]
[InlineData("HTTP_URL", "http://otherexample.com/other-foo?bar=2", UriMatchPart.Full)]
[InlineData("HTTP_URL", "http://otherexample.com/other-foo?bar=2", UriMatchPart.Path)]
[InlineData("QUERY_STRING", "bar=2", UriMatchPart.Path)]
[InlineData("REQUEST_FILENAME", "/other-foo", UriMatchPart.Path)]
[InlineData("REQUEST_URI", "/other-foo", UriMatchPart.Path)]
[InlineData("REQUEST_URI", "/other-foo", UriMatchPart.Full)]
[InlineData("REQUEST_METHOD", "POST", UriMatchPart.Full)]
public void CheckServerVariableFeatureHasPrecedenceWhenEnabled(string variable, string expected, UriMatchPart uriMatchPart)
{
// Arrange and Act
var testParserContext = new ParserContext("test");
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart, false);
var httpContext = CreateTestHttpContext();
httpContext.Features.Set<IServerVariablesFeature>(new TestServerVariablesFeature(new Dictionary<string, string>
{
["CONTENT_LENGTH"] = "20",
["CONTENT_TYPE"] = "text/xml",
["HTTP_ACCEPT"] = "other-accept",
["HTTP_COOKIE"] = "other-cookie",
["HTTP_HOST"] = "otherexample.com",
["HTTP_REFERER"] = "other-referer",
["HTTP_USER_AGENT"] = "other-useragent",
["HTTP_CONNECTION"] = "other-connection",
["HTTP_URL"] = "http://otherexample.com/other-foo?bar=2",
["QUERY_STRING"] = "bar=2",
["REQUEST_FILENAME"] = "/other-foo",
["REQUEST_URI"] = "/other-foo",
["REQUEST_METHOD"] = "POST"
}));
var rewriteContext = CreateTestRewriteContext(httpContext);
var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
// Assert
Assert.Equal(expected, lookup);
}
[Theory]
[InlineData("CONTENT_LENGTH", "10", UriMatchPart.Path)]
[InlineData("CONTENT_TYPE", "json", UriMatchPart.Path)]
[InlineData("HTTP_ACCEPT", "accept", UriMatchPart.Path)]
[InlineData("HTTP_COOKIE", "cookie", UriMatchPart.Path)]
[InlineData("HTTP_HOST", "example.com", UriMatchPart.Path)]
[InlineData("HTTP_REFERER", "referer", UriMatchPart.Path)]
[InlineData("HTTP_USER_AGENT", "useragent", UriMatchPart.Path)]
[InlineData("HTTP_CONNECTION", "connection", UriMatchPart.Path)]
[InlineData("HTTP_URL", "/foo", UriMatchPart.Path)]
[InlineData("HTTP_URL", "http://example.com/foo?bar=1", UriMatchPart.Full)]
[InlineData("QUERY_STRING", "bar=1", UriMatchPart.Path)]
[InlineData("REQUEST_FILENAME", "/foo", UriMatchPart.Path)]
[InlineData("REQUEST_URI", "/foo", UriMatchPart.Path)]
[InlineData("REQUEST_URI", "http://example.com/foo?bar=1", UriMatchPart.Full)]
[InlineData("REQUEST_METHOD", "GET", UriMatchPart.Full)]
public void CheckServerVariableFeatureIsntUsedWhenDisabled(string variable, string expected, UriMatchPart uriMatchPart)
{
// Arrange and Act
var testParserContext = new ParserContext("test");
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart, true);
var httpContext = CreateTestHttpContext();
httpContext.Features.Set<IServerVariablesFeature>(new TestServerVariablesFeature(new Dictionary<string, string>
{
["CONTENT_LENGTH"] = "20",
["CONTENT_TYPE"] = "text/xml",
["HTTP_ACCEPT"] = "other-accept",
["HTTP_COOKIE"] = "other-cookie",
["HTTP_HOST"] = "otherexample.com",
["HTTP_REFERER"] = "other-referer",
["HTTP_USER_AGENT"] = "other-useragent",
["HTTP_CONNECTION"] = "other-connection",
["HTTP_URL"] = "http://otherexample.com/other-foo?bar=2",
["QUERY_STRING"] = "bar=2",
["REQUEST_FILENAME"] = "/other-foo",
["REQUEST_URI"] = "/other-foo",
["REQUEST_METHOD"] = "POST"
}));
var rewriteContext = CreateTestRewriteContext(httpContext);
var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
// Assert
Assert.Equal(expected, lookup);
}
private HttpContext CreateTestHttpContext()
{
var context = new DefaultHttpContext();
context.Request.Method = HttpMethods.Get;
@ -53,7 +147,13 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
context.Request.Headers[HeaderNames.Referer] = "referer";
context.Request.Headers[HeaderNames.UserAgent] = "useragent";
context.Request.Headers[HeaderNames.Connection] = "connection";
return new RewriteContext { HttpContext = context };
return context;
}
private RewriteContext CreateTestRewriteContext(HttpContext context = null)
{
return new RewriteContext { HttpContext = context ?? CreateTestHttpContext() };
}
private MatchResults CreateTestRuleMatch()
@ -74,7 +174,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, UriMatchPart.Path);
var serverVar = ServerVariables.FindServerVariable("QUERY_STRING", testParserContext, UriMatchPart.Path, true);
var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
Assert.Equal(string.Empty, lookup);

View File

@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Rewrite.Tests.IISUrlRewrite
{
public class TestServerVariablesFeature : IServerVariablesFeature
{
private readonly Dictionary<string, string> _variables;
public TestServerVariablesFeature(Dictionary<string, string> variables)
{
_variables = variables;
}
public string this[string variableName]
{
get => _variables[variableName];
set => _variables[variableName] = value;
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rule>
</rules>
</rewrite>");
var rules = new UrlRewriteFileParser().Parse(xml);
var rules = new UrlRewriteFileParser().Parse(xml, false);
Assert.Equal(1, rules.Count);
var context = new RewriteContext { HttpContext = new DefaultHttpContext() };
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rule>
</rules>
</rewrite>");
var rules = new UrlRewriteFileParser().Parse(xml);
var rules = new UrlRewriteFileParser().Parse(xml, false);
Assert.Equal(1, rules.Count);
var context = new RewriteContext { HttpContext = new DefaultHttpContext() };
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rule>
</rules>
</rewrite>");
var rules = new UrlRewriteFileParser().Parse(xml);
var rules = new UrlRewriteFileParser().Parse(xml, false);
Assert.Equal(1, rules.Count);
Assert.True(rules[0].Conditions.TrackAllCaptures);