-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Add AppContext switch in patch release to opt-out of breaking behavior change in ForwardedHeaders middleware. #62687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.TestHost; | ||
using Microsoft.DotNet.RemoteExecutor; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
|
@@ -1035,6 +1036,128 @@ public async Task IgnoreXForwardedHeadersFromUnknownProxy(ForwardedHeaders forwa | |
} | ||
} | ||
|
||
[Theory] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] The AppContext and environment-variable tests share nearly identical setup. Consider extracting the common host setup and assertion logic into a helper or combining them into a single parameterized test to reduce duplication. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
[InlineData(ForwardedHeaders.XForwardedFor)] | ||
[InlineData(ForwardedHeaders.XForwardedHost)] | ||
[InlineData(ForwardedHeaders.XForwardedProto)] | ||
[InlineData(ForwardedHeaders.XForwardedPrefix)] | ||
public void AppContextDoesNotValidateUnknownProxyWithoutForwardedFor(ForwardedHeaders forwardedHeaders) | ||
{ | ||
RemoteExecutor.Invoke(static async (forwardedHeadersName) => | ||
{ | ||
Assert.True(Enum.TryParse<ForwardedHeaders>(forwardedHeadersName, out var forwardedHeaders)); | ||
AppContext.SetSwitch("Microsoft.AspNetCore.HttpOverrides.IgnoreUnknownProxiesWithoutFor", true); | ||
using var host = new HostBuilder() | ||
.ConfigureWebHost(webHostBuilder => | ||
{ | ||
webHostBuilder | ||
.UseTestServer() | ||
.Configure(app => | ||
{ | ||
var options = new ForwardedHeadersOptions | ||
{ | ||
ForwardedHeaders = forwardedHeaders | ||
}; | ||
app.UseForwardedHeaders(options); | ||
}); | ||
}).Build(); | ||
|
||
await host.StartAsync(); | ||
|
||
var server = host.GetTestServer(); | ||
|
||
var context = await server.SendAsync(c => | ||
{ | ||
c.Request.Headers["X-Forwarded-For"] = "11.111.111.11"; | ||
c.Request.Headers["X-Forwarded-Host"] = "testhost"; | ||
c.Request.Headers["X-Forwarded-Proto"] = "Protocol"; | ||
c.Request.Headers["X-Forwarded-Prefix"] = "/pathbase"; | ||
c.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); | ||
c.Connection.RemotePort = 99; | ||
}); | ||
|
||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedFor)) | ||
{ | ||
// X-Forwarded-For ignored since 10.0.0.1 isn't in KnownProxies | ||
Assert.Equal("10.0.0.1", context.Connection.RemoteIpAddress.ToString()); | ||
} | ||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedHost)) | ||
{ | ||
Assert.Equal("testhost", context.Request.Host.ToString()); | ||
} | ||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedProto)) | ||
{ | ||
Assert.Equal("Protocol", context.Request.Scheme); | ||
} | ||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedPrefix)) | ||
{ | ||
Assert.Equal("/pathbase", context.Request.PathBase); | ||
} | ||
return RemoteExecutor.SuccessExitCode; | ||
}, forwardedHeaders.ToString()).Dispose(); | ||
} | ||
|
||
[Theory] | ||
[InlineData(ForwardedHeaders.XForwardedFor)] | ||
[InlineData(ForwardedHeaders.XForwardedHost)] | ||
[InlineData(ForwardedHeaders.XForwardedProto)] | ||
[InlineData(ForwardedHeaders.XForwardedPrefix)] | ||
public void EnvVariableDoesNotValidateUnknownProxyWithoutForwardedFor(ForwardedHeaders forwardedHeaders) | ||
{ | ||
RemoteExecutor.Invoke(static async (forwardedHeadersName) => | ||
{ | ||
Assert.True(Enum.TryParse<ForwardedHeaders>(forwardedHeadersName, out var forwardedHeaders)); | ||
Environment.SetEnvironmentVariable("MICROSOFT_ASPNETCORE_HTTPOVERRIDES_IGNORE_UNKNOWN_PROXIES_WITHOUT_FOR", "true"); | ||
using var host = new HostBuilder() | ||
.ConfigureWebHost(webHostBuilder => | ||
{ | ||
webHostBuilder | ||
.UseTestServer() | ||
.Configure(app => | ||
{ | ||
var options = new ForwardedHeadersOptions | ||
{ | ||
ForwardedHeaders = forwardedHeaders | ||
}; | ||
app.UseForwardedHeaders(options); | ||
}); | ||
}).Build(); | ||
|
||
await host.StartAsync(); | ||
|
||
var server = host.GetTestServer(); | ||
|
||
var context = await server.SendAsync(c => | ||
{ | ||
c.Request.Headers["X-Forwarded-For"] = "11.111.111.11"; | ||
c.Request.Headers["X-Forwarded-Host"] = "testhost"; | ||
c.Request.Headers["X-Forwarded-Proto"] = "Protocol"; | ||
c.Request.Headers["X-Forwarded-Prefix"] = "/pathbase"; | ||
c.Connection.RemoteIpAddress = IPAddress.Parse("10.0.0.1"); | ||
c.Connection.RemotePort = 99; | ||
}); | ||
|
||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedFor)) | ||
{ | ||
// X-Forwarded-For ignored since 10.0.0.1 isn't in KnownProxies | ||
Assert.Equal("10.0.0.1", context.Connection.RemoteIpAddress.ToString()); | ||
} | ||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedHost)) | ||
{ | ||
Assert.Equal("testhost", context.Request.Host.ToString()); | ||
} | ||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedProto)) | ||
{ | ||
Assert.Equal("Protocol", context.Request.Scheme); | ||
} | ||
if (forwardedHeaders.HasFlag(ForwardedHeaders.XForwardedPrefix)) | ||
{ | ||
Assert.Equal("/pathbase", context.Request.PathBase); | ||
} | ||
return RemoteExecutor.SuccessExitCode; | ||
}, forwardedHeaders.ToString()).Dispose(); | ||
} | ||
|
||
[Fact] | ||
public async Task PartiallyEnabledForwardsPartiallyChangesRequest() | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Extract the switch key string into a private
const string
(and reuse it for the environment-variable name) to avoid magic strings and ensure consistency.Copilot uses AI. Check for mistakes.