合并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
|
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);
|
||||||
}
|
}
|
||||||
@ -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 HttpClientHanlder httpClientHanlder;
|
||||||
private readonly NoSniHttpClientHanlder noSniHttpClientHanlder;
|
|
||||||
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,
|
HttpClientHanlder httpClientHanlder,
|
||||||
NoSniHttpClientHanlder noSniHttpClientHanlder,
|
|
||||||
FastGithubConfig fastGithubConfig,
|
FastGithubConfig fastGithubConfig,
|
||||||
ILogger<ReverseProxyMiddleware> logger)
|
ILogger<ReverseProxyMiddleware> logger)
|
||||||
{
|
{
|
||||||
this.httpForwarder = httpForwarder;
|
this.httpForwarder = httpForwarder;
|
||||||
this.sniHttpClientHanlder = sniHttpClientHanlder;
|
this.httpClientHanlder = httpClientHanlder;
|
||||||
this.noSniHttpClientHanlder = noSniHttpClientHanlder;
|
|
||||||
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 = new HttpClient(this.httpClientHanlder, false, domainConfig.TlsSni);
|
||||||
var httpClient = domainConfig.TlsSni
|
|
||||||
? new HttpMessageInvoker(this.sniHttpClientHanlder, disposeHandler: false)
|
|
||||||
: new HttpMessageInvoker(this.noSniHttpClientHanlder, disposeHandler: false);
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@ -19,8 +19,7 @@ namespace FastGithub
|
|||||||
.AddMemoryCache()
|
.AddMemoryCache()
|
||||||
.AddHttpForwarder()
|
.AddHttpForwarder()
|
||||||
.AddSingleton<DomainResolver>()
|
.AddSingleton<DomainResolver>()
|
||||||
.AddTransient<SniHttpClientHanlder>()
|
.AddTransient<HttpClientHanlder>()
|
||||||
.AddTransient<NoSniHttpClientHanlder>()
|
|
||||||
.AddSingleton<ReverseProxyMiddleware>();
|
.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