* Forward custom header names
This commit is contained in:
Morten Andersen 2016-10-03 19:16:03 +02:00 коммит произвёл Chris R
Родитель 9bc8a83a39
Коммит 76256446f5
3 изменённых файлов: 106 добавлений и 19 удалений

Просмотреть файл

@ -0,0 +1,42 @@
// 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.
namespace Microsoft.AspNetCore.HttpOverrides
{
/// <summary>
/// Default values related to <see cref="ForwardedHeadersMiddleware"/> middleware
/// </summary>
/// <seealso cref="Microsoft.AspNetCore.Builder.ForwardedHeadersOptions"/>
public static class ForwardedHeadersDefaults
{
/// <summary>
/// X-Forwarded-For
/// </summary>
public static string XForwardedForHeaderName { get; } = "X-Forwarded-For";
/// <summary>
/// X-Forwarded-Host
/// </summary>
public static string XForwardedHostHeaderName { get; } = "X-Forwarded-Host";
/// <summary>
/// X-Forwarded-Proto
/// </summary>
public static string XForwardedProtoHeaderName { get; } = "X-Forwarded-Proto";
/// <summary>
/// X-Original-For
/// </summary>
public static string XOriginalForHeaderName { get; } = "X-Original-For";
/// <summary>
/// X-Original-Host
/// </summary>
public static string XOriginalHostHeaderName { get; } = "X-Original-Host";
/// <summary>
/// X-Original-Proto
/// </summary>
public static string XOriginalProtoHeaderName { get; } = "X-Original-Proto";
}
}

Просмотреть файл

