Skip to content

Commit 4a2bd2a

Browse files
mderrieyjkotalik
authored andcommitted
Source server variables from IIS when running ANCM in-proc (#10022)
1 parent 2c58d82 commit 4a2bd2a

16 files changed

+269
-66
lines changed

src/Middleware/Middleware.sln

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{179A
281281
EndProject
282282
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeaderPropagationSample", "HeaderPropagation\samples\HeaderPropagationSample\HeaderPropagationSample.csproj", "{CDE2E736-A034-4748-98C4-0DEDAAC8063D}"
283283
EndProject
284+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.IIS", "..\Servers\IIS\IIS\src\Microsoft.AspNetCore.Server.IIS.csproj", "{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}"
285+
EndProject
284286
Global
285287
GlobalSection(SolutionConfigurationPlatforms) = preSolution
286288
Debug|Any CPU = Debug|Any CPU
@@ -1527,6 +1529,18 @@ Global
15271529
{CDE2E736-A034-4748-98C4-0DEDAAC8063D}.Release|x64.Build.0 = Release|Any CPU
15281530
{CDE2E736-A034-4748-98C4-0DEDAAC8063D}.Release|x86.ActiveCfg = Release|Any CPU
15291531
{CDE2E736-A034-4748-98C4-0DEDAAC8063D}.Release|x86.Build.0 = Release|Any CPU
1532+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1533+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|Any CPU.Build.0 = Debug|Any CPU
1534+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x64.ActiveCfg = Debug|Any CPU
1535+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x64.Build.0 = Debug|Any CPU
1536+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x86.ActiveCfg = Debug|Any CPU
1537+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Debug|x86.Build.0 = Debug|Any CPU
1538+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|Any CPU.ActiveCfg = Release|Any CPU
1539+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|Any CPU.Build.0 = Release|Any CPU
1540+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x64.ActiveCfg = Release|Any CPU
1541+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x64.Build.0 = Release|Any CPU
1542+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x86.ActiveCfg = Release|Any CPU
1543+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861}.Release|x86.Build.0 = Release|Any CPU
15301544
EndGlobalSection
15311545
GlobalSection(SolutionProperties) = preSolution
15321546
HideSolutionNode = FALSE
@@ -1648,6 +1662,7 @@ Global
16481662
{8CDBD9C6-96D8-4987-AFCD-D248FBC7F02D} = {0437D207-864E-429C-92B4-9D08D290188C}
16491663
{179A159B-87EA-4353-BE92-4FB6CC05BC7D} = {0437D207-864E-429C-92B4-9D08D290188C}
16501664
{CDE2E736-A034-4748-98C4-0DEDAAC8063D} = {179A159B-87EA-4353-BE92-4FB6CC05BC7D}
1665+
{B9BE1823-B555-4AAB-AEBC-C8C3F48C8861} = {ACA6DDB9-7592-47CE-A740-D15BF307E9E0}
16511666
EndGlobalSection
16521667
GlobalSection(ExtensibilityGlobals) = postSolution
16531668
SolutionGuid = {83786312-A93B-4BB4-AB06-7C6913A59AFA}

src/Middleware/Rewrite/ref/Microsoft.AspNetCore.Rewrite.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<Compile Include="Microsoft.AspNetCore.Rewrite.netcoreapp3.0.cs" />
88
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
99
<Reference Include="Microsoft.AspNetCore.Http.Extensions" />
10+
<Reference Include="Microsoft.AspNetCore.Server.IIS" />
1011
<Reference Include="Microsoft.Extensions.Configuration.Abstractions" />
1112
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions" />
1213
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />

src/Middleware/Rewrite/ref/Microsoft.AspNetCore.Rewrite.netcoreapp3.0.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public static partial class ApacheModRewriteOptionsExtensions
1818
}
1919
public static partial class IISUrlRewriteOptionsExtensions
2020
{
21-
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, Microsoft.Extensions.FileProviders.IFileProvider fileProvider, string filePath) { throw null; }
22-
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, System.IO.TextReader reader) { throw null; }
21+
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; }
22+
public static Microsoft.AspNetCore.Rewrite.RewriteOptions AddIISUrlRewrite(this Microsoft.AspNetCore.Rewrite.RewriteOptions options, System.IO.TextReader reader, bool alwaysUseManagedServerVariables = false) { throw null; }
2323
}
2424
public partial interface IRule
2525
{
@@ -371,7 +371,7 @@ public virtual void ApplyRule(Microsoft.AspNetCore.Rewrite.RewriteContext contex
371371
public partial class InputParser
372372
{
373373
public InputParser() { }
374-
public InputParser(Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection rewriteMaps) { }
374+
public InputParser(Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISRewriteMapCollection rewriteMaps, bool alwaysUseManagedServerVariables) { }
375375
public Microsoft.AspNetCore.Rewrite.Internal.Pattern ParseInputString(string testString) { throw null; }
376376
public Microsoft.AspNetCore.Rewrite.Internal.Pattern ParseInputString(string testString, Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.UriMatchPart uriMatchPart) { throw null; }
377377
}
@@ -448,7 +448,7 @@ public static partial class RewriteTags
448448
}
449449
public static partial class ServerVariables
450450
{
451-
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; }
451+
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; }
452452
}
453453
public partial class UriMatchCondition : Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.Condition
454454
{
@@ -462,7 +462,7 @@ public enum UriMatchPart
462462
public partial class UrlRewriteFileParser
463463
{
464464
public UrlRewriteFileParser() { }
465-
public System.Collections.Generic.IList<Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule> Parse(System.IO.TextReader reader) { throw null; }
465+
public System.Collections.Generic.IList<Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite.IISUrlRewriteRule> Parse(System.IO.TextReader reader, bool alwaysUseManagedServerVariables) { throw null; }
466466
}
467467
public partial class UrlRewriteRuleBuilder
468468
{

src/Middleware/Rewrite/src/IISUrlRewriteOptionsExtensions.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
55
using System.IO;
6+
using Microsoft.AspNetCore.Http.Features;
67
using Microsoft.AspNetCore.Rewrite.Internal.IISUrlRewrite;
78
using Microsoft.Extensions.FileProviders;
89

@@ -19,7 +20,8 @@ public static class IISUrlRewriteOptionsExtensions
1920
/// <param name="options">The <see cref="RewriteOptions"/></param>
2021
/// <param name="fileProvider">The <see cref="IFileProvider"/> </param>
2122
/// <param name="filePath">The path to the file containing UrlRewrite rules.</param>
22-
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFileProvider fileProvider, string filePath)
23+
/// <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>
24+
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFileProvider fileProvider, string filePath, bool alwaysUseManagedServerVariables = false)
2325
{
2426
if (options == null)
2527
{
@@ -35,7 +37,7 @@ public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFile
3537

3638
using (var stream = file.CreateReadStream())
3739
{
38-
return AddIISUrlRewrite(options, new StreamReader(stream));
40+
return AddIISUrlRewrite(options, new StreamReader(stream), alwaysUseManagedServerVariables);
3941
}
4042
}
4143

@@ -44,7 +46,8 @@ public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, IFile
4446
/// </summary>
4547
/// <param name="options">The <see cref="RewriteOptions"/></param>
4648
/// <param name="reader">The text reader stream.</param>
47-
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader)
49+
/// <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>
50+
public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextReader reader, bool alwaysUseManagedServerVariables = false)
4851
{
4952
if (options == null)
5053
{
@@ -56,7 +59,7 @@ public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextR
5659
throw new ArgumentException(nameof(reader));
5760
}
5861

59-
var rules = new UrlRewriteFileParser().Parse(reader);
62+
var rules = new UrlRewriteFileParser().Parse(reader, alwaysUseManagedServerVariables);
6063

6164
foreach (var rule in rules)
6265
{
@@ -66,4 +69,4 @@ public static RewriteOptions AddIISUrlRewrite(this RewriteOptions options, TextR
6669
return options;
6770
}
6871
}
69-
}
72+
}

