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

View File

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

View File

@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Rewrite
} }
public static partial class IISUrlRewriteOptionsExtensions 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, 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) { 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 public partial interface IRule
{ {
@ -371,7 +371,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
public partial class InputParser public partial class InputParser
{ {
public 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) { throw null; }
public Microsoft.AspNetCore.Rewrite.Internal.Pattern ParseInputString(string testString, Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart uriMatchPart) { 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 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 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 partial class UrlRewriteFileParser
{ {
public 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 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
@ -19,7 +20,8 @@ namespace Microsoft.AspNetCore.Rewrite
/// <param name="options">The <see cref="RewriteOptions"/></param> /// <param name="options">The <see cref="RewriteOptions"/></param>
/// <param name="fileProvider">The <see cref="IFileProvider"/> </param> /// <param name="fileProvider">The <see cref="IFileProvider"/> </param>
/// <param name="filePath">The path to the file containing UrlRewrite rules.</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) if (options == null)
{ {
@ -35,7 +37,7 @@ namespace Microsoft.AspNetCore.Rewrite
using (var stream = file.CreateReadStream()) 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> /// </summary>
/// <param name="options">The <see cref="RewriteOptions"/></param> /// <param name="options">The <see cref="RewriteOptions"/></param>
/// <param name="reader">The text reader stream.</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) if (options == null)
{ {
@ -56,7 +59,7 @@ namespace Microsoft.AspNetCore.Rewrite
throw new ArgumentException(nameof(reader)); throw new ArgumentException(nameof(reader));
} }
var rules = new UrlRewriteFileParser().Parse(reader); var rules = new UrlRewriteFileParser().Parse(reader, alwaysUseManagedServerVariables);
foreach (var rule in rules) foreach (var rule in rules)
{ {

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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -14,14 +14,16 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
private const char OpenBrace = '{'; private const char OpenBrace = '{';
private const char CloseBrace = '}'; private const char CloseBrace = '}';
private readonly IISRewriteMapCollection _rewriteMaps; private readonly IISRewriteMapCollection _rewriteMaps;
private readonly bool _alwaysUseManagedServerVariables;
public InputParser() public InputParser()
{ {
} }
public InputParser(IISRewriteMapCollection rewriteMaps) public InputParser(IISRewriteMapCollection rewriteMaps, bool alwaysUseManagedServerVariables)
{ {
_rewriteMaps = rewriteMaps; _rewriteMaps = rewriteMaps;
_alwaysUseManagedServerVariables = alwaysUseManagedServerVariables;
} }
/// <summary> /// <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. // This is just a server variable, so we do a lookup and verify the server variable exists.
parameter = context.Capture(); parameter = context.Capture();
results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart)); results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart, _alwaysUseManagedServerVariables));
return; return;
} }
else if (context.Current == Colon) 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -15,58 +15,89 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
/// <param name="serverVariable">The server variable</param> /// <param name="serverVariable">The server variable</param>
/// <param name="context">The parser context which is utilized when an exception is thrown</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="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> /// <exception cref="FormatException">Thrown when the server variable is unknown</exception>
/// <returns>The matching <see cref="PatternSegment"/></returns> /// <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) switch (serverVariable)
{ {
// TODO Add all server variables here. // TODO Add all server variables here.
case "ALL_RAW": case "ALL_RAW":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "APP_POOL_ID": case "APP_POOL_ID":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "CONTENT_LENGTH": case "CONTENT_LENGTH":
return new HeaderSegment(HeaderNames.ContentLength); managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentLength);
break;
case "CONTENT_TYPE": case "CONTENT_TYPE":
return new HeaderSegment(HeaderNames.ContentType); managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentType);
break;
case "HTTP_ACCEPT": case "HTTP_ACCEPT":
return new HeaderSegment(HeaderNames.Accept); managedVariableThunk = () => new HeaderSegment(HeaderNames.Accept);
break;
case "HTTP_COOKIE": case "HTTP_COOKIE":
return new HeaderSegment(HeaderNames.Cookie); managedVariableThunk = () => new HeaderSegment(HeaderNames.Cookie);
break;
case "HTTP_HOST": case "HTTP_HOST":
return new HeaderSegment(HeaderNames.Host); managedVariableThunk = () => new HeaderSegment(HeaderNames.Host);
break;
case "HTTP_REFERER": case "HTTP_REFERER":
return new HeaderSegment(HeaderNames.Referer); managedVariableThunk = () => new HeaderSegment(HeaderNames.Referer);
break;
case "HTTP_USER_AGENT": case "HTTP_USER_AGENT":
return new HeaderSegment(HeaderNames.UserAgent); managedVariableThunk = () => new HeaderSegment(HeaderNames.UserAgent);
break;
case "HTTP_CONNECTION": case "HTTP_CONNECTION":
return new HeaderSegment(HeaderNames.Connection); managedVariableThunk = () => new HeaderSegment(HeaderNames.Connection);
break;
case "HTTP_URL": case "HTTP_URL":
return new UrlSegment(uriMatchPart); managedVariableThunk = () => new UrlSegment(uriMatchPart);
break;
case "HTTPS": case "HTTPS":
return new IsHttpsUrlSegment(); managedVariableThunk = () => new IsHttpsUrlSegment();
break;
case "LOCAL_ADDR": case "LOCAL_ADDR":
return new LocalAddressSegment(); managedVariableThunk = () => new LocalAddressSegment();
break;
case "HTTP_PROXY_CONNECTION": case "HTTP_PROXY_CONNECTION":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "QUERY_STRING": case "QUERY_STRING":
return new QueryStringSegment(); managedVariableThunk = () => new QueryStringSegment();
break;
case "REMOTE_ADDR": case "REMOTE_ADDR":
return new RemoteAddressSegment(); managedVariableThunk = () => new RemoteAddressSegment();
break;
case "REMOTE_HOST": case "REMOTE_HOST":
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable)); managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
break;
case "REMOTE_PORT": case "REMOTE_PORT":
return new RemotePortSegment(); managedVariableThunk = () => new RemotePortSegment();
break;
case "REQUEST_FILENAME": case "REQUEST_FILENAME":
return new RequestFileNameSegment(); managedVariableThunk = () => new RequestFileNameSegment();
break;
case "REQUEST_METHOD": case "REQUEST_METHOD":
return new RequestMethodSegment(); managedVariableThunk = () => new RequestMethodSegment();
break;
case "REQUEST_URI": case "REQUEST_URI":
return new UrlSegment(uriMatchPart); managedVariableThunk = () => new UrlSegment(uriMatchPart);
break;
default: default:
throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index)); 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; 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. /// Parse an IIS rewrite section into a list of <see cref="IISUrlRewriteRule"/>s.
/// </summary> /// </summary>
/// <param name="reader">The reader containing the rewrite XML</param> /// <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 xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo);
var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault(); var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault();
@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite
return null; return null;
} }
_inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot)); _inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot), alwaysUseManagedServerVariables);
var result = new List<IISUrlRewriteRule>(); var result = new List<IISUrlRewriteRule>();
ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true); 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> <ItemGroup>
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" /> <Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
<Reference Include="Microsoft.AspNetCore.Http.Extensions" /> <Reference Include="Microsoft.AspNetCore.Http.Extensions" />
<Reference Include="Microsoft.AspNetCore.Server.IIS" />
<Reference Include="Microsoft.Extensions.Configuration.Abstractions" /> <Reference Include="Microsoft.Extensions.Configuration.Abstractions" />
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions" /> <Reference Include="Microsoft.Extensions.FileProviders.Abstractions" />
<Reference Include="Microsoft.Extensions.Logging.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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic; using System.Collections.Generic;
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
pattern: "article.aspx?id={R:1}&amp;title={R:2}")); pattern: "article.aspx?id={R:1}&amp;title={R:2}"));
// act // act
var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); var res = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert // assert
AssertUrlRewriteRuleEquality(expected, res); AssertUrlRewriteRuleEquality(expected, res);
@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
pattern: "article.aspx?id={R:1}&amp;title={R:2}")); pattern: "article.aspx?id={R:1}&amp;title={R:2}"));
// act // act
var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); var res = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert // assert
AssertUrlRewriteRuleEquality(expected, res); AssertUrlRewriteRuleEquality(expected, res);
@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
pattern: "article.aspx?id={R:1}&amp;title={R:2}")); pattern: "article.aspx?id={R:1}&amp;title={R:2}"));
// act // act
var res = new UrlRewriteFileParser().Parse(new StringReader(xml)); var res = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert // assert
AssertUrlRewriteRuleEquality(expected, res); AssertUrlRewriteRuleEquality(expected, res);
@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rewrite>"; </rewrite>";
// act // act
var rules = new UrlRewriteFileParser().Parse(new StringReader(xml)); var rules = new UrlRewriteFileParser().Parse(new StringReader(xml), false);
// assert // assert
Assert.Equal(2, rules.Count); Assert.Equal(2, rules.Count);

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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
public void ThrowFormatExceptionWithCorrectMessage(string input, string expected) public void ThrowFormatExceptionWithCorrectMessage(string input, string expected)
{ {
// Arrange, Act, Assert // 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); 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
[Fact] [Fact]
public void Should_throw_FormatException_if_no_rewrite_maps_are_defined() 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] [Fact]
@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
const string undefinedMapName = "apiMap"; const string undefinedMapName = "apiMap";
var map = new IISRewriteMap(definedMapName); var map = new IISRewriteMap(definedMapName);
var maps = new IISRewriteMapCollection { map }; 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] [Fact]
@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
var maps = new IISRewriteMapCollection { map }; var maps = new IISRewriteMapCollection { map };
var inputString = $"{{{expectedMapName}:{{R:1}}}}"; 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); Assert.Equal(1, pattern.PatternSegments.Count);
var segment = pattern.PatternSegments.Single(); var segment = pattern.PatternSegments.Single();