@ -17,13 +17,6 @@ namespace Microsoft.AspNetCore.HttpOverrides
{
public class ForwardedHeadersMiddleware
{
private const string XForwardedForHeaderName = "X-Forwarded-For";
private const string XForwardedHostHeaderName = "X-Forwarded-Host";
private const string XForwardedProtoHeaderName = "X-Forwarded-Proto";
private const string XOriginalForName = "X-Original-For";
private const string XOriginalHostName = "X-Original-Host";
private const string XOriginalProtoName = "X-Original-Proto";
private readonly ForwardedHeadersOptions _options;
private readonly RequestDelegate _next;
private readonly ILogger _logger;
@ -43,11 +36,27 @@ namespace Microsoft.AspNetCore.HttpOverrides
throw new ArgumentNullException(nameof(options));
}
// Make sure required options is not null or whitespace
EnsureOptionNotNullorWhitespace(options.Value.ForwardedForHeaderName, nameof(options.Value.ForwardedForHeaderName));
EnsureOptionNotNullorWhitespace(options.Value.ForwardedHostHeaderName, nameof(options.Value.ForwardedHostHeaderName));
EnsureOptionNotNullorWhitespace(options.Value.ForwardedProtoHeaderName, nameof(options.Value.ForwardedProtoHeaderName));
EnsureOptionNotNullorWhitespace(options.Value.OriginalForHeaderName, nameof(options.Value.OriginalForHeaderName));
EnsureOptionNotNullorWhitespace(options.Value.OriginalHostHeaderName, nameof(options.Value.OriginalHostHeaderName));
EnsureOptionNotNullorWhitespace(options.Value.OriginalProtoHeaderName, nameof(options.Value.OriginalProtoHeaderName));
_options = options.Value;
_logger = loggerFactory.CreateLogger<ForwardedHeadersMiddleware>();
_next = next;
}
private static void EnsureOptionNotNullorWhitespace(string value, string propertyName)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException($"options.{propertyName} is required", "options");
}
}
public Task Invoke(HttpContext context)
{
ApplyForwarders(context);
@ -64,14 +73,14 @@ namespace Microsoft.AspNetCore.HttpOverrides
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedFor) == ForwardedHeaders.XForwardedFor)
{
checkFor = true;
forwardedFor = context.Request.Headers.GetCommaSeparatedValues(XForwardedForHeaderName);
forwardedFor = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedForHeaderName);
entryCount = Math.Max(forwardedFor.Length, entryCount);
}
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedProto) == ForwardedHeaders.XForwardedProto)
{
checkProto = true;
forwardedProto = context.Request.Headers.GetCommaSeparatedValues(XForwardedProtoHeaderName);
forwardedProto = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedProtoHeaderName);
if (_options.RequireHeaderSymmetry && checkFor && forwardedFor.Length != forwardedProto.Length)
{
_logger.LogWarning(1, "Parameter count mismatch between X-Forwarded-For and X-Forwarded-Proto.");
@ -83,7 +92,7 @@ namespace Microsoft.AspNetCore.HttpOverrides
if ((_options.ForwardedHeaders & ForwardedHeaders.XForwardedHost) == ForwardedHeaders.XForwardedHost)
{
checkHost = true;
forwardedHost = context.Request.Headers.GetCommaSeparatedValues(XForwardedHostHeaderName);
forwardedHost = context.Request.Headers.GetCommaSeparatedValues(_options.ForwardedHostHeaderName);
if (_options.RequireHeaderSymmetry
&& ((checkFor && forwardedFor.Length != forwardedHost.Length)
|| (checkProto && forwardedProto.Length != forwardedHost.Length)))
@ -198,17 +207,17 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (connection.RemoteIpAddress != null)
{
// Save the original
request.Headers[XOriginalForName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString();
request.Headers[_options.OriginalForHeaderName] = new IPEndPoint(connection.RemoteIpAddress, connection.RemotePort).ToString();
}
if (forwardedFor.Length > entriesConsumed)
{
// Truncate the consumed header values
request.Headers[XForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray();
request.Headers[_options.ForwardedForHeaderName] = forwardedFor.Take(forwardedFor.Length - entriesConsumed).ToArray();
}
else
{
// All values were consumed
request.Headers.Remove(XForwardedForHeaderName);
request.Headers.Remove(_options.ForwardedForHeaderName);
}
connection.RemoteIpAddress = currentValues.RemoteIpAndPort.Address;
connection.RemotePort = currentValues.RemoteIpAndPort.Port;
@ -217,16 +226,16 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (checkProto && currentValues.Scheme != null)
{
// Save the original
request.Headers[XOriginalProtoName] = request.Scheme;
request.Headers[_options.OriginalProtoHeaderName] = request.Scheme;
if (forwardedProto.Length > entriesConsumed)
{
// Truncate the consumed header values
request.Headers[XForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray();
request.Headers[_options.ForwardedProtoHeaderName] = forwardedProto.Take(forwardedProto.Length - entriesConsumed).ToArray();
}
else
{
// All values were consumed
request.Headers.Remove(XForwardedProtoHeaderName);
request.Headers.Remove(_options.ForwardedProtoHeaderName);
}
request.Scheme = currentValues.Scheme;
}
@ -234,16 +243,16 @@ namespace Microsoft.AspNetCore.HttpOverrides
if (checkHost && currentValues.Host != null)
{
// Save the original
request.Headers[XOriginalHostName] = request.Host.ToString();
request.Headers[_options.OriginalHostHeaderName] = request.Host.ToString();
if (forwardedHost.Length > entriesConsumed)
{
// Truncate the consumed header values
request.Headers[XForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray();
request.Headers[_options.ForwardedHostHeaderName] = forwardedHost.Take(forwardedHost.Length - entriesConsumed).ToArray();
}
else
{
// All values were consumed
request.Headers.Remove(XForwardedHostHeaderName);
request.Headers.Remove(_options.ForwardedHostHeaderName);
}
request.Host = HostString.FromUriComponent(currentValues.Host);
}

Просмотреть файл

@ -9,6 +9,42 @@ namespace Microsoft.AspNetCore.Builder
{
public class ForwardedHeadersOptions
{
/// <summary>
/// Use this header instead of <see cref="ForwardedHeadersDefaults.XForwardedForHeaderName"/>
/// </summary>
/// <seealso cref="Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersDefaults"/>
public string ForwardedForHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedForHeaderName;
/// <summary>
/// Use this header instead of <see cref="ForwardedHeadersDefaults.XForwardedHostHeaderName"/>
/// </summary>
/// <seealso cref="ForwardedHeadersDefaults"/>
public string ForwardedHostHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedHostHeaderName;
/// <summary>
/// Use this header instead of <see cref="ForwardedHeadersDefaults.XForwardedProtoHeaderName"/>
/// </summary>
/// <seealso cref="ForwardedHeadersDefaults"/>
public string ForwardedProtoHeaderName { get; set; } = ForwardedHeadersDefaults.XForwardedProtoHeaderName;
/// <summary>
/// Use this header instead of <see cref="ForwardedHeadersDefaults.XOriginalForHeaderName"/>
/// </summary>
/// <seealso cref="ForwardedHeadersDefaults"/>
public string OriginalForHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalForHeaderName;
/// <summary>
/// Use this header instead of <see cref="ForwardedHeadersDefaults.XOriginalHostHeaderName"/>
/// </summary>
/// <seealso cref="ForwardedHeadersDefaults"/>
public string OriginalHostHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalHostHeaderName;
/// <summary>
/// Use this header instead of <see cref="ForwardedHeadersDefaults.XOriginalProtoHeaderName"/>
/// </summary>
/// <seealso cref="ForwardedHeadersDefaults"/>
public string OriginalProtoHeaderName { get; set; } = ForwardedHeadersDefaults.XOriginalProtoHeaderName;
/// <summary>
/// Identifies which forwarders should be processed.
/// </summary>