src/Middleware/Rewrite/src/Internal/IISUrlRewrite/InputParser.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -14,14 +14,16 @@ public class InputParser
1414
private const char OpenBrace = '{';
1515
private const char CloseBrace = '}';
1616
private readonly IISRewriteMapCollection _rewriteMaps;
17+
private readonly bool _alwaysUseManagedServerVariables;
1718

1819
public InputParser()
1920
{
2021
}
2122

22-
public InputParser(IISRewriteMapCollection rewriteMaps)
23+
public InputParser(IISRewriteMapCollection rewriteMaps, bool alwaysUseManagedServerVariables)
2324
{
2425
_rewriteMaps = rewriteMaps;
26+
_alwaysUseManagedServerVariables = alwaysUseManagedServerVariables;
2527
}
2628

2729
/// <summary>
@@ -98,7 +100,7 @@ private void ParseParameter(ParserContext context, IList<PatternSegment> results
98100
{
99101
// This is just a server variable, so we do a lookup and verify the server variable exists.
100102
parameter = context.Capture();
101-
results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart));
103+
results.Add(ServerVariables.FindServerVariable(parameter, context, uriMatchPart, _alwaysUseManagedServerVariables));
102104
return;
103105
}
104106
else if (context.Current == Colon)
Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -15,58 +15,89 @@ public static class ServerVariables
1515
/// <param name="serverVariable">The server variable</param>
1616
/// <param name="context">The parser context which is utilized when an exception is thrown</param>
1717
/// <param name="uriMatchPart">Indicates whether the full URI or the path should be evaluated for URL segments</param>
18+
/// <param name="alwaysUseManagedServerVariables">Determines whether server variables are sourced from the managed server</param>
1819
/// <exception cref="FormatException">Thrown when the server variable is unknown</exception>
1920
/// <returns>The matching <see cref="PatternSegment"/></returns>
20-
public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, UriMatchPart uriMatchPart)
21+
public static PatternSegment FindServerVariable(string serverVariable, ParserContext context, UriMatchPart uriMatchPart, bool alwaysUseManagedServerVariables)
2122
{
23+
Func<PatternSegment> managedVariableThunk = default;
24+
2225
switch (serverVariable)
2326
{
2427
// TODO Add all server variables here.
2528
case "ALL_RAW":
26-
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
29+
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
30+
break;
2731
case "APP_POOL_ID":
28-
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
32+
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
33+
break;
2934
case "CONTENT_LENGTH":
30-
return new HeaderSegment(HeaderNames.ContentLength);
35+
managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentLength);
36+
break;
3137
case "CONTENT_TYPE":
32-
return new HeaderSegment(HeaderNames.ContentType);
38+
managedVariableThunk = () => new HeaderSegment(HeaderNames.ContentType);
39+
break;
3340
case "HTTP_ACCEPT":
34-
return new HeaderSegment(HeaderNames.Accept);
41+
managedVariableThunk = () => new HeaderSegment(HeaderNames.Accept);
42+
break;
3543
case "HTTP_COOKIE":
36-
return new HeaderSegment(HeaderNames.Cookie);
44+
managedVariableThunk = () => new HeaderSegment(HeaderNames.Cookie);
45+
break;
3746
case "HTTP_HOST":
38-
return new HeaderSegment(HeaderNames.Host);
47+
managedVariableThunk = () => new HeaderSegment(HeaderNames.Host);
48+
break;
3949
case "HTTP_REFERER":
40-
return new HeaderSegment(HeaderNames.Referer);
50+
managedVariableThunk = () => new HeaderSegment(HeaderNames.Referer);
51+
break;
4152
case "HTTP_USER_AGENT":
42-
return new HeaderSegment(HeaderNames.UserAgent);
53+
managedVariableThunk = () => new HeaderSegment(HeaderNames.UserAgent);
54+
break;
4355
case "HTTP_CONNECTION":
44-
return new HeaderSegment(HeaderNames.Connection);
56+
managedVariableThunk = () => new HeaderSegment(HeaderNames.Connection);
57+
break;
4558
case "HTTP_URL":
46-
return new UrlSegment(uriMatchPart);
59+
managedVariableThunk = () => new UrlSegment(uriMatchPart);
60+
break;
4761
case "HTTPS":
48-
return new IsHttpsUrlSegment();
62+
managedVariableThunk = () => new IsHttpsUrlSegment();
63+
break;
4964
case "LOCAL_ADDR":
50-
return new LocalAddressSegment();
65+
managedVariableThunk = () => new LocalAddressSegment();
66+
break;
5167
case "HTTP_PROXY_CONNECTION":
52-
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
68+
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
69+
break;
5370
case "QUERY_STRING":
54-
return new QueryStringSegment();
71+
managedVariableThunk = () => new QueryStringSegment();
72+
break;
5573
case "REMOTE_ADDR":
56-
return new RemoteAddressSegment();
74+
managedVariableThunk = () => new RemoteAddressSegment();
75+
break;
5776
case "REMOTE_HOST":
58-
throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
77+
managedVariableThunk = () => throw new NotSupportedException(Resources.FormatError_UnsupportedServerVariable(serverVariable));
78+
break;
5979
case "REMOTE_PORT":
60-
return new RemotePortSegment();
80+
managedVariableThunk = () => new RemotePortSegment();
81+
break;
6182
case "REQUEST_FILENAME":
62-
return new RequestFileNameSegment();
83+
managedVariableThunk = () => new RequestFileNameSegment();
84+
break;
6385
case "REQUEST_METHOD":
64-
return new RequestMethodSegment();
86+
managedVariableThunk = () => new RequestMethodSegment();
87+
break;
6588
case "REQUEST_URI":
66-
return new UrlSegment(uriMatchPart);
89+
managedVariableThunk = () => new UrlSegment(uriMatchPart);
90+
break;
6791
default:
6892
throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(serverVariable, context.Index));
6993
}
94+
95+
if (alwaysUseManagedServerVariables)
96+
{
97+
return managedVariableThunk();
98+
}
99+
100+
return new IISServerVariableSegment(serverVariable, managedVariableThunk);
70101
}
71102
}
72103
}

