Quellcode durchsuchen

合并HttpClientHanlder

xljiulang vor 4 Jahren
Ursprung
Commit
d50c35466b

+ 40 - 0
FastGithub.ReverseProxy/HttpClient.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FastGithub.ReverseProxy
+{
+    /// <summary>
+    /// YARP的HttpClient
+    /// </summary>
+    class HttpClient : HttpMessageInvoker
+    {
+        private readonly bool tlsSni;
+
+        /// <summary>
+        /// YARP的HttpClient
+        /// </summary>
+        /// <param name="handler"></param>
+        /// <param name="disposeHandler"></param>
+        /// <param name="tlsSni"></param>
+        public HttpClient(HttpMessageHandler handler, bool disposeHandler, bool tlsSni) :
+            base(handler, disposeHandler)
+        {
+            this.tlsSni = tlsSni;
+        }
+
+        /// <summary>
+        /// 发送数据
+        /// </summary>
+        /// <param name="request"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+        {
+            var isHttps = request.RequestUri?.Scheme == Uri.UriSchemeHttps;
+            request.SetSniContext(new SniContext(isHttps, this.tlsSni));
+            return base.SendAsync(request, cancellationToken);
+        }
+    }
+}

+ 21 - 11
FastGithub.ReverseProxy/NoSniHttpClientHanlder.cs → FastGithub.ReverseProxy/HttpClientHanlder.cs

