using System; using System.Collections.Generic; using System.Threading; using Best.HTTP.Request.Authentication; using Best.HTTP.Shared.Logger; using Best.HTTP.Shared.Streams; namespace Best.HTTP.Proxies { /// /// Represents parameters used when connecting through a proxy server. /// /// /// The ProxyConnectParameters struct defines the parameters required when initiating a connection /// through a proxy server. It includes information about the proxy, target URI, and callbacks for success and error handling. /// This struct is commonly used during the negotiation steps in the class. /// public struct ProxyConnectParameters { /// /// The maximum number of authentication attempts allowed during proxy connection. /// public const int MaxAuthenticationAttempts = 1; /// /// The proxy server through which the connection is established. /// public Proxy proxy; /// /// The stream used for communication with the proxy server. /// public PeekableContentProviderStream stream; /// /// The target URI to reach through the proxy server. /// public Uri uri; /// /// A cancellation token that allows canceling the proxy connection operation. /// public CancellationToken token; /// /// The number of authentication attempts made during proxy connection. /// public int AuthenticationAttempts; /// /// Gets or sets a value indicating whether to create a proxy tunnel. /// /// /// A proxy tunnel, also known as a TCP tunnel, is established when communication between the client and the target server /// needs to be relayed through the proxy without modification. Setting this field to true indicates the intention /// to create a tunnel, allowing the data to pass through the proxy without interpretation or alteration by the proxy. /// This is typically used for protocols like HTTPS, where end-to-end encryption is desired, and the proxy should act as a /// pass-through conduit. /// public bool createTunel; /// /// The logging context for debugging purposes. /// public LoggingContext context; /// /// A callback to be executed upon successful proxy connection. /// public Action OnSuccess; /// /// A callback to be executed upon encountering an error during proxy connection. /// /// /// The callback includes parameters for the current connection parameters, the encountered exception, /// and a flag indicating whether the connection should be retried for authentication. /// public Action OnError; } /// /// Base class for proxy implementations, providing common proxy configuration and behavior. /// /// /// The Proxy class serves as the base class for various proxy client implementations, /// such as and . It provides a foundation for configuring proxy settings and handling /// proxy-related functionality common to all proxy types, like connecting to a proxy, setting up a request to go through the proxy /// and deciding whether an address is usable with the proxy or the plugin must connect directly. /// public abstract class Proxy { /// /// Address of the proxy server. It has to be in the http://proxyaddress:port form. /// public Uri Address { get; set; } /// /// Credentials for authenticating with the proxy server. /// public Credentials Credentials { get; set; } /// /// 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. /// public List Exceptions { get; set; } /// /// Initializes a new instance of the Proxy class with the specified proxy address and credentials. /// /// The address of the proxy server. /// The credentials for proxy authentication. internal Proxy(Uri address, Credentials credentials) { this.Address = address; this.Credentials = credentials; } /// /// Initiates a connection through the proxy server. Used during the negotiation steps. /// /// Parameters for the proxy connection. internal abstract void BeginConnect(ProxyConnectParameters parameters); /// /// 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. /// /// The target URI. /// The request path for proxy communication. public abstract string GetRequestPath(Uri uri); /// /// Sets up an HTTP request to use the proxy as needed. /// /// The HTTP request to set up. /// true if the request should use the proxy; otherwise, false. internal abstract bool SetupRequest(HTTPRequest request); /// /// Determines whether the proxy should be used for a specific address based on the configured exceptions. /// /// The address to check for proxy usage. /// true if the proxy should be used for the address; otherwise, false. public bool UseProxyForAddress(Uri address) { if (this.Exceptions == null) return true; string host = address.Host; // https://github.com/httplib2/httplib2/issues/94 // If domain starts with a dot (example: .example.com): // 1. Use endswith to match any subdomain (foo.example.com should match) // 2. Remove the dot and do an exact match (example.com should also match) // // If domain does not start with a dot (example: example.com): // 1. It should be an exact match. for (int i = 0; i < this.Exceptions.Count; ++i) { var exception = this.Exceptions[i]; if (exception == "*") return false; if (exception.StartsWith(".")) { // Use EndsWith to match any subdomain if (host.EndsWith(exception)) return false; // Remove the dot and exception = exception.Substring(1); } // do an exact match if (host.Equals(exception)) return false; } return true; } } }