ProxyDetector.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #if !UNITY_WEBGL || UNITY_EDITOR
  2. using System;
  3. using Best.HTTP.Shared;
  4. using Best.HTTP.Hosts.Connections;
  5. using Best.HTTP.Request.Timings;
  6. namespace Best.HTTP.Proxies.Autodetect
  7. {
  8. /// <summary>
  9. /// Interface for custom proxy-detection logic.
  10. /// </summary>
  11. public interface IProxyDetector
  12. {
  13. /// <summary>
  14. /// Receives the <see cref="HTTPRequest"/> instance this detector has to try to find a proxy.
  15. /// </summary>
  16. /// <param name="request"><see cref="HTTPRequest"/>instance to find a proxy for</param>
  17. /// <returns>A concrete <see cref="Proxy"/> implementation, or <c>null</c> if no proxy could be found.</returns>
  18. Proxy GetProxy(HTTPRequest request);
  19. }
  20. /// <summary>
  21. /// Possible detection modes the <see cref="ProxyDetector"/> can be in.
  22. /// </summary>
  23. public enum ProxyDetectionMode
  24. {
  25. /// <summary>
  26. /// In Continuous mode the ProxyDetector will check for a proxy for every request.
  27. /// </summary>
  28. Continuous,
  29. /// <summary>
  30. /// This mode will cache the first Proxy found and use it for consecutive requests.
  31. /// </summary>
  32. CacheFirstFound
  33. }
  34. /// <summary>
  35. /// Helper class to contain, manage and execute logic to detect available proxy on the network. It's a wrapper class to execute the various <see cref="IProxyDetector"/>s.
  36. /// </summary>
  37. public sealed class ProxyDetector
  38. {
  39. public static IProxyDetector[] GetDefaultDetectors() => new IProxyDetector[] {
  40. // HTTPManager.Proxy has the highest priority
  41. new ProgrammaticallyAddedProxyDetector(),
  42. // then comes the environment set
  43. new EnvironmentProxyDetector(),
  44. // .net framework's detector
  45. new FrameworkProxyDetector(),
  46. #if UNITY_ANDROID && !UNITY_EDITOR
  47. new AndroidProxyDetector(),
  48. #endif
  49. };
  50. private IProxyDetector[] _proxyDetectors;
  51. private ProxyDetectionMode _detectionMode;
  52. private bool _attached;
  53. public ProxyDetector()
  54. : this(ProxyDetectionMode.CacheFirstFound, GetDefaultDetectors())
  55. { }
  56. public ProxyDetector(ProxyDetectionMode detectionMode)
  57. :this(detectionMode, GetDefaultDetectors())
  58. { }
  59. public ProxyDetector(ProxyDetectionMode detectionMode, IProxyDetector[] proxyDetectors)
  60. {
  61. this._detectionMode = detectionMode;
  62. this._proxyDetectors = proxyDetectors;
  63. if (this._proxyDetectors != null)
  64. Reattach();
  65. }
  66. public void Reattach()
  67. {
  68. HTTPManager.Logger.Information(nameof(ProxyDetector), $"{nameof(Reattach)}({this._attached})");
  69. if (!this._attached)
  70. {
  71. RequestEventHelper.OnEvent += OnRequestEvent;
  72. this._attached = true;
  73. }
  74. }
  75. /// <summary>
  76. /// Call Detach() to disable ProxyDetector's logic to find and set a proxy.
  77. /// </summary>
  78. public void Detach()
  79. {
  80. HTTPManager.Logger.Information(nameof(ProxyDetector), $"{nameof(Detach)}({this._attached})");
  81. if (this._attached)
  82. {
  83. RequestEventHelper.OnEvent -= OnRequestEvent;
  84. this._attached = false;
  85. }
  86. }
  87. private void OnRequestEvent(RequestEventInfo @event)
  88. {
  89. // The Resend event is raised for every request when it's queued up (sent or redirected).
  90. if (@event.Event == RequestEvents.Resend &&
  91. @event.SourceRequest.ProxySettings != null &&
  92. @event.SourceRequest.ProxySettings.Proxy == null)
  93. {
  94. Uri uri = @event.SourceRequest.CurrentUri;
  95. if (uri.Scheme.Equals("file"))
  96. return;
  97. @event.SourceRequest.Timing.StartNext(TimingEventNames.ProxyDetection);
  98. try
  99. {
  100. for (int i = 0; i < this._proxyDetectors.Length; i++)
  101. {
  102. var detector = this._proxyDetectors[i];
  103. if (detector == null)
  104. continue;
  105. if (HTTPManager.Logger.IsDiagnostic)
  106. HTTPManager.Logger.Verbose(nameof(ProxyDetector), $"Calling {detector.GetType().Name}'s GetProxy", @event.SourceRequest.Context);
  107. Proxy proxy = null;
  108. #if ENABLE_PROFILER
  109. using (var _ = new Unity.Profiling.ProfilerMarker($"{detector.GetType().Name}.GetProxy").Auto())
  110. #endif
  111. proxy = detector.GetProxy(@event.SourceRequest);
  112. #if ENABLE_PROFILER
  113. using (var _ = new Unity.Profiling.ProfilerMarker($"{detector.GetType().Name}.UseProxyForAddress").Auto())
  114. #endif
  115. if (proxy != null && proxy.UseProxyForAddress(uri))
  116. {
  117. if (HTTPManager.Logger.IsDiagnostic)
  118. HTTPManager.Logger.Verbose(nameof(ProxyDetector), $"[{detector.GetType().Name}] Proxy found: {proxy.Address} ", @event.SourceRequest.Context);
  119. switch (this._detectionMode)
  120. {
  121. case ProxyDetectionMode.Continuous:
  122. @event.SourceRequest.ProxySettings.Proxy = proxy;
  123. break;
  124. case ProxyDetectionMode.CacheFirstFound:
  125. HTTPManager.Proxy = @event.SourceRequest.ProxySettings.Proxy = proxy;
  126. HTTPManager.Logger.Verbose(nameof(ProxyDetector), $"Proxy cached in HTTPManager.Proxy!", @event.SourceRequest.Context);
  127. Detach();
  128. break;
  129. }
  130. return;
  131. }
  132. }
  133. HTTPManager.Logger.Information(nameof(ProxyDetector), $"No Proxy for '{uri}'.", @event.SourceRequest.Context);
  134. }
  135. catch (Exception ex)
  136. {
  137. if (HTTPManager.Logger.IsDiagnostic)
  138. HTTPManager.Logger.Exception(nameof(ProxyDetector), $"GetProxyFor({@event.SourceRequest.CurrentUri})", ex, @event.SourceRequest.Context);
  139. }
  140. finally
  141. {
  142. @event.SourceRequest.Timing.StartNext(TimingEventNames.Queued);
  143. }
  144. }
  145. }
  146. }
  147. }
  148. #endif