@@ -9,20 +9,20 @@ using System.Threading.Tasks;
 namespace FastGithub.ReverseProxy
 namespace FastGithub.ReverseProxy
 {
 {
     /// <summary>
     /// <summary>
-    /// 不发送NoSni的HttpClientHandler
+    /// YARP的HttpClientHandler
     /// </summary> 
     /// </summary> 
-    class NoSniHttpClientHanlder : DelegatingHandler
+    class HttpClientHanlder : DelegatingHandler
     {
     {
         private readonly DomainResolver domainResolver;
         private readonly DomainResolver domainResolver;
-        private readonly ILogger<NoSniHttpClientHanlder> logger;
+        private readonly ILogger<HttpClientHanlder> logger;
 
 
         /// <summary>
         /// <summary>
-        /// 不发送NoSni的HttpClientHandler
+        /// YARP的HttpClientHandler
         /// </summary>
         /// </summary>
         /// <param name="domainResolver"></param> 
         /// <param name="domainResolver"></param> 
-        public NoSniHttpClientHanlder(
+        public HttpClientHanlder(
             DomainResolver domainResolver,
             DomainResolver domainResolver,
-            ILogger<NoSniHttpClientHanlder> logger)
+            ILogger<HttpClientHanlder> logger)
         {
         {
             this.domainResolver = domainResolver;
             this.domainResolver = domainResolver;
             this.logger = logger;
             this.logger = logger;
@@ -45,7 +45,8 @@ namespace FastGithub.ReverseProxy
                     var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                     var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
                     await socket.ConnectAsync(ctx.DnsEndPoint, ct);
                     await socket.ConnectAsync(ctx.DnsEndPoint, ct);
                     var stream = new NetworkStream(socket, ownsSocket: true);
                     var stream = new NetworkStream(socket, ownsSocket: true);
-                    if (ctx.InitialRequestMessage.Headers.Host == null)
+                    var sniContext = ctx.InitialRequestMessage.GetSniContext();
+                    if (sniContext.IsHttps == false)
                     {
                     {
                         return stream;
                         return stream;
                     }
                     }
@@ -53,7 +54,7 @@ namespace FastGithub.ReverseProxy
                     var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
                     var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
                     await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
                     await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
                     {
                     {
-                        TargetHost = string.Empty,
+                        TargetHost = sniContext.TlsSniValue,
                         RemoteCertificateValidationCallback = delegate { return true; }
                         RemoteCertificateValidationCallback = delegate { return true; }
                     }, ct);
                     }, ct);
                     return sslStream;
                     return sslStream;
@@ -74,16 +75,25 @@ namespace FastGithub.ReverseProxy
             if (uri != null && uri.HostNameType == UriHostNameType.Dns)
             if (uri != null && uri.HostNameType == UriHostNameType.Dns)
             {
             {
                 var address = await this.domainResolver.ResolveAsync(uri.Host, cancellationToken);
                 var address = await this.domainResolver.ResolveAsync(uri.Host, cancellationToken);
-                this.logger.LogInformation($"[{address}--NoSni->{uri.Host}]");
-
                 var builder = new UriBuilder(uri)
                 var builder = new UriBuilder(uri)
                 {
                 {
                     Scheme = Uri.UriSchemeHttp,
                     Scheme = Uri.UriSchemeHttp,
                     Host = address.ToString(),
                     Host = address.ToString(),
-                    Port = 443
                 };
                 };
                 request.RequestUri = builder.Uri;
                 request.RequestUri = builder.Uri;
                 request.Headers.Host = uri.Host;
                 request.Headers.Host = uri.Host;
+
+                // 计算Sni
+                var context = request.GetSniContext();
+                if (context.IsHttps && context.TlsSni)
+                {
+                    context.TlsSniValue = uri.Host;
+                    this.logger.LogInformation($"[{address}--Sni->{uri.Host}]");
+                }
+                else
+                {
+                    this.logger.LogInformation($"[{address}--NoSni->{uri.Host}]");
+                }
             }
             }
             return await base.SendAsync(request, cancellationToken);
             return await base.SendAsync(request, cancellationToken);
         }
         }

+ 4 - 11
FastGithub.ReverseProxy/ReverseProxyMiddleware.cs

@@ -1,7 +1,6 @@
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 using System;
 using System;
-using System.Net.Http;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Yarp.ReverseProxy.Forwarder;
 using Yarp.ReverseProxy.Forwarder;
 
 
@@ -13,21 +12,18 @@ namespace FastGithub.ReverseProxy
     sealed class ReverseProxyMiddleware
     sealed class ReverseProxyMiddleware
     {
     {
         private readonly IHttpForwarder httpForwarder;
         private readonly IHttpForwarder httpForwarder;
-        private readonly SniHttpClientHanlder sniHttpClientHanlder;
-        private readonly NoSniHttpClientHanlder noSniHttpClientHanlder;
+        private readonly HttpClientHanlder httpClientHanlder;
         private readonly FastGithubConfig fastGithubConfig;
         private readonly FastGithubConfig fastGithubConfig;
         private readonly ILogger<ReverseProxyMiddleware> logger;
         private readonly ILogger<ReverseProxyMiddleware> logger;
 
 
         public ReverseProxyMiddleware(
         public ReverseProxyMiddleware(
             IHttpForwarder httpForwarder,
             IHttpForwarder httpForwarder,
-            SniHttpClientHanlder sniHttpClientHanlder,
-            NoSniHttpClientHanlder noSniHttpClientHanlder,
+            HttpClientHanlder httpClientHanlder,
             FastGithubConfig fastGithubConfig,
             FastGithubConfig fastGithubConfig,
             ILogger<ReverseProxyMiddleware> logger)
             ILogger<ReverseProxyMiddleware> logger)
         {
         {
             this.httpForwarder = httpForwarder;
             this.httpForwarder = httpForwarder;
-            this.sniHttpClientHanlder = sniHttpClientHanlder;
-            this.noSniHttpClientHanlder = noSniHttpClientHanlder;
+            this.httpClientHanlder = httpClientHanlder;
             this.fastGithubConfig = fastGithubConfig;
             this.fastGithubConfig = fastGithubConfig;
             this.logger = logger;
             this.logger = logger;
         }
         }
@@ -59,10 +55,7 @@ namespace FastGithub.ReverseProxy
             {
             {
                 var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
                 var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
                 var requestConfig = new ForwarderRequestConfig { Timeout = domainConfig.Timeout };
                 var requestConfig = new ForwarderRequestConfig { Timeout = domainConfig.Timeout };
-
-                var httpClient = domainConfig.TlsSni
-                   ? new HttpMessageInvoker(this.sniHttpClientHanlder, disposeHandler: false)
-                   : new HttpMessageInvoker(this.noSniHttpClientHanlder, disposeHandler: false);
+                var httpClient = new HttpClient(this.httpClientHanlder, false, domainConfig.TlsSni);
 
 
                 var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, requestConfig);
                 var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient, requestConfig);
                 await ResponseErrorAsync(context, error);
                 await ResponseErrorAsync(context, error);

+ 1 - 2
FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs

@@ -19,8 +19,7 @@ namespace FastGithub
                 .AddMemoryCache()
                 .AddMemoryCache()
                 .AddHttpForwarder()
                 .AddHttpForwarder()
                 .AddSingleton<DomainResolver>()
                 .AddSingleton<DomainResolver>()
-                .AddTransient<SniHttpClientHanlder>()
-                .AddTransient<NoSniHttpClientHanlder>()
+                .AddTransient<HttpClientHanlder>()
                 .AddSingleton<ReverseProxyMiddleware>();
                 .AddSingleton<ReverseProxyMiddleware>();
         }
         }
     }
     }

