using System;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Http
{
///
/// Extensions for the .
///
public static class HttpContextExtensions
{
// Search these additional headers for a remote client ip address.
private static readonly string[] _defaultIpHeaderNames = new[]
{
"Cf-Connecting-Ip", // set by Cloudflare
"X-Real-IP", // wide-spread alternative to X-Forwarded-For
"X-Forwarded-For", // commonly used on all known proxies
};
///
/// Retrieves the antiforgery token.
///
/// The current .
/// FormName, HeaderName and Value of the antiforgery token.
public static (string FormName, string HeaderName, string Value) GetAntiforgeryToken(this HttpContext httpContext)
{
var antiforgery = httpContext.RequestServices.GetService();
var tokenSet = antiforgery?.GetAndStoreTokens(httpContext);
return (tokenSet?.FormFieldName, tokenSet?.HeaderName, tokenSet?.RequestToken);
}
///
/// Returns the remote ip address.
///
///
/// Searches for additional headers in the following order:
///
/// - Cf-Connecting-Ip
/// - X-Real-IP
/// - X-Forwarded-For
///
///
/// The current .
/// The name of the header to resolve the when behind a proxy.
/// The ip address of the client.
public static IPAddress GetRemoteIpAddress(this HttpContext httpContext, string ipHeaderName = null)
{
string forwardedForAddress = null;
var headerNames = string.IsNullOrWhiteSpace(ipHeaderName)
? _defaultIpHeaderNames
: new[] { ipHeaderName }.Concat(_defaultIpHeaderNames);
foreach (string headerName in headerNames)
{
if (!httpContext.Request.Headers.ContainsKey(headerName))
continue;
// X-Forwarded-For can contain multiple comma-separated addresses.
forwardedForAddress = httpContext.Request.Headers[headerName].ToString()
.Split(',', StringSplitOptions.TrimEntries)
.First();
break;
}
if (!string.IsNullOrWhiteSpace(forwardedForAddress) && IPAddress.TryParse(forwardedForAddress, out var remoteAddress))
{
return remoteAddress.IsIPv4MappedToIPv6
? remoteAddress.MapToIPv4()
: remoteAddress;
}
return httpContext.Connection.RemoteIpAddress.IsIPv4MappedToIPv6
? httpContext.Connection.RemoteIpAddress.MapToIPv4()
: httpContext.Connection.RemoteIpAddress;
}
///
/// Returns whether the request was made locally.
///
///
/// Searches for additional headers in the following order:
///
/// - Cf-Connecting-Ip
/// - X-Real-IP
/// - X-Forwarded-For
///
///
/// The current .
/// The name of the header to resolve the when behind a proxy.
///
public static bool IsLocalRequest(this HttpContext httpContext, string ipHeaderName = null)
{
var remoteIpAddress = httpContext.GetRemoteIpAddress(ipHeaderName);
return httpContext.Connection.LocalIpAddress.Equals(remoteIpAddress);
}
///
/// Tries to retrieve the return url.
///
/// The current .
///
public static string GetReturnUrl(this HttpContext httpContext)
{
if (httpContext.Items.ContainsKey("OriginalRequest"))
return httpContext.Items["OriginalRequest"].ToString();
if (httpContext.Request.Query.ContainsKey("ReturnUrl"))
return httpContext.Request.Query["ReturnUrl"].ToString();
return null;
}
///
/// Clears a session when available.
///
/// The current .
public static void ClearSession(this HttpContext httpContext)
=> httpContext.Session?.Clear();
}
}