2
0

HttpProxyMiddleware.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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 PortService portService;
  23. private readonly SocketsHttpHandler socketsHttpHandler = new() { UseCookies = false, UseProxy = false, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None };
  24. /// <summary>
  25. /// http代理中间件
  26. /// </summary>
  27. /// <param name="fastGithubConfig"></param>
  28. /// <param name="domainResolver"></param>
  29. /// <param name="httpForwarder"></param>
  30. /// <param name="portService"></param>
  31. public HttpProxyMiddleware(
  32. FastGithubConfig fastGithubConfig,
  33. IDomainResolver domainResolver,
  34. IHttpForwarder httpForwarder,
  35. PortService portService)
  36. {
  37. this.fastGithubConfig = fastGithubConfig;
  38. this.domainResolver = domainResolver;
  39. this.httpForwarder = httpForwarder;
  40. this.portService = portService;
  41. }
  42. /// <summary>
  43. /// 处理请求
  44. /// </summary>
  45. /// <param name="context"></param>
  46. /// <param name="next"></param>
  47. /// <returns></returns>
  48. public async Task InvokeAsync(HttpContext context, RequestDelegate next)
  49. {
  50. if (context.Request.Method != HttpMethods.Connect)
  51. {
  52. var httpClient = new HttpMessageInvoker(this.socketsHttpHandler, false);
  53. var destinationPrefix = $"{context.Request.Scheme}://{context.Request.Host}";
  54. await this.httpForwarder.SendAsync(context, destinationPrefix, httpClient);
  55. }
  56. else
  57. {
  58. var endpoint = await this.GetTargetEndPointAsync(context.Request);
  59. using var targetSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
  60. await targetSocket.ConnectAsync(endpoint);
  61. context.Response.StatusCode = StatusCodes.Status200OK;
  62. context.Features.Get<IHttpResponseFeature>().ReasonPhrase = "Connection Established";
  63. await context.Response.CompleteAsync();
  64. var transport = context.Features.Get<IConnectionTransportFeature>()?.Transport;
  65. if (transport != null)
  66. {
  67. var targetStream = new NetworkStream(targetSocket, ownsSocket: false);
  68. var task1 = targetStream.CopyToAsync(transport.Output);
  69. var task2 = transport.Input.CopyToAsync(targetStream);
  70. await Task.WhenAny(task1, task2);
  71. }
  72. }
  73. }
  74. /// <summary>
  75. /// 获取目标终节点
  76. /// </summary>
  77. /// <param name="request"></param>
  78. /// <returns></returns>
  79. private async Task<EndPoint> GetTargetEndPointAsync(HttpRequest request)
  80. {
  81. var domain = request.Host.Host;
  82. var port = request.Host.Port ?? 443;
  83. if (IPAddress.TryParse(domain, out var address) == true)
  84. {
  85. return new IPEndPoint(address, port);
  86. }
  87. if (this.fastGithubConfig.TryGetDomainConfig(domain, out _) == false)
  88. {
  89. return new DnsEndPoint(domain, port);
  90. }
  91. // https,走反向代理中间人
  92. if (port == 443)
  93. {
  94. return new IPEndPoint(IPAddress.Loopback, this.portService.HttpsReverseProxyPort);
  95. }
  96. // dns优选
  97. address = await this.domainResolver.ResolveAsync(new DnsEndPoint(domain, port));
  98. return new IPEndPoint(address, port);
  99. }
  100. }
  101. }