parent
8b99354419
commit
b670246e3d
|
|
@ -1,8 +1,9 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
<UserSecretsId>aspnetcore-MetaPackagesSampleApp-20170406180413</UserSecretsId>
|
<UserSecretsId>aspnetcore-MetaPackagesSampleApp-20170406180413</UserSecretsId>
|
||||||
|
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -16,19 +16,16 @@ namespace SampleApp
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
HelloWorld();
|
CreateHostBuilder(args).Build().Run();
|
||||||
|
|
||||||
CustomUrl();
|
|
||||||
|
|
||||||
CustomRouter();
|
|
||||||
|
|
||||||
CustomApplicationBuilder();
|
|
||||||
|
|
||||||
StartupClass(args);
|
|
||||||
|
|
||||||
HostBuilderWithWebHost(args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
});
|
||||||
|
|
||||||
private static void HelloWorld()
|
private static void HelloWorld()
|
||||||
{
|
{
|
||||||
using (WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
|
using (WebHost.Start(context => context.Response.WriteAsync("Hello, World!")))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
// 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.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Extensions;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace SampleApp
|
namespace SampleApp
|
||||||
|
|
@ -15,12 +21,50 @@ namespace SampleApp
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
public void Configure(IApplicationBuilder app, IConfiguration config)
|
||||||
{
|
{
|
||||||
app.Run(async (context) =>
|
app.Run(async (context) =>
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync($"Hello from {nameof(Startup)}!");
|
await context.Response.WriteAsync($"Hello from {context.Request.GetDisplayUrl()}\r\n");
|
||||||
|
await context.Response.WriteAsync("\r\n");
|
||||||
|
|
||||||
|
await context.Response.WriteAsync("Headers:\r\n");
|
||||||
|
foreach (var header in context.Request.Headers)
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync($"{header.Key}: {header.Value}\r\n");
|
||||||
|
}
|
||||||
|
await context.Response.WriteAsync("\r\n");
|
||||||
|
|
||||||
|
await context.Response.WriteAsync("Connection:\r\n");
|
||||||
|
await context.Response.WriteAsync("RemoteIp: " + context.Connection.RemoteIpAddress + "\r\n");
|
||||||
|
await context.Response.WriteAsync("RemotePort: " + context.Connection.RemotePort + "\r\n");
|
||||||
|
await context.Response.WriteAsync("LocalIp: " + context.Connection.LocalIpAddress + "\r\n");
|
||||||
|
await context.Response.WriteAsync("LocalPort: " + context.Connection.LocalPort + "\r\n");
|
||||||
|
await context.Response.WriteAsync("ClientCert: " + context.Connection.ClientCertificate + "\r\n");
|
||||||
|
await context.Response.WriteAsync("\r\n");
|
||||||
|
|
||||||
|
await context.Response.WriteAsync("Environment Variables:\r\n");
|
||||||
|
var vars = Environment.GetEnvironmentVariables();
|
||||||
|
foreach (var key in vars.Keys.Cast<string>().OrderBy(key => key, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var value = vars[key];
|
||||||
|
await context.Response.WriteAsync($"{key}: {value}\r\n");
|
||||||
|
}
|
||||||
|
await context.Response.WriteAsync("\r\n");
|
||||||
|
|
||||||
|
await context.Response.WriteAsync("Config:\r\n");
|
||||||
|
await ShowConfig(context.Response, config);
|
||||||
|
await context.Response.WriteAsync("\r\n");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task ShowConfig(HttpResponse response, IConfiguration config)
|
||||||
|
{
|
||||||
|
foreach (var pair in config.GetChildren())
|
||||||
|
{
|
||||||
|
await response.WriteAsync($"{pair.Path}: {pair.Value}\r\n");
|
||||||
|
await ShowConfig(response, pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
"AllowedHosts": "example.com;localhost",
|
||||||
|
"Kestrel": {
|
||||||
|
"EndPoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://localhost:5005"
|
||||||
|
},
|
||||||
|
"Https": {
|
||||||
|
"Url": "https://localhost:5006"
|
||||||
|
}
|
||||||
|
|
||||||
|
// To enable HTTPS using a certificate file, set the path to a .pfx file in
|
||||||
|
// the "Path" property below and configure the password in user secrets.
|
||||||
|
// The "Password" property should be set in user secrets.
|
||||||
|
//"HttpsInlineCertFile": {
|
||||||
|
// "Url": "http://localhost:5005"
|
||||||
|
// "Certificate": {
|
||||||
|
// "Path": "<path to .pfx file>",
|
||||||
|
// "Password: "<cert password>"
|
||||||
|
// }
|
||||||
|
//},
|
||||||
|
|
||||||
|
//"HttpsInlineCertStore": {
|
||||||
|
// "Url": "http://localhost:5005"
|
||||||
|
// "Certificate": {
|
||||||
|
// "Subject": "",
|
||||||
|
// "Store": "",
|
||||||
|
// "Location": "",
|
||||||
|
// "AllowInvalid": "" // Set to "true" to allow invalid certificates (e.g. expired)
|
||||||
|
// }
|
||||||
|
//},
|
||||||
|
|
||||||
|
// This uses the cert defined under Certificates/Default or the development cert.
|
||||||
|
//"HttpsDefaultCert": {
|
||||||
|
// "Url": "http://localhost:5005"
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Certificates": {
|
||||||
|
//"Default": {
|
||||||
|
// "Path": "<file>",
|
||||||
|
// "Password": "<password>"
|
||||||
|
//},
|
||||||
|
|
||||||
|
// From cert store:
|
||||||
|
//"Default": {
|
||||||
|
// "Subject": "",
|
||||||
|
// "Store": "",
|
||||||
|
// "Location": "",
|
||||||
|
// "AllowInvalid": "" // Set to "true" to allow invalid certificates (e.g. expired certificates)
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,50 +1,2 @@
|
||||||
{
|
{
|
||||||
"AllowedHosts": "example.com;localhost",
|
|
||||||
"Kestrel": {
|
|
||||||
"EndPoints": {
|
|
||||||
"Http": {
|
|
||||||
"Url": "http://localhost:5005"
|
|
||||||
}
|
|
||||||
|
|
||||||
// To enable HTTPS using a certificate file, set the path to a .pfx file in
|
|
||||||
// the "Path" property below and configure the password in user secrets.
|
|
||||||
// The "Password" property should be set in user secrets.
|
|
||||||
//"HttpsInlineCertFile": {
|
|
||||||
// "Url": "http://localhost:5005"
|
|
||||||
// "Certificate": {
|
|
||||||
// "Path": "<path to .pfx file>",
|
|
||||||
// "Password: "<cert password>"
|
|
||||||
// }
|
|
||||||
//},
|
|
||||||
|
|
||||||
//"HttpsInlineCertStore": {
|
|
||||||
// "Url": "http://localhost:5005"
|
|
||||||
// "Certificate": {
|
|
||||||
// "Subject": "",
|
|
||||||
// "Store": "",
|
|
||||||
// "Location": "",
|
|
||||||
// "AllowInvalid": "" // Set to "true" to allow invalid certificates (e.g. expired)
|
|
||||||
// }
|
|
||||||
//},
|
|
||||||
|
|
||||||
// This uses the cert defined under Certificates/Default or the development cert.
|
|
||||||
//"HttpsDefaultCert": {
|
|
||||||
// "Url": "http://localhost:5005"
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Certificates": {
|
|
||||||
//"Default": {
|
|
||||||
// "Path": "<file>",
|
|
||||||
// "Password": "<password>"
|
|
||||||
//},
|
|
||||||
|
|
||||||
// From cert store:
|
|
||||||
//"Default": {
|
|
||||||
// "Subject": "",
|
|
||||||
// "Store": "",
|
|
||||||
// "Location": "",
|
|
||||||
// "AllowInvalid": "" // Set to "true" to allow invalid certificates (e.g. expired certificates)
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore
|
||||||
|
{
|
||||||
|
internal class ForwardedHeadersStartupFilter : IStartupFilter
|
||||||
|
{
|
||||||
|
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
|
||||||
|
{
|
||||||
|
return app =>
|
||||||
|
{
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
next(app);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore;
|
using Microsoft.AspNetCore;
|
||||||
|
|
||||||
|
|
@ -15,6 +15,8 @@ namespace Microsoft.Extensions.Hosting
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The following defaults are applied to the <see cref="IWebHostBuilder"/>:
|
/// The following defaults are applied to the <see cref="IWebHostBuilder"/>:
|
||||||
/// use Kestrel as the web server and configure it using the application's configuration providers,
|
/// use Kestrel as the web server and configure it using the application's configuration providers,
|
||||||
|
/// adds the HostFiltering middleware,
|
||||||
|
/// adds the ForwardedHeaders middleware if ASPNETCORE_FORWARDEDHEADERS_ENABLED=true,
|
||||||
/// and enable IIS integration.
|
/// and enable IIS integration.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="builder">The <see cref="IHostBuilder" /> instance to configure</param>
|
/// <param name="builder">The <see cref="IHostBuilder" /> instance to configure</param>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.HostFiltering;
|
using Microsoft.AspNetCore.HostFiltering;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -124,6 +125,8 @@ namespace Microsoft.AspNetCore
|
||||||
/// load <see cref="IConfiguration"/> from User Secrets when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development' using the entry assembly,
|
/// load <see cref="IConfiguration"/> from User Secrets when <see cref="IHostEnvironment.EnvironmentName"/> is 'Development' using the entry assembly,
|
||||||
/// load <see cref="IConfiguration"/> from environment variables,
|
/// load <see cref="IConfiguration"/> from environment variables,
|
||||||
/// configure the <see cref="ILoggerFactory"/> to log to the console and debug output,
|
/// configure the <see cref="ILoggerFactory"/> to log to the console and debug output,
|
||||||
|
/// adds the HostFiltering middleware,
|
||||||
|
/// adds the ForwardedHeaders middleware if ASPNETCORE_FORWARDEDHEADERS_ENABLED=true,
|
||||||
/// and enable IIS integration.
|
/// and enable IIS integration.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>The initialized <see cref="IWebHostBuilder"/>.</returns>
|
/// <returns>The initialized <see cref="IWebHostBuilder"/>.</returns>
|
||||||
|
|
@ -142,6 +145,8 @@ namespace Microsoft.AspNetCore
|
||||||
/// load <see cref="IConfiguration"/> from environment variables,
|
/// load <see cref="IConfiguration"/> from environment variables,
|
||||||
/// load <see cref="IConfiguration"/> from supplied command line args,
|
/// load <see cref="IConfiguration"/> from supplied command line args,
|
||||||
/// configure the <see cref="ILoggerFactory"/> to log to the console and debug output,
|
/// configure the <see cref="ILoggerFactory"/> to log to the console and debug output,
|
||||||
|
/// adds the HostFiltering middleware,
|
||||||
|
/// adds the ForwardedHeaders middleware if ASPNETCORE_FORWARDEDHEADERS_ENABLED=true,
|
||||||
/// and enable IIS integration.
|
/// and enable IIS integration.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="args">The command line args.</param>
|
/// <param name="args">The command line args.</param>
|
||||||
|
|
@ -224,6 +229,20 @@ namespace Microsoft.AspNetCore
|
||||||
|
|
||||||
services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
|
services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
|
||||||
|
|
||||||
|
if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
|
// Only loopback proxies are allowed by default. Clear that restriction because forwarders are
|
||||||
|
// being enabled by explicit configuration.
|
||||||
|
options.KnownNetworks.Clear();
|
||||||
|
options.KnownProxies.Clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
services.AddRouting();
|
services.AddRouting();
|
||||||
})
|
})
|
||||||
.UseIIS()
|
.UseIIS()
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Microsoft.AspNetCore" />
|
<Reference Include="Microsoft.AspNetCore" />
|
||||||
|
<Reference Include="Microsoft.AspNetCore.TestHost" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@ using System.Diagnostics.Tracing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.HostFiltering;
|
using Microsoft.AspNetCore.HostFiltering;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -57,6 +59,35 @@ namespace Microsoft.AspNetCore.Tests
|
||||||
Assert.Contains("NewHost", options.AllowedHosts);
|
Assert.Contains("NewHost", options.AllowedHosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task WebHostConfiguration_EnablesForwardedHeadersFromConfig()
|
||||||
|
{
|
||||||
|
using var host = WebHost.CreateDefaultBuilder()
|
||||||
|
.ConfigureAppConfiguration(configBuilder =>
|
||||||
|
{
|
||||||
|
configBuilder.AddInMemoryCollection(new[]
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("FORWARDEDHEADERS_ENABLED", "true" ),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.UseTestServer()
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
Assert.True(app.Properties.ContainsKey("ForwardedHeadersAdded"), "Forwarded Headers");
|
||||||
|
app.Run(context =>
|
||||||
|
{
|
||||||
|
Assert.Equal("https", context.Request.Scheme);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
await host.StartAsync();
|
||||||
|
var client = host.GetTestClient();
|
||||||
|
client.DefaultRequestHeaders.Add("x-forwarded-proto", "https");
|
||||||
|
var result = await client.GetAsync("http://localhost/");
|
||||||
|
result.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CreateDefaultBuilder_RegistersRouting()
|
public void CreateDefaultBuilder_RegistersRouting()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ namespace Microsoft.AspNetCore.TestHost
|
||||||
{
|
{
|
||||||
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureTestContainer<TContainer>(this Microsoft.AspNetCore.Hosting.IWebHostBuilder webHostBuilder, System.Action<TContainer> servicesConfiguration) { throw null; }
|
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureTestContainer<TContainer>(this Microsoft.AspNetCore.Hosting.IWebHostBuilder webHostBuilder, System.Action<TContainer> servicesConfiguration) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureTestServices(this Microsoft.AspNetCore.Hosting.IWebHostBuilder webHostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> servicesConfiguration) { throw null; }
|
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder ConfigureTestServices(this Microsoft.AspNetCore.Hosting.IWebHostBuilder webHostBuilder, System.Action<Microsoft.Extensions.DependencyInjection.IServiceCollection> servicesConfiguration) { throw null; }
|
||||||
|
public static System.Net.Http.HttpClient GetTestClient(this Microsoft.AspNetCore.Hosting.IWebHost host) { throw null; }
|
||||||
|
public static Microsoft.AspNetCore.TestHost.TestServer GetTestServer(this Microsoft.AspNetCore.Hosting.IWebHost host) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder UseSolutionRelativeContentRoot(this Microsoft.AspNetCore.Hosting.IWebHostBuilder builder, string solutionRelativePath, string solutionName = "*.sln") { throw null; }
|
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder UseSolutionRelativeContentRoot(this Microsoft.AspNetCore.Hosting.IWebHostBuilder builder, string solutionRelativePath, string solutionName = "*.sln") { throw null; }
|
||||||
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder UseSolutionRelativeContentRoot(this Microsoft.AspNetCore.Hosting.IWebHostBuilder builder, string solutionRelativePath, string applicationBasePath, string solutionName = "*.sln") { throw null; }
|
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder UseSolutionRelativeContentRoot(this Microsoft.AspNetCore.Hosting.IWebHostBuilder builder, string solutionRelativePath, string applicationBasePath, string solutionName = "*.sln") { throw null; }
|
||||||
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder UseTestServer(this Microsoft.AspNetCore.Hosting.IWebHostBuilder builder) { throw null; }
|
public static Microsoft.AspNetCore.Hosting.IWebHostBuilder UseTestServer(this Microsoft.AspNetCore.Hosting.IWebHostBuilder builder) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Hosting.Internal;
|
using Microsoft.AspNetCore.Hosting.Internal;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
|
@ -21,6 +22,26 @@ namespace Microsoft.AspNetCore.TestHost
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the TestServer from the host services.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static TestServer GetTestServer(this IWebHost host)
|
||||||
|
{
|
||||||
|
return (TestServer)host.Services.GetRequiredService<IServer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the test client from the TestServer in the host services.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static HttpClient GetTestClient(this IWebHost host)
|
||||||
|
{
|
||||||
|
return host.GetTestServer().CreateClient();
|
||||||
|
}
|
||||||
|
|
||||||
public static IWebHostBuilder ConfigureTestServices(this IWebHostBuilder webHostBuilder, Action<IServiceCollection> servicesConfiguration)
|
public static IWebHostBuilder ConfigureTestServices(this IWebHostBuilder webHostBuilder, Action<IServiceCollection> servicesConfiguration)
|
||||||
{
|
{
|
||||||
if (webHostBuilder == null)
|
if (webHostBuilder == null)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -9,6 +9,8 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
public static class ForwardedHeadersExtensions
|
public static class ForwardedHeadersExtensions
|
||||||
{
|
{
|
||||||
|
private const string ForwardedHeadersAdded = "ForwardedHeadersAdded";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forwards proxied headers onto current request
|
/// Forwards proxied headers onto current request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -21,7 +23,15 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.UseMiddleware<ForwardedHeadersMiddleware>();
|
// Don't add more than one instance of this middleware to the pipeline using the options from the DI container.
|
||||||
|
// Doing so could cause a request to be processed multiple times and the ForwardLimit to be exceeded.
|
||||||
|
if (!builder.Properties.ContainsKey(ForwardedHeadersAdded))
|
||||||
|
{
|
||||||
|
builder.Properties[ForwardedHeadersAdded] = true;
|
||||||
|
return builder.UseMiddleware<ForwardedHeadersMiddleware>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.TestHost;
|
using Microsoft.AspNetCore.TestHost;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -865,5 +866,66 @@ namespace Microsoft.AspNetCore.HttpOverrides
|
||||||
|
|
||||||
Assert.Equal(expectedRemoteIp, context.Connection.RemoteIpAddress.ToString());
|
Assert.Equal(expectedRemoteIp, context.Connection.RemoteIpAddress.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1, "httpa, httpb, httpc", "httpc", "httpa,httpb")]
|
||||||
|
[InlineData(2, "httpa, httpb, httpc", "httpb", "httpa")]
|
||||||
|
public async Task ForwardersWithDIOptionsRunsOnce(int limit, string header, string expectedScheme, string remainingHeader)
|
||||||
|
{
|
||||||
|
var builder = new WebHostBuilder()
|
||||||
|
.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
|
||||||
|
options.KnownProxies.Clear();
|
||||||
|
options.KnownNetworks.Clear();
|
||||||
|
options.ForwardLimit = limit;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
});
|
||||||
|
var server = new TestServer(builder);
|
||||||
|
|
||||||
|
var context = await server.SendAsync(c =>
|
||||||
|
{
|
||||||
|
c.Request.Headers["X-Forwarded-Proto"] = header;
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Equal(expectedScheme, context.Request.Scheme);
|
||||||
|
Assert.Equal(remainingHeader, context.Request.Headers["X-Forwarded-Proto"].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1, "httpa, httpb, httpc", "httpb", "httpa")]
|
||||||
|
[InlineData(2, "httpa, httpb, httpc", "httpa", "")]
|
||||||
|
public async Task ForwardersWithDirectOptionsRunsTwice(int limit, string header, string expectedScheme, string remainingHeader)
|
||||||
|
{
|
||||||
|
var builder = new WebHostBuilder()
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
var options = new ForwardedHeadersOptions
|
||||||
|
{
|
||||||
|
ForwardedHeaders = ForwardedHeaders.XForwardedProto,
|
||||||
|
ForwardLimit = limit,
|
||||||
|
};
|
||||||
|
options.KnownProxies.Clear();
|
||||||
|
options.KnownNetworks.Clear();
|
||||||
|
app.UseForwardedHeaders(options);
|
||||||
|
app.UseForwardedHeaders(options);
|
||||||
|
});
|
||||||
|
var server = new TestServer(builder);
|
||||||
|
|
||||||
|
var context = await server.SendAsync(c =>
|
||||||
|
{
|
||||||
|
c.Request.Headers["X-Forwarded-Proto"] = header;
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Equal(expectedScheme, context.Request.Scheme);
|
||||||
|
Assert.Equal(remainingHeader, context.Request.Headers["X-Forwarded-Proto"].ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue