合并HttpClientHanlder
This commit is contained in:
parent
106b789c80
commit
d50c35466b
40
FastGithub.ReverseProxy/HttpClient.cs
Normal file
40
FastGithub.ReverseProxy/HttpClient.cs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,20 +9,20 @@ using System.Threading.Tasks;
|
||||
namespace FastGithub.ReverseProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// 不发送NoSni的HttpClientHandler
|
||||
/// YARP的HttpClientHandler
|
||||
/// </summary>
|
||||
class NoSniHttpClientHanlder : DelegatingHandler
|
||||
class HttpClientHanlder : DelegatingHandler
|
||||
{
|
||||
private readonly DomainResolver domainResolver;
|
||||
private readonly ILogger<NoSniHttpClientHanlder> logger;
|
||||
private readonly ILogger<HttpClientHanlder> logger;
|
||||
|
||||
/// <summary>
|
||||
/// 不发送NoSni的HttpClientHandler
|
||||
/// YARP的HttpClientHandler
|
||||
/// </summary>
|
||||
/// <param name="domainResolver"></param>
|
||||
public NoSniHttpClientHanlder(
|
||||
public HttpClientHanlder(
|
||||
DomainResolver domainResolver,
|
||||
ILogger<NoSniHttpClientHanlder> logger)
|
||||
ILogger<HttpClientHanlder> logger)
|
||||
{
|
||||
this.domainResolver = domainResolver;
|
||||
this.logger = logger;
|
||||
@ -45,7 +45,8 @@ namespace FastGithub.ReverseProxy
|
||||
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)
|
||||
var sniContext = ctx.InitialRequestMessage.GetSniContext();
|
||||
if (sniContext.IsHttps == false)
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
@ -53,7 +54,7 @@ namespace FastGithub.ReverseProxy
|
||||
var sslStream = new SslStream(stream, leaveInnerStreamOpen: false);
|
||||
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
|
||||
{
|
||||
TargetHost = string.Empty,
|
||||
TargetHost = sniContext.TlsSniValue,
|
||||
RemoteCertificateValidationCallback = delegate { return true; }
|
||||
}, ct);
|
||||
return sslStream;
|
||||
@ -74,16 +75,25 @@ namespace FastGithub.ReverseProxy
|
||||
if (uri != null && uri.HostNameType == UriHostNameType.Dns)
|
||||
{
|
||||
var address = await this.domainResolver.ResolveAsync(uri.Host, cancellationToken);
|
||||
this.logger.LogInformation($"[{address}--NoSni->{uri.Host}]");
|
||||
|
||||
var builder = new UriBuilder(uri)
|
||||
{
|
||||
Scheme = Uri.UriSchemeHttp,
|
||||
Host = address.ToString(),
|
||||
Port = 443
|
||||
};
|
||||
request.RequestUri = builder.Uri;
|
||||
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);
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
|
||||
@ -13,21 +12,18 @@ namespace FastGithub.ReverseProxy
|
||||
sealed class ReverseProxyMiddleware
|
||||
{
|
||||
private readonly IHttpForwarder httpForwarder;
|
||||
private readonly SniHttpClientHanlder sniHttpClientHanlder;
|
||||
private readonly NoSniHttpClientHanlder noSniHttpClientHanlder;
|
||||
private readonly HttpClientHanlder httpClientHanlder;
|
||||
private readonly FastGithubConfig fastGithubConfig;
|
||||
private readonly ILogger<ReverseProxyMiddleware> logger;
|
||||
|
||||
public ReverseProxyMiddleware(
|
||||
IHttpForwarder httpForwarder,
|
||||
SniHttpClientHanlder sniHttpClientHanlder,
|
||||
NoSniHttpClientHanlder noSniHttpClientHanlder,
|
||||
HttpClientHanlder httpClientHanlder,
|
||||
FastGithubConfig fastGithubConfig,
|
||||
ILogger<ReverseProxyMiddleware> logger)
|
||||
{
|
||||
this.httpForwarder = httpForwarder;
|
||||
this.sniHttpClientHanlder = sniHttpClientHanlder;
|
||||
this.noSniHttpClientHanlder = noSniHttpClientHanlder;
|
||||
this.httpClientHanlder = httpClientHanlder;
|
||||
this.fastGithubConfig = fastGithubConfig;
|
||||
this.logger = logger;
|
||||
}
|
||||
@ -59,10 +55,7 @@ namespace FastGithub.ReverseProxy
|
||||
{
|
||||
var destinationPrefix = GetDestinationPrefix(host, domainConfig.Destination);
|
||||
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);
|
||||
await ResponseErrorAsync(context, error);
|
||||
|
||||
@ -19,8 +19,7 @@ namespace FastGithub
|
||||
.AddMemoryCache()
|
||||
.AddHttpForwarder()
|
||||
.AddSingleton<DomainResolver>()
|
||||
.AddTransient<SniHttpClientHanlder>()
|
||||
.AddTransient<NoSniHttpClientHanlder>()
|
||||
.AddTransient<HttpClientHanlder>()
|
||||
.AddSingleton<ReverseProxyMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
34
FastGithub.ReverseProxy/SniContext.cs
Normal file
34
FastGithub.ReverseProxy/SniContext.cs
Normal file
@ -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
FastGithub.ReverseProxy/SniContextExtensions.cs
Normal file
37
FastGithub.ReverseProxy/SniContextExtensions.cs
Normal file
@ -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)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user