+ 34 - 0
FastGithub.ReverseProxy/SniContext.cs

@@ -0,0 +1,34 @@
+namespace FastGithub.ReverseProxy
+{
+    /// <summary>
+    /// Sni上下文
+    /// </summary>
+    sealed class SniContext
+    {
+        /// <summary>
+        /// 获取请求是否为https
+        /// </summary>
+        public bool IsHttps { get; }
+
+        /// <summary>
+        /// 获取是否发送Sni
+        /// </summary>
+        public bool TlsSni { get; }
+
+        /// <summary>
+        /// Sni值
+        /// </summary>
+        public string TlsSniValue { get; set; } = string.Empty;
+
+        /// <summary>
+        /// Sni上下文
+        /// </summary>
+        /// <param name="isHttps"></param>
+        /// <param name="tlsSni"></param>
+        public SniContext(bool isHttps, bool tlsSni)
+        {
+            this.IsHttps = isHttps;
+            this.TlsSni = tlsSni;
+        }
+    }
+}

+ 37 - 0
FastGithub.ReverseProxy/SniContextExtensions.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Net.Http;
+
+namespace FastGithub.ReverseProxy
+{
+    /// <summary>
+    /// SniContext扩展
+    /// </summary>
+    static class SniContextExtensions
+    {
+        private static readonly HttpRequestOptionsKey<SniContext> key = new(nameof(SniContext));
+
+        /// <summary>
+        /// 设置SniContext
+        /// </summary>
+        /// <param name="httpRequestMessage"></param>
+        /// <param name="context"></param>
+        public static void SetSniContext(this HttpRequestMessage httpRequestMessage, SniContext context)
+        {
+            httpRequestMessage.Options.Set(key, context);
+        }
+
+        /// <summary>
+        /// 获取SniContext
+        /// </summary>
+        /// <param name="httpRequestMessage"></param>
+        /// <returns></returns>
+        public static SniContext GetSniContext(this HttpRequestMessage httpRequestMessage)
+        {
+            if (httpRequestMessage.Options.TryGetValue(key, out var value))
+            {
+                return value;
+            }
+            throw new InvalidOperationException($"请先调用{nameof(SetSniContext)}");
+        }
+    }
+}

+ 0 - 60
FastGithub.ReverseProxy/SniHttpClientHanlder.cs

@@ -1,60 +0,0 @@
-using Microsoft.Extensions.Logging;
-using System;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace FastGithub.ReverseProxy
-{
-    /// <summary>
-    /// 携带Sni的的HttpClientHandler
-    /// </summary> 
-    class SniHttpClientHanlder : DelegatingHandler
-    {
-        private readonly DomainResolver domainResolver;
-        private readonly ILogger<SniHttpClientHanlder> logger;
-
-        /// <summary>
-        /// 携带Sni的HttpClientHandler
-        /// </summary>
-        /// <param name="domainResolver"></param> 
-        public SniHttpClientHanlder(
-            DomainResolver domainResolver,
-            ILogger<SniHttpClientHanlder> logger)
-        {
-            this.domainResolver = domainResolver;
-            this.logger = logger;
-
-            this.InnerHandler = new SocketsHttpHandler
-            {
-                Proxy = null,
-                UseProxy = false,
-                AllowAutoRedirect = false,
-            };
-        }
-
-        /// <summary>
-        /// 替换域名为ip
-        /// </summary>
-        /// <param name="request"></param>
-        /// <param name="cancellationToken"></param>
-        /// <returns></returns>
-        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
-        {
-            var uri = request.RequestUri;
-            if (uri != null && uri.HostNameType == UriHostNameType.Dns)
-            {
-                var address = await this.domainResolver.ResolveAsync(uri.Host, cancellationToken);
-                this.logger.LogInformation($"[{address}--Sni->{uri.Host}]");
-
-                var builder = new UriBuilder(uri)
-                {
-                    Host = address.ToString()
-                };
-                request.RequestUri = builder.Uri;
-                request.Headers.Host = uri.Host;
-            }
-            return await base.SendAsync(request, cancellationToken);
-        }
-    }
-}