-
Notifications
You must be signed in to change notification settings - Fork 65
/
Copy pathProxyHeaderModule.Framework.cs
127 lines (102 loc) · 4.05 KB
/
ProxyHeaderModule.Framework.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Specialized;
using System.Globalization;
using System.Web;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.SystemWebAdapters;
/// <summary>
/// Updates server and request variables based on proxy headers. See https://docs.microsoft.com/en-us/iis/web-dev-reference/server-variables for reference on what server variables should be used.
/// </summary>
internal class ProxyHeaderModule : IHttpModule
{
private const string Host = "Host";
private const string ServerHttps = "HTTPS";
private const string ServerName = "SERVER_NAME";
private const string ServerPort = "SERVER_PORT";
private const string ForwardedProto = "x-forwarded-proto";
private const string ForwardedHost = "x-forwarded-host";
private const string On = "ON";
private const string Off = "OFF";
private readonly IOptions<ProxyOptions> _options;
public ProxyHeaderModule(IOptions<ProxyOptions> options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
public void Dispose()
{
}
public void Init(HttpApplication context)
{
var options = _options.Value;
if (options.UseForwardedHeaders)
{
context.BeginRequest += (s, e) =>
{
var request = ((HttpApplication)s).Context.Request;
UseHeaders(request.Headers, request.ServerVariables);
};
}
else
{
var values = new ServerValues(options);
context.BeginRequest += (s, e) =>
{
var request = ((HttpApplication)s).Context.Request;
UseOptions(values, request.Headers, request.ServerVariables);
};
}
}
public void UseHeaders(NameValueCollection requestHeaders, NameValueCollection serverVariables)
{
UseForwardedFor(requestHeaders, serverVariables);
var proto = requestHeaders[ForwardedProto];
if (requestHeaders[ForwardedHost] is { } host)
{
if (requestHeaders[Host] is { } originalHost)
{
requestHeaders[_options.Value.OriginalHostHeaderName] = originalHost;
}
var value = new ForwardedHost(host, proto);
serverVariables.Set(ServerName, value.ServerName);
serverVariables.Set(ServerPort, value.Port.ToString(CultureInfo.InvariantCulture));
serverVariables.Set(ServerHttps, value.IsSecure ? On : Off);
requestHeaders[Host] = host;
}
}
private static void UseOptions(ServerValues values, NameValueCollection requestHeaders, NameValueCollection serverVariables)
{
UseForwardedFor(requestHeaders, serverVariables);
serverVariables.Set(ServerName, values.Name);
serverVariables.Set(ServerPort, values.Port);
serverVariables.Set(ServerHttps, values.Https);
requestHeaders[Host] = values.Host;
}
private static void UseForwardedFor(NameValueCollection requestHeaders, NameValueCollection serverVariables)
{
if (requestHeaders["x-forwarded-for"] is { } remote)
{
serverVariables.Set("REMOTE_ADDR", remote);
serverVariables.Set("REMOTE_HOST", remote);
}
}
private class ServerValues
{
public ServerValues(ProxyOptions options)
{
if (options.ServerName is null)
{
throw new InvalidOperationException("Server name must be set for proxy options.");
}
Name = options.ServerName;
Port = options.ServerPort.ToString(CultureInfo.InvariantCulture);
Https = string.Equals("https", options.Scheme, StringComparison.OrdinalIgnoreCase) ? On : Off;
Host = $"{Name}:{Port}";
}
public string Name { get; }
public string Port { get; }
public string Https { get; }
public string Host { get; }
}
}