域名隔离

This commit is contained in:
老九 2021-10-03 15:57:40 +08:00
parent 3f01444f2d
commit 1163fa4678
6 changed files with 72 additions and 47 deletions

View File

@ -20,7 +20,7 @@ namespace FastGithub.Http
/// <summary>
/// 非首次生命周期
/// </summary>
private readonly TimeSpan nextLifeTime = TimeSpan.FromMinutes(1d);
private readonly TimeSpan nextLifeTime = TimeSpan.FromSeconds(100d);
/// <summary>
/// LifetimeHttpHandler清理器
@ -30,7 +30,7 @@ namespace FastGithub.Http
/// <summary>
/// LazyOf(LifetimeHttpHandler)缓存
/// </summary>
private readonly ConcurrentDictionary<DomainConfig, Lazy<LifetimeHttpHandler>> httpHandlerLazyCache = new();
private readonly ConcurrentDictionary<LifeTimeKey, Lazy<LifetimeHttpHandler>> httpHandlerLazyCache = new();
/// <summary>
@ -45,20 +45,31 @@ namespace FastGithub.Http
/// <summary>
/// 创建httpClient
/// </summary>
/// <param name="domain"></param>
/// <param name="domainConfig"></param>
/// <returns></returns>
public HttpClient CreateHttpClient(DomainConfig domainConfig)
public HttpClient CreateHttpClient(string domain, DomainConfig domainConfig)
{
var lifetimeHttpHandlerLazy = this.httpHandlerLazyCache.GetOrAdd(domainConfig, CreateLifetimeHttpHandlerLazy);
var lifetimeHttpHandler = lifetimeHttpHandlerLazy.Value;
var lifeTimeKey = new LifeTimeKey(domain, domainConfig);
var lifetimeHttpHandler = this.httpHandlerLazyCache.GetOrAdd(lifeTimeKey, CreateLifetimeHttpHandlerLazy).Value;
return new HttpClient(lifetimeHttpHandler, disposeHandler: false);
Lazy<LifetimeHttpHandler> CreateLifetimeHttpHandlerLazy(DomainConfig domainConfig)
Lazy<LifetimeHttpHandler> CreateLifetimeHttpHandlerLazy(LifeTimeKey lifeTimeKey)
{
return new Lazy<LifetimeHttpHandler>(() => this.CreateLifetimeHttpHandler(domainConfig, this.firstLiftTime), true);
return new Lazy<LifetimeHttpHandler>(() => this.CreateLifetimeHttpHandler(lifeTimeKey, this.firstLiftTime), true);
}
}
/// <summary>
/// 创建LifetimeHttpHandler
/// </summary>
/// <param name="lifeTimeKey"></param>
/// <param name="lifeTime"></param>
/// <returns></returns>
private LifetimeHttpHandler CreateLifetimeHttpHandler(LifeTimeKey lifeTimeKey, TimeSpan lifeTime)
{
return new LifetimeHttpHandler(this.domainResolver, lifeTimeKey, lifeTime, this.OnLifetimeHttpHandlerDeactivate);
}
/// <summary>
/// 当有httpHandler失效时
@ -66,26 +77,14 @@ namespace FastGithub.Http
/// <param name="lifetimeHttpHandler">httpHandler</param>
private void OnLifetimeHttpHandlerDeactivate(LifetimeHttpHandler lifetimeHttpHandler)
{
var domainConfig = lifetimeHttpHandler.DomainConfig;
this.httpHandlerLazyCache[domainConfig] = CreateLifetimeHttpHandlerLazy(domainConfig);
var lifeTimeKey = lifetimeHttpHandler.LifeTimeKey;
this.httpHandlerLazyCache[lifeTimeKey] = CreateLifetimeHttpHandlerLazy(lifeTimeKey);
this.httpHandlerCleaner.Add(lifetimeHttpHandler);
Lazy<LifetimeHttpHandler> CreateLifetimeHttpHandlerLazy(DomainConfig domainConfig)
Lazy<LifetimeHttpHandler> CreateLifetimeHttpHandlerLazy(LifeTimeKey lifeTimeKey)
{
return new Lazy<LifetimeHttpHandler>(() => this.CreateLifetimeHttpHandler(domainConfig, this.nextLifeTime), true);
}
}
/// <summary>
/// 创建LifetimeHttpHandler
/// </summary>
/// <param name="domainConfig"></param>
/// <param name="lifeTime"></param>
/// <returns></returns>
private LifetimeHttpHandler CreateLifetimeHttpHandler(DomainConfig domainConfig, TimeSpan lifeTime)
{
var httpClientHandler = new HttpClientHandler(domainConfig, this.domainResolver);
return new LifetimeHttpHandler(httpClientHandler, lifeTime, this.OnLifetimeHttpHandlerDeactivate);
return new Lazy<LifetimeHttpHandler>(() => this.CreateLifetimeHttpHandler(lifeTimeKey, this.nextLifeTime), true);
}
}
}
}

View File

