diff --git a/Netch/Controllers/HTTPController.cs b/Netch/Controllers/HTTPController.cs index e880bac0..0963ff29 100644 --- a/Netch/Controllers/HTTPController.cs +++ b/Netch/Controllers/HTTPController.cs @@ -3,6 +3,7 @@ using WindowsProxy; using Netch.Models; using Netch.Servers.Socks5; using Netch.Servers.Trojan; +using Netch.Utils; using Netch.Utils.HttpProxyHandler; namespace Netch.Controllers @@ -24,16 +25,30 @@ namespace Netch.Controllers { PrivoxyController.Start(MainController.Server!); Global.Job.AddProcess(PrivoxyController.Instance!); + string? pacUrl = null; + + if (MainController.Server is Socks5 or Trojan && mode.BypassChina || (Global.Settings.AlwaysStartPACServer ?? false)) + { + try + { + PortHelper.CheckPort(Global.Settings.Pac_Port); + } + catch + { + Global.Settings.Pac_Port = PortHelper.GetAvailablePort(); + } + + pacUrl = PACServerHandle.InitPACServer("127.0.0.1"); + } if (mode.Type is 3) { using var service = new ProxyService(); _oldState = service.Query(); - if (MainController.Server is Socks5 or Trojan && mode.BypassChina) + if (pacUrl != null) { - service.AutoConfigUrl = PACServerHandle.InitPACServer("127.0.0.1"); - + service.AutoConfigUrl = pacUrl; service.Pac(); } else diff --git a/Netch/Models/Setting.cs b/Netch/Models/Setting.cs index a2c4414e..0e7b3912 100644 --- a/Netch/Models/Setting.cs +++ b/Netch/Models/Setting.cs @@ -174,7 +174,7 @@ namespace Netch.Models /// /// PAC端口 /// - public int Pac_Port { get; set; } = 2803; + public ushort Pac_Port { get; set; } = 2803; /// /// 不代理TCP @@ -293,6 +293,8 @@ namespace Netch.Models public V2rayConfig V2RayConfig { get; set; } = new(); + public bool? AlwaysStartPACServer { get; set; } + public Setting Clone() { return (Setting) MemberwiseClone(); diff --git a/Netch/Utils/HttpProxyHandler/HttpWebServer.cs b/Netch/Utils/HttpProxyHandler/HttpWebServer.cs index 30c4ccbe..00ad981a 100644 --- a/Netch/Utils/HttpProxyHandler/HttpWebServer.cs +++ b/Netch/Utils/HttpProxyHandler/HttpWebServer.cs @@ -1,85 +1,67 @@ using System; using System.Net; using System.Text; -using System.Threading; namespace Netch.Utils.HttpProxyHandler { public class HttpWebServer { - private HttpListener? _listener; private readonly Func? _responderMethod; + private HttpListener? _listener; public HttpWebServer(string[] prefixes, Func method) { - try - { - _listener = new HttpListener(); + _listener = new HttpListener(); - if (!HttpListener.IsSupported) - throw new NotSupportedException("Needs Windows XP SP2, Server 2003 or later."); + // URI prefixes are required, for example + // "http://localhost:8080/index/". + if (prefixes == null || prefixes.Length == 0) + throw new ArgumentException("prefixes"); - // URI prefixes are required, for example - // "http://localhost:8080/index/". - if (prefixes == null || prefixes.Length == 0) - throw new ArgumentException("prefixes"); + // A responder method is required + if (method == null) + throw new ArgumentException("method"); - // A responder method is required - if (method == null) - throw new ArgumentException("method"); + foreach (var s in prefixes) + _listener.Prefixes.Add(s); - foreach (var s in prefixes) - _listener.Prefixes.Add(s); - - _responderMethod = method; - _listener.Start(); - } - catch (Exception ex) - { - Logging.Error("HttpWebServer():" + ex.Message); - } + _responderMethod = method; + _listener.Start(); } public HttpWebServer(Func method, params string[] prefixes) : this(prefixes, method) { } - public void Run() + public void StartWaitingRequest() { - ThreadPool.QueueUserWorkItem(o => + Logging.Info("Webserver running..."); + while (_listener?.IsListening ?? false) { - Logging.Info("Webserver running..."); + HttpListenerContext ctx; try { - while (_listener!.IsListening) - ThreadPool.QueueUserWorkItem(c => - { - var ctx = (HttpListenerContext) c; - try - { - var rstr = _responderMethod!(ctx.Request); - var buf = Encoding.UTF8.GetBytes(rstr); - ctx.Response.StatusCode = 200; - ctx.Response.ContentType = "application/x-ns-proxy-autoconfig"; - ctx.Response.ContentLength64 = buf.Length; - ctx.Response.OutputStream.Write(buf, 0, buf.Length); - } - catch - { - // ignored - } - finally - { - ctx.Response.OutputStream.Close(); - } - }, - _listener.GetContext()); + ctx = _listener.GetContext(); } - catch (Exception ex) + catch { - Logging.Error(ex.Message); + break; } - }); + + try + { + var rstr = _responderMethod!(ctx.Request); + var buf = Encoding.UTF8.GetBytes(rstr); + ctx.Response.StatusCode = 200; + ctx.Response.ContentType = "application/x-ns-proxy-autoconfig"; + ctx.Response.ContentLength64 = buf.Length; + ctx.Response.OutputStream.Write(buf, 0, buf.Length); + } + finally + { + ctx.Response.OutputStream.Close(); + } + } } public void Stop() diff --git a/Netch/Utils/HttpProxyHandler/PACServerHandle.cs b/Netch/Utils/HttpProxyHandler/PACServerHandle.cs index d4e925fc..c252233a 100644 --- a/Netch/Utils/HttpProxyHandler/PACServerHandle.cs +++ b/Netch/Utils/HttpProxyHandler/PACServerHandle.cs @@ -1,102 +1,74 @@ using System; -using System.Collections; -using System.Collections.Generic; using System.IO; using System.Net; using System.Text; +using System.Threading.Tasks; +using Netch.Controllers; namespace Netch.Utils.HttpProxyHandler { /// /// 提供PAC功能支持 /// - internal class PACServerHandle + internal static class PACServerHandle { - private static readonly Hashtable httpWebServer = new(); - private static readonly Hashtable pacList = new(); + private static HttpWebServer? _httpWebServer; + private static string? _pacContent; public static string InitPACServer(string address) { try { - if (!pacList.ContainsKey(address)) - pacList.Add(address, GetPacList(address)); - + _pacContent = GetPacList(address); var prefixes = $"http://{address}:{Global.Settings.Pac_Port}/pac/"; - var ws = new HttpWebServer(SendResponse, prefixes); - ws.Run(); - - if (!httpWebServer.ContainsKey(address)) - httpWebServer.Add(address, ws); + _httpWebServer = new HttpWebServer(SendResponse, prefixes); + Task.Run(() => _httpWebServer.StartWaitingRequest()); var pacUrl = GetPacUrl(); Logging.Info($"Webserver InitServer OK: {pacUrl}"); return pacUrl; } - catch (Exception ex) + catch { - throw new Exception("Webserver InitServer Error:" + ex.Message); + Logging.Error("Webserver InitServer Failed"); + throw; } } public static string SendResponse(HttpListenerRequest request) { - try - { - var arrAddress = request.UserHostAddress.Split(':'); - var address = "127.0.0.1"; - if (arrAddress.Length > 0) - address = arrAddress[0]; - - return pacList[address].ToString(); - } - catch (Exception ex) - { - Logging.Error("Webserver SendResponse " + ex.Message); - return ex.Message; - } + return _pacContent!; } public static void Stop() { try { - if (httpWebServer == null) - return; - - foreach (var key in httpWebServer.Keys) - { - Logging.Info("Webserver Stop " + key); - ((HttpWebServer) httpWebServer[key]).Stop(); - } - - httpWebServer.Clear(); + _httpWebServer?.Stop(); } - catch (Exception ex) + catch { - Logging.Error("Webserver Stop " + ex.Message); + // ignored } + + _httpWebServer = null; } private static string GetPacList(string address) { try { - var lstProxy = new List(); - lstProxy.Add(string.Format("PROXY {0}:{1};", address, Global.Settings.HTTPLocalPort)); + var proxy = $"PROXY {address}:{Global.Settings.HTTPLocalPort};"; + var pacfile = Path.Combine(Global.NetchDir, "bin\\pac.txt"); - var proxy = string.Join("", lstProxy.ToArray()); - var strPacfile = Path.Combine(Global.NetchDir, "bin\\pac.txt"); - - var pac = File.ReadAllText(strPacfile, Encoding.UTF8).Replace("__PROXY__", proxy); + var pac = File.ReadAllText(pacfile, Encoding.UTF8).Replace("__PROXY__", proxy); return pac; } catch { + throw new MessageException("Pac file not found!"); } - - return "No pac content"; } /// @@ -105,9 +77,7 @@ namespace Netch.Utils.HttpProxyHandler /// public static string GetPacUrl() { - var pacUrl = string.Format("http://127.0.0.1:{0}/pac/?t={1}", Global.Settings.Pac_Port, DateTime.Now.ToString("yyyyMMddHHmmssfff")); - - return pacUrl; + return $"http://127.0.0.1:{Global.Settings.Pac_Port}/pac/?t={DateTime.Now:yyyyMMddHHmmssfff}"; } } } \ No newline at end of file