src/Middleware/Rewrite/src/Internal/IISUrlRewrite/UrlRewriteFileParser.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -20,7 +20,8 @@ public class UrlRewriteFileParser
2020
/// Parse an IIS rewrite section into a list of <see cref="IISUrlRewriteRule"/>s.
2121
/// </summary>
2222
/// <param name="reader">The reader containing the rewrite XML</param>
23-
public IList<IISUrlRewriteRule> Parse(TextReader reader)
23+
/// <param name="alwaysUseManagedServerVariables">Determines whether server variables will be sourced from the managed server</param>
24+
public IList<IISUrlRewriteRule> Parse(TextReader reader, bool alwaysUseManagedServerVariables)
2425
{
2526
var xmlDoc = XDocument.Load(reader, LoadOptions.SetLineInfo);
2627
var xmlRoot = xmlDoc.Descendants(RewriteTags.Rewrite).FirstOrDefault();
@@ -30,7 +31,7 @@ public IList<IISUrlRewriteRule> Parse(TextReader reader)
3031
return null;
3132
}
3233

33-
_inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot));
34+
_inputParser = new InputParser(RewriteMapParser.Parse(xmlRoot), alwaysUseManagedServerVariables);
3435

3536
var result = new List<IISUrlRewriteRule>();
3637
ParseRules(xmlRoot.Descendants(RewriteTags.GlobalRules).FirstOrDefault(), result, global: true);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.AspNetCore.Server.IIS;
6+
7+
namespace Microsoft.AspNetCore.Rewrite.Internal.PatternSegments
8+
{
9+
internal class IISServerVariableSegment : PatternSegment
10+
{
11+
private readonly string _variableName;
12+
private readonly Func<PatternSegment> _fallbackThunk;
13+
14+
public IISServerVariableSegment(string variableName, Func<PatternSegment> fallbackThunk)
15+
{
16+
_variableName = variableName;
17+
_fallbackThunk = fallbackThunk;
18+
}
19+
20+
public override string Evaluate(RewriteContext context, BackReferenceCollection ruleBackReferences, BackReferenceCollection conditionBackReferences)
21+
{
22+
return context.HttpContext.GetIISServerVariable(_variableName) ?? _fallbackThunk().Evaluate(context, ruleBackReferences, conditionBackReferences);
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)