1- using Microsoft . AspNetCore . Http ;
2- using Microsoft . Extensions . DependencyInjection ;
3- using Microsoft . Extensions . DependencyModel ;
41using System ;
52using System . Collections . Generic ;
6- using System . Linq ;
7- using System . Net . Http ;
8- using System . Net . Sockets ;
93using System . Reflection ;
10- using System . Text ;
11- using System . Threading . Tasks ;
4+ using Microsoft . Extensions . DependencyModel ;
125
136namespace AspNetCore . Proxy
147{
158 internal static class Helpers
169 {
17- internal static readonly string ProxyClientName = "AspNetCore.Proxy.ProxyClient" ;
10+ internal static readonly string HttpProxyClientName = "AspNetCore.Proxy.HttpProxyClient" ;
11+ internal static readonly string [ ] WebSocketNotForwardedHeaders = new [ ] { "Connection" , "Host" , "Upgrade" , "Sec-WebSocket-Accept" , "Sec-WebSocket-Protocol" , "Sec-WebSocket-Key" , "Sec-WebSocket-Version" , "Sec-WebSocket-Extensions" } ;
1812
1913 internal static IEnumerable < Assembly > GetReferencingAssemblies ( )
2014 {
@@ -31,142 +25,5 @@ internal static IEnumerable<Assembly> GetReferencingAssemblies()
3125 }
3226 return assemblies ;
3327 }
34-
35- internal static async Task ExecuteProxyOperation ( HttpContext context , string uri , ProxyOptions options = null )
36- {
37- try
38- {
39- var proxiedRequest = context . CreateProxiedHttpRequest ( uri , options ? . ShouldAddForwardedHeaders ?? true ) ;
40-
41- if ( options ? . BeforeSend != null )
42- await options . BeforeSend ( context , proxiedRequest ) . ConfigureAwait ( false ) ;
43- var proxiedResponse = await context
44- . SendProxiedHttpRequest ( proxiedRequest , options ? . HttpClientName ?? Helpers . ProxyClientName )
45- . ConfigureAwait ( false ) ;
46-
47- if ( options ? . AfterReceive != null )
48- await options . AfterReceive ( context , proxiedResponse ) . ConfigureAwait ( false ) ;
49- await context . WriteProxiedHttpResponse ( proxiedResponse ) . ConfigureAwait ( false ) ;
50- }
51- catch ( Exception e )
52- {
53- if ( options ? . HandleFailure == null )
54- {
55- // If the failures are not caught, then write a generic response.
56- context . Response . StatusCode = 502 ;
57- await context . Response . WriteAsync ( $ "Request could not be proxied.\n \n { e . Message } \n \n { e . StackTrace } .") . ConfigureAwait ( false ) ;
58- return ;
59- }
60-
61- await options . HandleFailure ( context , e ) . ConfigureAwait ( false ) ;
62- }
63- }
64- }
65-
66- internal static class Extensions
67- {
68- internal static HttpRequestMessage CreateProxiedHttpRequest ( this HttpContext context , string uriString , bool shouldAddForwardedHeaders )
69- {
70- var uri = new Uri ( uriString ) ;
71- var request = context . Request ;
72-
73- var requestMessage = new HttpRequestMessage ( ) ;
74- var requestMethod = request . Method ;
75-
76- // Write to request content, when necessary.
77- if ( ! HttpMethods . IsGet ( requestMethod ) &&
78- ! HttpMethods . IsHead ( requestMethod ) &&
79- ! HttpMethods . IsDelete ( requestMethod ) &&
80- ! HttpMethods . IsTrace ( requestMethod ) )
81- {
82- var streamContent = new StreamContent ( request . Body ) ;
83- requestMessage . Content = streamContent ;
84- }
85-
86- // Copy the request headers.
87- foreach ( var header in context . Request . Headers )
88- if ( ! requestMessage . Headers . TryAddWithoutValidation ( header . Key , header . Value . ToArray ( ) ) )
89- requestMessage . Content ? . Headers . TryAddWithoutValidation ( header . Key , header . Value . ToArray ( ) ) ;
90-
91- // Add forwarded headers.
92- if ( shouldAddForwardedHeaders )
93- AddForwardedHeadersToRequest ( context , requestMessage ) ;
94-
95- // Set destination and method.
96- requestMessage . Headers . Host = uri . Authority ;
97- requestMessage . RequestUri = uri ;
98- requestMessage . Method = new HttpMethod ( request . Method ) ;
99-
100- return requestMessage ;
101- }
102-
103- internal static Task < HttpResponseMessage > SendProxiedHttpRequest ( this HttpContext context , HttpRequestMessage message , string httpClientName )
104- {
105- return context . RequestServices
106- . GetService < IHttpClientFactory > ( )
107- . CreateClient ( httpClientName )
108- . SendAsync ( message , HttpCompletionOption . ResponseHeadersRead , context . RequestAborted ) ;
109- }
110-
111- internal static Task WriteProxiedHttpResponse ( this HttpContext context , HttpResponseMessage responseMessage )
112- {
113- var response = context . Response ;
114-
115- response . StatusCode = ( int ) responseMessage . StatusCode ;
116- foreach ( var header in responseMessage . Headers )
117- {
118- response . Headers [ header . Key ] = header . Value . ToArray ( ) ;
119- }
120-
121- foreach ( var header in responseMessage . Content . Headers )
122- {
123- response . Headers [ header . Key ] = header . Value . ToArray ( ) ;
124- }
125-
126- response . Headers . Remove ( "transfer-encoding" ) ;
127-
128- return responseMessage . Content . CopyToAsync ( response . Body ) ;
129- }
130-
131- private static void AddForwardedHeadersToRequest ( HttpContext context , HttpRequestMessage requestMessage )
132- {
133- var request = context . Request ;
134- var connection = context . Connection ;
135-
136- var host = request . Host . ToString ( ) ;
137- var protocol = request . Scheme ;
138-
139- var localIp = connection . LocalIpAddress ? . ToString ( ) ;
140- var isLocalIpV6 = connection . LocalIpAddress ? . AddressFamily == AddressFamily . InterNetworkV6 ;
141-
142- var remoteIp = context . Connection . RemoteIpAddress ? . ToString ( ) ;
143- var isRemoteIpV6 = connection . RemoteIpAddress ? . AddressFamily == AddressFamily . InterNetworkV6 ;
144-
145- if ( remoteIp != null )
146- requestMessage . Headers . TryAddWithoutValidation ( "X-Forwarded-For" , remoteIp ) ;
147- requestMessage . Headers . TryAddWithoutValidation ( "X-Forwarded-Proto" , protocol ) ;
148- requestMessage . Headers . TryAddWithoutValidation ( "X-Forwarded-Host" , host ) ;
149-
150- // Fix IPv6 IPs for the `Forwarded` header.
151- var forwardedHeader = new StringBuilder ( $ "proto={ protocol } ;host={ host } ;") ;
152-
153- if ( localIp != null )
154- {
155- if ( isLocalIpV6 )
156- localIp = $ "\" [{ localIp } ]\" ";
157-
158- forwardedHeader . Append ( $ "by={ localIp } ;") ;
159- }
160-
161- if ( remoteIp != null )
162- {
163- if ( isRemoteIpV6 )
164- remoteIp = $ "\" [{ remoteIp } ]\" ";
165-
166- forwardedHeader . Append ( $ "for={ remoteIp } ;") ;
167- }
168-
169- requestMessage . Headers . TryAddWithoutValidation ( "Forwarded" , forwardedHeader . ToString ( ) ) ;
170- }
17128 }
172- }
29+ }
0 commit comments