HttpProxyMiddleware.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using FastGithub.Configuration;
  2. using FastGithub.DomainResolve;
  3. using Microsoft.AspNetCore.Connections.Features;
  4. using Microsoft.AspNetCore.Http;
  5. using Microsoft.AspNetCore.Http.Features;
  6. using System.IO.Pipelines;
  7. using System.Net;
  8. using System.Net.Http;
  9. using System.Net.Sockets;
  10. using System.Threading.Tasks;
  11. using Yarp.ReverseProxy.Forwarder;
  12. namespace FastGithub.ReverseProxy
  13. {
  14. /// <summary>
  15. /// http代理中间件
  16. /// </summary>
  17. sealed class HttpProxyMiddleware
  18. {
  19. private readonly FastGithubConfig fastGithubConfig;
  20. private readonly IDomainResolver domainResolver;
  21. private readonly IHttpForwarder httpForwarder;
  22. private readonly SocketsHttpHandler socketsHttpHandler = new() { UseCookies = false, UseProxy = false, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None };
  23. /// <summary>
  24. /// http代理中间件
  25. /// </summary>
  26. /// <param name="fastGithubConfig"></param>
  27. /// <param name="domainResolver"></param>
  28. /// <param name="httpForwarder"></param>
  29. public HttpProxyMiddleware(
  30. FastGithubConfig fastGithubConfig,
  31. IDomainResolver domainResolver,
  32. IHttpForwarder httpForwarder)
  33. {
  34. this.fastGithubConfig = fastGithubConfig;
  35. this.domainResolver = domainResolver;
  36. this.httpForwarder = httpForwarder;
  37. }
  38. /// <summary>
  39. /// 处理请求
  40. /// </summary>
  41. /// <param name="context"></param>
  42. /// <returns></returns>
  43. public async Task InvokeAsync(HttpContext context)
  44. {
  45. if (context.Request.Method != HttpMethods.Connect)
  46. {
  47. var httpClient = new HttpMessageInvoker(this.socketsHttpHandler, false);
  48. var destinationPrefix = $"{context.Request.Scheme}://{context.Request.Host}";
  49. await this.httpForwarder.SendAsync(context, destinationPrefix, httpClient);
  50. }
  51. else
  52. {
  53. var endpoint = await this.GetTargetEndPointAsync(context.Request);
  54. using var targetSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
  55. await targetSocket.ConnectAsync(endpoint);
  56. context.Response.StatusCode = StatusCodes.Status200OK;
  57. context.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Connection Established";
  58. await context.Response.CompleteAsync();
  59. var transport = context.Features.Get<IConnectionTransportFeature>()?.Transport;
  60. if (transport != null)
  61. {
  62. var targetStream = new NetworkStream(targetSocket, ownsSocket: false);
  63. var task1 = targetStream.CopyToAsync(transport.Output);
  64. var task2 = transport.Input.CopyToAsync(targetStream);
  65. await Task.WhenAny(task1, task2);
  66. }
  67. }
  68. }
  69. /// <summary>
  70. /// 获取目标终节点
  71. /// </summary>
  72. /// <param name="request"></param>
  73. /// <returns></returns>
  74. private async Task<EndPoint> GetTargetEndPointAsync(HttpRequest request)
  75. {
  76. var targetHost = request.Host.Host;
  77. var targetPort = request.Host.Port ?? 443;
  78. if (IPAddress.TryParse(targetHost, out var address) == true)
  79. {
  80. return new IPEndPoint(address, targetPort);
  81. }
  82. if (this.fastGithubConfig.TryGetDomainConfig(targetHost, out _) == false)
  83. {
  84. return new DnsEndPoint(targetHost, targetPort);
  85. }
  86. // https,走反向代理中间人
  87. if (targetPort == 443)
  88. {
  89. return new IPEndPoint(IPAddress.Loopback, HttpsReverseProxyPort.Value);
  90. }
  91. // dns优选
  92. address = await this.domainResolver.ResolveAsync(new DnsEndPoint(targetHost, targetPort));
  93. return new IPEndPoint(address, targetPort);
  94. }
  95. }
  96. }