Explorar o código

实现proxy.pac

老九 %!s(int64=3) %!d(string=hai) anos
pai
achega
91a5ebbcee

+ 9 - 0
FastGithub.Configuration/FastGithubConfig.cs

@@ -102,5 +102,14 @@ namespace FastGithub.Configuration
                 return key == null ? null : this.domainConfigs[key];
             }
         }
+
+        /// <summary>
+        /// 获取所有域名表达式
+        /// </summary>
+        /// <returns></returns>
+        public string[] GetDomainPatterns()
+        {
+            return this.domainConfigs.Keys.Select(item => item.ToString()).ToArray();
+        }
     }
 }

+ 5 - 1
FastGithub.Dns/ProxyConflictValidtor.cs

@@ -50,11 +50,15 @@ namespace FastGithub.Dns
                 return;
             }
 
+            var httpProxyPort = this.options.Value.HttpProxyPort;
+            var loopbackProxyUri = new Uri($"http://127.0.0.1:{httpProxyPort}");
+            var localhostProxyUri = new Uri($"http://localhost:{httpProxyPort}");
+
             foreach (var domain in this.options.Value.DomainConfigs.Keys)
             {
                 var destination = new Uri($"https://{domain.Replace('*', 'a')}");
                 var proxyServer = systemProxy.GetProxy(destination);
-                if (proxyServer != null)
+                if (proxyServer != null && proxyServer != loopbackProxyUri && proxyServer != localhostProxyUri)
                 {
                     this.logger.LogError($"由于系统配置了{proxyServer}代理{domain},{nameof(FastGithub)}无法加速相关域名");
                 }

+ 37 - 4
FastGithub.ReverseProxy/HttpProxyMiddleware.cs

@@ -7,6 +7,7 @@ using System.IO.Pipelines;
 using System.Net;
 using System.Net.Http;
 using System.Net.Sockets;
+using System.Text;
 using System.Threading.Tasks;
 using Yarp.ReverseProxy.Forwarder;
 
@@ -20,7 +21,7 @@ namespace FastGithub.ReverseProxy
         private readonly FastGithubConfig fastGithubConfig;
         private readonly IDomainResolver domainResolver;
         private readonly IHttpForwarder httpForwarder;
-        private readonly SocketsHttpHandler socketsHttpHandler = new() { UseCookies = false, UseProxy = false, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None };
+        private readonly HttpMessageInvoker httpClient;
 
         /// <summary>
         /// http代理中间件
@@ -36,6 +37,7 @@ namespace FastGithub.ReverseProxy
             this.fastGithubConfig = fastGithubConfig;
             this.domainResolver = domainResolver;
             this.httpForwarder = httpForwarder;
+            this.httpClient = new HttpMessageInvoker(CreateHttpHandler(), disposeHandler: false);
         }
 
         /// <summary>
@@ -45,11 +47,26 @@ namespace FastGithub.ReverseProxy
         /// <returns></returns>
         public async Task InvokeAsync(HttpContext context)
         {
-            if (context.Request.Method != HttpMethods.Connect)
+            if (context.Request.Method == HttpMethods.Get && context.Request.Path == "/proxy.pac")
+            {
+                var buidler = new StringBuilder();
+                buidler.AppendLine("function FindProxyForURL(url, host){");
+                buidler.AppendLine($"    var proxy = 'PROXY {context.Request.Host}';");
+                foreach (var domain in this.fastGithubConfig.GetDomainPatterns())
+                {
+                    buidler.AppendLine($"    if (shExpMatch(host, '{domain}')) return proxy;");
+                }
+                buidler.AppendLine("    return 'DIRECT';");
+                buidler.AppendLine("}");
+                var pacString = buidler.ToString();
+
+                context.Response.ContentType = "application/x-ns-proxy-autoconfig";
+                await context.Response.WriteAsync(pacString);
+            }
+            else if (context.Request.Method != HttpMethods.Connect)
             {
-                var httpClient = new HttpMessageInvoker(this.socketsHttpHandler, false);
                 var destinationPrefix = $"{context.Request.Scheme}://{context.Request.Host}";
-                await this.httpForwarder.SendAsync(context, destinationPrefix, httpClient);
+                await this.httpForwarder.SendAsync(context, destinationPrefix, this.httpClient);
             }
             else
             {
@@ -102,5 +119,21 @@ namespace FastGithub.ReverseProxy
             address = await this.domainResolver.ResolveAsync(new DnsEndPoint(targetHost, targetPort));
             return new IPEndPoint(address, targetPort);
         }
+
+        /// <summary>
+        /// 创建httpHandler
+        /// </summary>
+        /// <returns></returns>
+        private static SocketsHttpHandler CreateHttpHandler()
+        {
+            return new()
+            {
+                Proxy = null,
+                UseProxy = false,
+                UseCookies = false,
+                AllowAutoRedirect = false,
+                AutomaticDecompression = DecompressionMethods.None
+            };
+        }
     }
 }

+ 1 - 0
FastGithub.ReverseProxy/KestrelServerOptionsExtensions.cs

@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Options;
 using System;
 using System.Net;
+using System.Runtime.CompilerServices;
 
 namespace FastGithub
 {

+ 9 - 17
FastGithub/Startup.cs

@@ -49,25 +49,17 @@ namespace FastGithub
         /// <param name="app"></param>
         public void Configure(IApplicationBuilder app)
         {
-            if (OperatingSystem.IsWindows())
-            {
-                app.UseRequestLogging();
-                app.UseHttpReverseProxy();
-            }
-            else
+            var httpProxyPort = app.ApplicationServices.GetRequiredService<IOptions<FastGithubOptions>>().Value.HttpProxyPort;
+            app.MapWhen(context => context.Connection.LocalPort == httpProxyPort, appBuilder =>
             {
-                var httpProxyPort = app.ApplicationServices.GetRequiredService<IOptions<FastGithubOptions>>().Value.HttpProxyPort;
-                app.MapWhen(context => context.Connection.LocalPort == httpProxyPort, appBuilder =>
-                {
-                    appBuilder.UseHttpProxy();
-                });
+                appBuilder.UseHttpProxy();
+            });
 
-                app.MapWhen(context => context.Connection.LocalPort != httpProxyPort, appBuilder =>
-                {
-                    appBuilder.UseRequestLogging();
-                    appBuilder.UseHttpReverseProxy();
-                });
-            }
+            app.MapWhen(context => context.Connection.LocalPort != httpProxyPort, appBuilder =>
+            {
+                appBuilder.UseRequestLogging();
+                appBuilder.UseHttpReverseProxy();
+            });
         }
     }
 }