From c33d9040133b3e959094d46d984535283b5ecf2d Mon Sep 17 00:00:00 2001
From: xljiulang <366193849@qq.com>
Date: Thu, 15 Jul 2021 02:49:31 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=8D=E5=90=91=E4=BB=A3?=
=?UTF-8?q?=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../GithubDnsHttpHandler.cs | 61 -------
.../GithubHttpClientHanlder.cs | 114 +++++++++++++
.../GithubReverseProxyOptions.cs | 5 -
.../LifetimeHttpHandler.cs | 58 -------
.../LifetimeHttpHandlerCleaner.cs | 158 ------------------
.../NoneSniHttpClientFactory.cs | 111 ------------
...everseProxyApplicationBuilderExtensions.cs | 7 +-
...ReverseProxyServiceCollectionExtensions.cs | 1 +
.../GithubLookupFactoryOptions.cs | 2 +-
FastGithub/appsettings.json | 1 -
10 files changed, 119 insertions(+), 399 deletions(-)
delete mode 100644 FastGithub.ReverseProxy/GithubDnsHttpHandler.cs
create mode 100644 FastGithub.ReverseProxy/GithubHttpClientHanlder.cs
delete mode 100644 FastGithub.ReverseProxy/LifetimeHttpHandler.cs
delete mode 100644 FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs
delete mode 100644 FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs
diff --git a/FastGithub.ReverseProxy/GithubDnsHttpHandler.cs b/FastGithub.ReverseProxy/GithubDnsHttpHandler.cs
deleted file mode 100644
index 2eb04a0..0000000
--- a/FastGithub.ReverseProxy/GithubDnsHttpHandler.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using FastGithub.Scanner;
-using Microsoft.Extensions.Logging;
-using System;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace FastGithub.ReverseProxy
-{
- ///
- /// Github的dns解析的httpHandler
- /// 使扫描索结果作为github的https请求的域名解析
- ///
- sealed class GithubDnsHttpHandler : DelegatingHandler
- {
- private readonly IGithubScanResults scanResults;
- private readonly ILogger logger;
-
- ///
- /// Github的dns解析的httpHandler
- ///
- ///
- ///
- public GithubDnsHttpHandler(
- IGithubScanResults scanResults,
- HttpMessageHandler innerHandler,
- ILogger logger)
- : base(innerHandler)
- {
- this.scanResults = scanResults;
- this.logger = logger;
- }
-
- ///
- /// 发送消息
- ///
- ///
- ///
- ///
- protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- var uri = request.RequestUri;
- if (uri != null && uri.HostNameType == UriHostNameType.Dns)
- {
- var address = this.scanResults.FindBestAddress(uri.Host);
- if (address != null)
- {
- this.logger.LogInformation($"使用{address}请求{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);
- }
- }
-}
diff --git a/FastGithub.ReverseProxy/GithubHttpClientHanlder.cs b/FastGithub.ReverseProxy/GithubHttpClientHanlder.cs
new file mode 100644
index 0000000..b60f2f9
--- /dev/null
+++ b/FastGithub.ReverseProxy/GithubHttpClientHanlder.cs
@@ -0,0 +1,114 @@
+using FastGithub.Scanner;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FastGithub.ReverseProxy
+{
+ ///
+ /// 使用于请求github的HttpClientHandler
+ ///
+ [Service(ServiceLifetime.Transient)]
+ sealed class GithubHttpClientHanlder : DelegatingHandler
+ {
+ private readonly IGithubScanResults githubScanResults;
+ private readonly ILogger logger;
+ private readonly IMemoryCache memoryCache;
+
+ ///
+ /// 请求github的HttpClientHandler
+ ///
+ ///
+ ///
+ public GithubHttpClientHanlder(
+ IGithubScanResults githubScanResults,
+ ILogger logger,
+ IMemoryCache memoryCache)
+ {
+ this.githubScanResults = githubScanResults;
+ this.logger = logger;
+ this.memoryCache = memoryCache;
+ this.InnerHandler = CreateNoneSniHttpHandler();
+ }
+
+ ///
+ /// 创建无Sni发送的httpHandler
+ ///
+ ///
+ private static HttpMessageHandler CreateNoneSniHttpHandler()
+ {
+ return new SocketsHttpHandler
+ {
+ Proxy = null,
+ UseProxy = false,
+ AllowAutoRedirect = false,
+ ConnectCallback = async (ctx, ct) =>
+ {
+ var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
+ await socket.ConnectAsync(ctx.DnsEndPoint, ct);
+ var stream = new NetworkStream(socket, ownsSocket: true);
+ if (ctx.InitialRequestMessage.Headers.Host == null)
+ {
+ return stream;
+ }
+
+ var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
+ await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
+ {
+ TargetHost = string.Empty,
+ RemoteCertificateValidationCallback = delegate { return true; }
+ }, ct);
+ return sslStream;
+ }
+ };
+ }
+
+
+ ///
+ /// 查找最快的ip来发送消息
+ ///
+ ///
+ ///
+ ///
+ protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ var uri = request.RequestUri;
+ if (uri != null && uri.HostNameType == UriHostNameType.Dns)
+ {
+ var address = this.Resolve(uri.Host);
+ if (address != null)
+ {
+ this.logger.LogInformation($"使用{address}请求{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);
+ }
+
+ ///
+ /// 解析域名
+ ///
+ ///
+ ///
+ private IPAddress? Resolve(string domain)
+ {
+ return this.memoryCache.GetOrCreate(typeof(GithubHttpClientHanlder), e =>
+ {
+ e.SetAbsoluteExpiration(TimeSpan.FromSeconds(1d));
+ return this.githubScanResults.FindBestAddress(domain);
+ });
+ }
+ }
+}
diff --git a/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs b/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs
index 8608d2b..2c53567 100644
--- a/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs
+++ b/FastGithub.ReverseProxy/GithubReverseProxyOptions.cs
@@ -13,11 +13,6 @@ namespace FastGithub.ReverseProxy
///
public bool Enable { get; set; } = true;
- ///
- /// 每个服务的最大代理连接数
- ///
- public int MaxConnectionsPerServer { get; set; } = int.MaxValue;
-
///
/// 请求配置
///
diff --git a/FastGithub.ReverseProxy/LifetimeHttpHandler.cs b/FastGithub.ReverseProxy/LifetimeHttpHandler.cs
deleted file mode 100644
index 932309f..0000000
--- a/FastGithub.ReverseProxy/LifetimeHttpHandler.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Net.Http;
-using System.Threading;
-
-namespace FastGithub.ReverseProxy
-{
- ///
- /// 表示自主管理生命周期的的HttpMessageHandler
- ///
- [DebuggerDisplay("LifeTime = {lifeTime}")]
- sealed class LifetimeHttpHandler : DelegatingHandler
- {
- ///
- /// 生命周期
- ///
- private readonly TimeSpan lifeTime;
-
- ///
- /// Token取消源
- ///
- private readonly CancellationTokenSource tokenSource = new();
-
- ///
- /// 具有生命周期的HttpHandler
- ///
- /// HttpHandler
- /// 拦截器的生命周期
- /// 失效回调
- ///
- public LifetimeHttpHandler(HttpMessageHandler handler, TimeSpan lifeTime, Action deactivateAction)
- : base(handler)
- {
- if (deactivateAction == null)
- {
- throw new ArgumentNullException(nameof(deactivateAction));
- }
-
- this.lifeTime = lifeTime;
-
- this.tokenSource.Token.Register(() =>
- {
- this.tokenSource.Dispose();
- deactivateAction.Invoke(this);
- }, useSynchronizationContext: false);
-
- this.tokenSource.CancelAfter(lifeTime);
- }
-
- ///
- /// 这里不释放资源
- ///
- ///
- protected override void Dispose(bool disposing)
- {
- }
- }
-}
diff --git a/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs b/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs
deleted file mode 100644
index bd1ca86..0000000
--- a/FastGithub.ReverseProxy/LifetimeHttpHandlerCleaner.cs
+++ /dev/null
@@ -1,158 +0,0 @@
-using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace FastGithub.ReverseProxy
-{
- ///
- /// 表示LifetimeHttpHandler清理器
- ///
- sealed class LifetimeHttpHandlerCleaner
- {
- private readonly ILogger logger;
-
- ///
- /// 当前监视生命周期的记录的数量
- ///
- private int trackingEntryCount = 0;
-
- ///
- /// 监视生命周期的记录队列
- ///
- private readonly ConcurrentQueue trackingEntries = new();
-
- ///
- /// 获取或设置清理的时间间隔
- /// 默认10s
- ///
- public TimeSpan CleanupInterval { get; set; } = TimeSpan.FromSeconds(10d);
-
- ///
- /// LifetimeHttpHandler清理器
- ///
- ///
- public LifetimeHttpHandlerCleaner(ILogger logger)
- {
- this.logger = logger;
- }
-
- ///
- /// 添加要清除的httpHandler
- ///
- /// httpHandler
- public void Add(LifetimeHttpHandler handler)
- {
- var entry = new TrackingEntry(handler);
- this.trackingEntries.Enqueue(entry);
-
- // 从0变为1,要启动清理作业
- if (Interlocked.Increment(ref this.trackingEntryCount) == 1)
- {
- this.StartCleanup();
- }
- }
-
- ///
- /// 启动清理作业
- ///
- private async void StartCleanup()
- {
- try
- {
- while (true)
- {
- await Task.Delay(this.CleanupInterval);
- if (this.Cleanup() == true)
- {
- break;
- }
- }
- }
- catch (Exception ex)
- {
- this.logger.LogError(ex, "清理HttpMessageHandler出现不可预期的异常");
- // 这是应该不可能发生的
- }
- }
-
- ///
- /// 清理失效的拦截器
- /// 返回是否完全清理
- ///
- ///
- private bool Cleanup()
- {
- var cleanCount = this.trackingEntries.Count;
- this.logger.LogTrace($"尝试清理{cleanCount}条HttpMessageHandler");
-
- for (var i = 0; i < cleanCount; i++)
- {
- this.trackingEntries.TryDequeue(out var entry);
- Debug.Assert(entry != null);
-
- if (entry.CanDispose == false)
- {
- this.trackingEntries.Enqueue(entry);
- continue;
- }
-
- this.logger.LogTrace($"释放了{entry.GetHashCode()}@HttpMessageHandler");
- entry.Dispose();
- if (Interlocked.Decrement(ref this.trackingEntryCount) == 0)
- {
- return true;
- }
- }
-
- return false;
- }
-
-
- ///
- /// 表示监视生命周期的记录
- ///
- private class TrackingEntry : IDisposable
- {
- ///
- /// 用于释放资源的对象
- ///
- private readonly IDisposable disposable;
-
- ///
- /// 监视对象的弱引用
- ///
- private readonly WeakReference weakReference;
-
- ///
- /// 获取是否可以释放资源
- ///
- ///
- public bool CanDispose => this.weakReference.IsAlive == false;
-
- ///
- /// 监视生命周期的记录
- ///
- /// 激活状态的httpHandler
- public TrackingEntry(LifetimeHttpHandler handler)
- {
- this.disposable = handler.InnerHandler!;
- this.weakReference = new WeakReference(handler);
- }
-
- ///
- /// 释放资源
- ///
- public void Dispose()
- {
- try
- {
- this.disposable.Dispose();
- }
- catch (Exception) { }
- }
- }
- }
-}
diff --git a/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs b/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs
deleted file mode 100644
index 16ca0dd..0000000
--- a/FastGithub.ReverseProxy/NoneSniHttpClientFactory.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using FastGithub.Scanner;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using System;
-using System.Net.Http;
-using System.Net.Security;
-using System.Net.Sockets;
-
-namespace FastGithub.ReverseProxy
-{
- ///
- /// 禁用tls sni的HttpClient工厂
- ///
- [Service(ServiceLifetime.Singleton)]
- sealed class NoneSniHttpClientFactory
- {
- private readonly IGithubScanResults githubScanResults;
- private readonly IOptionsMonitor options;
- private readonly ILogger logger;
-
- ///
- /// 生命周期
- ///
- private readonly TimeSpan lifeTime = TimeSpan.FromMinutes(2d);
-
- ///
- /// 具有生命周期的httpHandler延时创建对象
- ///
- private volatile Lazy lifeTimeHttpHandlerLazy;
-
- ///
- /// HttpHandler清理器
- ///
- private readonly LifetimeHttpHandlerCleaner httpHandlerCleaner;
-
-
- ///
- /// 禁用tls sni的HttpClient工厂
- ///
- ///
- public NoneSniHttpClientFactory(
- IGithubScanResults githubScanResults,
- IOptionsMonitor options,
- ILogger logger)
- {
- this.githubScanResults = githubScanResults;
- this.options = options;
- this.logger = logger;
- this.lifeTimeHttpHandlerLazy = new Lazy(this.CreateHttpHandler, true);
- this.httpHandlerCleaner = new LifetimeHttpHandlerCleaner(logger);
- }
-
- ///
- /// 创建HttpClient
- ///
- ///
- public HttpMessageInvoker CreateHttpClient()
- {
- var handler = this.lifeTimeHttpHandlerLazy.Value;
- return new HttpMessageInvoker(handler);
- }
-
- ///
- /// 创建具有生命周期控制的httpHandler
- ///
- ///
- private LifetimeHttpHandler CreateHttpHandler()
- {
- var noneSniHandler = new SocketsHttpHandler
- {
- Proxy = null,
- UseProxy = false,
- AllowAutoRedirect = false,
- MaxConnectionsPerServer = this.options.CurrentValue.MaxConnectionsPerServer,
- ConnectCallback = async (ctx, ct) =>
- {
- var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
- await socket.ConnectAsync(ctx.DnsEndPoint, ct);
- var stream = new NetworkStream(socket, ownsSocket: true);
- if (ctx.InitialRequestMessage.Headers.Host == null)
- {
- return stream;
- }
-
- var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
- await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
- {
- TargetHost = string.Empty,
- RemoteCertificateValidationCallback = delegate { return true; }
- }, ct);
- return sslStream;
- }
- };
-
- var dnsHandler = new GithubDnsHttpHandler(this.githubScanResults, noneSniHandler, this.logger);
- return new LifetimeHttpHandler(dnsHandler, this.lifeTime, this.OnHttpHandlerDeactivate);
- }
-
- ///
- /// 当有httpHandler失效时
- ///
- /// httpHandler
- private void OnHttpHandlerDeactivate(LifetimeHttpHandler handler)
- {
- // 切换激活状态的记录的实例
- this.lifeTimeHttpHandlerLazy = new Lazy(this.CreateHttpHandler, true);
- this.httpHandlerCleaner.Add(handler);
- }
- }
-}
diff --git a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs
index 62dfff0..908b827 100644
--- a/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs
+++ b/FastGithub.ReverseProxy/ReverseProxyApplicationBuilderExtensions.cs
@@ -4,8 +4,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
-using System;
-using System.Linq;
+using System.Net.Http;
using Yarp.ReverseProxy.Forwarder;
namespace FastGithub
@@ -23,7 +22,7 @@ namespace FastGithub
public static IApplicationBuilder UseGithubReverseProxy(this IApplicationBuilder app)
{
var httpForwarder = app.ApplicationServices.GetRequiredService();
- var httpClientFactory = app.ApplicationServices.GetRequiredService();
+ var httpClientHanlder = app.ApplicationServices.GetRequiredService();
var lookupOptions = app.ApplicationServices.GetRequiredService>();
var options = app.ApplicationServices.GetRequiredService>();
@@ -38,7 +37,7 @@ namespace FastGithub
{
var port = context.Request.Host.Port ?? 443;
var destinationPrefix = $"http://{host}:{port}/";
- var httpClient = httpClientFactory.CreateHttpClient();
+ var httpClient = new HttpMessageInvoker(httpClientHanlder, disposeHandler: false);
var requestConfig = options.CurrentValue.ForwarderRequestConfig;
await httpForwarder.SendAsync(context, destinationPrefix, httpClient, requestConfig);
}
diff --git a/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs b/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs
index df95e9e..b7245f7 100644
--- a/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs
+++ b/FastGithub.ReverseProxy/ReverseProxyServiceCollectionExtensions.cs
@@ -19,6 +19,7 @@ namespace FastGithub
var assembly = typeof(ReverseProxyServiceCollectionExtensions).Assembly;
return services
.AddServiceAndOptions(assembly, configuration)
+ .AddMemoryCache()
.AddHttpForwarder();
}
}
diff --git a/FastGithub.Scanner/GithubLookupFactoryOptions.cs b/FastGithub.Scanner/GithubLookupFactoryOptions.cs
index 354e0f5..da8e753 100644
--- a/FastGithub.Scanner/GithubLookupFactoryOptions.cs
+++ b/FastGithub.Scanner/GithubLookupFactoryOptions.cs
@@ -11,6 +11,6 @@ namespace FastGithub.Scanner
///
/// 反查的域名
///
- public string [] Domains { get; set; } = new string[0];
+ public HashSet Domains { get; set; } = new();
}
}
diff --git a/FastGithub/appsettings.json b/FastGithub/appsettings.json
index f4581d5..9fb6915 100644
--- a/FastGithub/appsettings.json
+++ b/FastGithub/appsettings.json
@@ -6,7 +6,6 @@
},
"ReverseProxy": {
"Enable": true, // Ƿʹ÷github,
- "MaxConnectionsPerServer": 100, //
"ForwarderRequestConfig": {
"Timeout": "00:02:00" // ʱʱ
}