Proxy.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using Best.HTTP.Request.Authentication;
  5. using Best.HTTP.Shared.Logger;
  6. using Best.HTTP.Shared.Streams;
  7. namespace Best.HTTP.Proxies
  8. {
  9. /// <summary>
  10. /// Represents parameters used when connecting through a proxy server.
  11. /// </summary>
  12. /// <remarks>
  13. /// The ProxyConnectParameters struct defines the parameters required when initiating a connection
  14. /// through a proxy server. It includes information about the proxy, target URI, and callbacks for success and error handling.
  15. /// This struct is commonly used during the negotiation steps in the <see cref="Best.HTTP.Shared.PlatformSupport.Network.Tcp.Negotiator"/> class.
  16. /// </remarks>
  17. public struct ProxyConnectParameters
  18. {
  19. /// <summary>
  20. /// The maximum number of authentication attempts allowed during proxy connection.
  21. /// </summary>
  22. public const int MaxAuthenticationAttempts = 1;
  23. /// <summary>
  24. /// The proxy server through which the connection is established.
  25. /// </summary>
  26. public Proxy proxy;
  27. /// <summary>
  28. /// The stream used for communication with the proxy server.
  29. /// </summary>
  30. public PeekableContentProviderStream stream;
  31. /// <summary>
  32. /// The target URI to reach through the proxy server.
  33. /// </summary>
  34. public Uri uri;
  35. /// <summary>
  36. /// A cancellation token that allows canceling the proxy connection operation.
  37. /// </summary>
  38. public CancellationToken token;
  39. /// <summary>
  40. /// The number of authentication attempts made during proxy connection.
  41. /// </summary>
  42. public int AuthenticationAttempts;
  43. /// <summary>
  44. /// Gets or sets a value indicating whether to create a proxy tunnel.
  45. /// </summary>
  46. /// <remarks>
  47. /// A proxy tunnel, also known as a TCP tunnel, is established when communication between the client and the target server
  48. /// needs to be relayed through the proxy without modification. Setting this field to <c>true</c> indicates the intention
  49. /// to create a tunnel, allowing the data to pass through the proxy without interpretation or alteration by the proxy.
  50. /// This is typically used for protocols like HTTPS, where end-to-end encryption is desired, and the proxy should act as a
  51. /// pass-through conduit.
  52. /// </remarks>
  53. public bool createTunel;
  54. /// <summary>
  55. /// The logging context for debugging purposes.
  56. /// </summary>
  57. public LoggingContext context;
  58. /// <summary>
  59. /// A callback to be executed upon successful proxy connection.
  60. /// </summary>
  61. public Action<ProxyConnectParameters> OnSuccess;
  62. /// <summary>
  63. /// A callback to be executed upon encountering an error during proxy connection.
  64. /// </summary>
  65. /// <remarks>
  66. /// The callback includes parameters for the current connection parameters, the encountered exception,
  67. /// and a flag indicating whether the connection should be retried for authentication.
  68. /// </remarks>
  69. public Action<ProxyConnectParameters, Exception, bool> OnError;
  70. }
  71. /// <summary>
  72. /// Base class for proxy implementations, providing common proxy configuration and behavior.
  73. /// </summary>
  74. /// <remarks>
  75. /// The Proxy class serves as the base class for various proxy client implementations,
  76. /// such as <see cref="HTTPProxy"/> and <see cref="SOCKSProxy"/>. It provides a foundation for configuring proxy settings and handling
  77. /// proxy-related functionality common to all proxy types, like connecting to a proxy, setting up a request to go through the proxy
  78. /// and deciding whether an address is usable with the proxy or the plugin must connect directly.
  79. /// </remarks>
  80. public abstract class Proxy
  81. {
  82. /// <summary>
  83. /// Address of the proxy server. It has to be in the http://proxyaddress:port form.
  84. /// </summary>
  85. public Uri Address { get; set; }
  86. /// <summary>
  87. /// Credentials for authenticating with the proxy server.
  88. /// </summary>
  89. public Credentials Credentials { get; set; }
  90. /// <summary>
  91. /// List of exceptions for which the proxy should not be used. Elements of this list are compared to the Host (DNS or IP address) part of the uri.
  92. /// </summary>
  93. public List<string> Exceptions { get; set; }
  94. /// <summary>
  95. /// Initializes a new instance of the Proxy class with the specified proxy address and credentials.
  96. /// </summary>
  97. /// <param name="address">The address of the proxy server.</param>
  98. /// <param name="credentials">The credentials for proxy authentication.</param>
  99. internal Proxy(Uri address, Credentials credentials)
  100. {
  101. this.Address = address;
  102. this.Credentials = credentials;
  103. }
  104. /// <summary>
  105. /// Initiates a connection through the proxy server. Used during the negotiation steps.
  106. /// </summary>
  107. /// <param name="parameters">Parameters for the proxy connection.</param>
  108. internal abstract void BeginConnect(ProxyConnectParameters parameters);
  109. /// <summary>
  110. /// Gets the request path to be used for proxy communication. In some cases with HTTPProxy, the request must send the whole uri as the request path.
  111. /// </summary>
  112. /// <param name="uri">The target URI.</param>
  113. /// <returns>The request path for proxy communication.</returns>
  114. public abstract string GetRequestPath(Uri uri);
  115. /// <summary>
  116. /// Sets up an HTTP request to use the proxy as needed.
  117. /// </summary>
  118. /// <param name="request">The HTTP request to set up.</param>
  119. /// <returns><c>true</c> if the request should use the proxy; otherwise, <c>false</c>.</returns>
  120. internal abstract bool SetupRequest(HTTPRequest request);
  121. /// <summary>
  122. /// Determines whether the proxy should be used for a specific address based on the configured exceptions.
  123. /// </summary>
  124. /// <param name="address">The address to check for proxy usage.</param>
  125. /// <returns><c>true</c> if the proxy should be used for the address; otherwise, <c>false</c>.</returns>
  126. public bool UseProxyForAddress(Uri address)
  127. {
  128. if (this.Exceptions == null)
  129. return true;
  130. string host = address.Host;
  131. // https://github.com/httplib2/httplib2/issues/94
  132. // If domain starts with a dot (example: .example.com):
  133. // 1. Use endswith to match any subdomain (foo.example.com should match)
  134. // 2. Remove the dot and do an exact match (example.com should also match)
  135. //
  136. // If domain does not start with a dot (example: example.com):
  137. // 1. It should be an exact match.
  138. for (int i = 0; i < this.Exceptions.Count; ++i)
  139. {
  140. var exception = this.Exceptions[i];
  141. if (exception == "*")
  142. return false;
  143. if (exception.StartsWith("."))
  144. {
  145. // Use EndsWith to match any subdomain
  146. if (host.EndsWith(exception))
  147. return false;
  148. // Remove the dot and
  149. exception = exception.Substring(1);
  150. }
  151. // do an exact match
  152. if (host.Equals(exception))
  153. return false;
  154. }
  155. return true;
  156. }
  157. }
  158. }