@ -21,14 +21,10 @@ namespace FastGithub.Http
/// </summary>
class HttpClientHandler : DelegatingHandler
{
private readonly DomainConfig domainConfig;
private readonly IDomainResolver domainResolver;
private readonly TimeSpan connectTimeout = TimeSpan.FromSeconds(10d);
/// <summary>
/// 获取域名配置
/// </summary>
public DomainConfig DomainConfig { get; }
/// <summary>
/// HttpClientHandler
/// </summary>
@ -36,8 +32,8 @@ namespace FastGithub.Http
/// <param name="domainResolver"></param>
public HttpClientHandler(DomainConfig domainConfig, IDomainResolver domainResolver)
{
this.domainConfig = domainConfig;
this.domainResolver = domainResolver;
this.DomainConfig = domainConfig;
this.InnerHandler = this.CreateSocketsHttpHandler();
}
@ -57,16 +53,16 @@ namespace FastGithub.Http
// 请求上下文信息
var isHttps = uri.Scheme == Uri.UriSchemeHttps;
var tlsSniValue = this.DomainConfig.GetTlsSniPattern().WithDomain(uri.Host).WithRandom();
var tlsSniValue = this.domainConfig.GetTlsSniPattern().WithDomain(uri.Host).WithRandom();
request.SetRequestContext(new RequestContext(isHttps, tlsSniValue));
// 设置请求头host修改协议为http
request.Headers.Host = uri.Host;
request.RequestUri = new UriBuilder(uri) { Scheme = Uri.UriSchemeHttp }.Uri;
if (this.DomainConfig.Timeout != null)
if (this.domainConfig.Timeout != null)
{
using var timeoutTokenSource = new CancellationTokenSource(this.DomainConfig.Timeout.Value);
using var timeoutTokenSource = new CancellationTokenSource(this.domainConfig.Timeout.Value);
using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token);
return await base.SendAsync(request, linkedTokenSource.Token);
}
@ -157,7 +153,7 @@ namespace FastGithub.Http
{
if (errors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
{
if (this.DomainConfig.TlsIgnoreNameMismatch == true)
if (this.domainConfig.TlsIgnoreNameMismatch == true)
{
return true;
}
@ -179,7 +175,7 @@ namespace FastGithub.Http
/// <returns></returns>
private async IAsyncEnumerable<IPEndPoint> GetIPEndPointsAsync(DnsEndPoint dnsEndPoint, [EnumeratorCancellation] CancellationToken cancellationToken)
{
if (IPAddress.TryParse(this.DomainConfig.IPAddress, out var address) ||
if (IPAddress.TryParse(this.domainConfig.IPAddress, out var address) ||
IPAddress.TryParse(dnsEndPoint.Host, out address))
{
yield return new IPEndPoint(address, dnsEndPoint.Port);

View File

@ -10,8 +10,9 @@ namespace FastGithub.Http
/// <summary>
/// 创建httpClient
/// </summary>
/// <param name="domain"></param>
/// <param name="domainConfig"></param>
/// <returns></returns>
HttpClient CreateHttpClient(DomainConfig domainConfig);
HttpClient CreateHttpClient(string domain, DomainConfig domainConfig);
}
}

View File

@ -0,0 +1,31 @@
using FastGithub.Configuration;
namespace FastGithub.Http
{
/// <summary>
/// 生命周期的Key
/// </summary>
record LifeTimeKey
{
/// <summary>
/// 域名
/// </summary>
public string Domain { get; }
/// <summary>
/// 域名配置
/// </summary>
public DomainConfig DomainConfig { get; }
/// <summary>
/// 生命周期的Key
/// </summary>
/// <param name="domain"></param>
/// <param name="domainConfig"></param>
public LifeTimeKey(string domain, DomainConfig domainConfig)
{
this.Domain = domain;
this.DomainConfig = domainConfig;
}
}
}

View File

@ -1,4 +1,4 @@
using FastGithub.Configuration;
using FastGithub.DomainResolve;
using System;
using System.Net.Http;
using System.Threading;
@ -12,21 +12,19 @@ namespace FastGithub.Http
{
private readonly Timer timer;
/// <summary>
/// 获取域名配置
/// </summary>
public DomainConfig DomainConfig { get; }
public LifeTimeKey LifeTimeKey { get; }
/// <summary>
/// 具有生命周期的HttpHandler
/// </summary>
/// <param name="handler">HttpHandler</param>
/// <param name="lifeTime">拦截器的生命周期</param>
/// <param name="deactivateAction">失效回调</param>
public LifetimeHttpHandler(HttpClientHandler handler, TimeSpan lifeTime, Action<LifetimeHttpHandler> deactivateAction)
: base(handler)
/// <param name="domainResolver"></param>
/// <param name="lifeTimeKey"></param>
/// <param name="lifeTime"></param>
/// <param name="deactivateAction"></param>
public LifetimeHttpHandler(IDomainResolver domainResolver, LifeTimeKey lifeTimeKey, TimeSpan lifeTime, Action<LifetimeHttpHandler> deactivateAction)
{
this.DomainConfig = handler.DomainConfig;
this.LifeTimeKey = lifeTimeKey;
this.InnerHandler = new HttpClientHandler(lifeTimeKey.DomainConfig, domainResolver);
this.timer = new Timer(this.OnTimerCallback, deactivateAction, lifeTime, Timeout.InfiniteTimeSpan);
}

View File

@ -47,7 +47,7 @@ namespace FastGithub.HttpServer
{
var scheme = context.Request.Scheme;
var destinationPrefix = GetDestinationPrefix(scheme, host, domainConfig.Destination);
var httpClient = this.httpClientFactory.CreateHttpClient(domainConfig);
var httpClient = this.httpClientFactory.CreateHttpClient(host.Host, domainConfig);
var error = await httpForwarder.SendAsync(context, destinationPrefix, httpClient);
await HandleErrorAsync(context, error);
}