View File

@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
public void ThrowInvalidUrlRewriteFormatExceptionWithCorrectMessage(string input, string expected) public void ThrowInvalidUrlRewriteFormatExceptionWithCorrectMessage(string input, string expected)
{ {
// Arrange, Act, Assert // 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); 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. // 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 System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Rewrite.Internal; using Microsoft.AspNetCore.Rewrite.Internal;
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite; using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite namespace Microsoft.AspNetCore.Rewrite.Tests.IISUrlRewrite
{ {
public class ServerVariableTests public class ServerVariableTests
{ {
@ -32,13 +34,105 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
{ {
// Arrange and Act // Arrange and Act
var testParserContext = new ParserContext("test"); var testParserContext = new ParserContext("test");
var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart); var serverVar = ServerVariables.FindServerVariable(variable, testParserContext, uriMatchPart, true);
var lookup = serverVar.Evaluate(CreateTestHttpContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences); var lookup = serverVar.Evaluate(CreateTestRewriteContext(), CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
// Assert // Assert
Assert.Equal(expected, lookup); 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(); var context = new DefaultHttpContext();
context.Request.Method = HttpMethods.Get; 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.Referer] = "referer";
context.Request.Headers[HeaderNames.UserAgent] = "useragent"; context.Request.Headers[HeaderNames.UserAgent] = "useragent";
context.Request.Headers[HeaderNames.Connection] = "connection"; 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() private MatchResults CreateTestRuleMatch()
@ -74,7 +174,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
var context = new DefaultHttpContext(); var context = new DefaultHttpContext();
var rewriteContext = new RewriteContext { HttpContext = context }; var rewriteContext = new RewriteContext { HttpContext = context };
var testParserContext = new ParserContext("test"); 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); var lookup = serverVar.Evaluate(rewriteContext, CreateTestRuleMatch().BackReferences, CreateTestCondMatch().BackReferences);
Assert.Equal(string.Empty, lookup); 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO; using System.IO;
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rule> </rule>
</rules> </rules>
</rewrite>"); </rewrite>");
var rules = new UrlRewriteFileParser().Parse(xml); var rules = new UrlRewriteFileParser().Parse(xml, false);
Assert.Equal(1, rules.Count); Assert.Equal(1, rules.Count);
var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var context = new RewriteContext { HttpContext = new DefaultHttpContext() };
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rule> </rule>
</rules> </rules>
</rewrite>"); </rewrite>");
var rules = new UrlRewriteFileParser().Parse(xml); var rules = new UrlRewriteFileParser().Parse(xml, false);
Assert.Equal(1, rules.Count); Assert.Equal(1, rules.Count);
var context = new RewriteContext { HttpContext = new DefaultHttpContext() }; var context = new RewriteContext { HttpContext = new DefaultHttpContext() };
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.UrlRewrite
</rule> </rule>
</rules> </rules>
</rewrite>"); </rewrite>");
var rules = new UrlRewriteFileParser().Parse(xml); var rules = new UrlRewriteFileParser().Parse(xml, false);
Assert.Equal(1, rules.Count); Assert.Equal(1, rules.Count);
Assert.True(rules[0].Conditions.TrackAllCaptures); Assert.True(rules[0].Conditions.TrackAllCaptures);