185 lines
7.6 KiB
C#
185 lines
7.6 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Represents parameters used when connecting through a proxy server.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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 <see cref="Best.HTTP.Shared.PlatformSupport.Network.Tcp.Negotiator"/> class.
|
|
/// </remarks>
|
|
public struct ProxyConnectParameters
|
|
{
|
|
/// <summary>
|
|
/// The maximum number of authentication attempts allowed during proxy connection.
|
|
/// </summary>
|
|
public const int MaxAuthenticationAttempts = 1;
|
|
|
|
/// <summary>
|
|
/// The proxy server through which the connection is established.
|
|
/// </summary>
|
|
public Proxy proxy;
|
|
|
|
/// <summary>
|
|
/// The stream used for communication with the proxy server.
|
|
/// </summary>
|
|
public PeekableContentProviderStream stream;
|
|
|
|
/// <summary>
|
|
/// The target URI to reach through the proxy server.
|
|
/// </summary>
|
|
public Uri uri;
|
|
|
|
/// <summary>
|
|
/// A cancellation token that allows canceling the proxy connection operation.
|
|
/// </summary>
|
|
public CancellationToken token;
|
|
|
|
/// <summary>
|
|
/// The number of authentication attempts made during proxy connection.
|
|
/// </summary>
|
|
public int AuthenticationAttempts;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to create a proxy tunnel.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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 <c>true</c> 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.
|
|
/// </remarks>
|
|
public bool createTunel;
|
|
|
|
/// <summary>
|
|
/// The logging context for debugging purposes.
|
|
/// </summary>
|
|
public LoggingContext context;
|
|
|
|
/// <summary>
|
|
/// A callback to be executed upon successful proxy connection.
|
|
/// </summary>
|
|
public Action<ProxyConnectParameters> OnSuccess;
|
|
|
|
/// <summary>
|
|
/// A callback to be executed upon encountering an error during proxy connection.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The callback includes parameters for the current connection parameters, the encountered exception,
|
|
/// and a flag indicating whether the connection should be retried for authentication.
|
|
/// </remarks>
|
|
public Action<ProxyConnectParameters, Exception, bool> OnError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Base class for proxy implementations, providing common proxy configuration and behavior.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The Proxy class serves as the base class for various proxy client implementations,
|
|
/// such as <see cref="HTTPProxy"/> and <see cref="SOCKSProxy"/>. 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.
|
|
/// </remarks>
|
|
public abstract class Proxy
|
|
{
|
|
/// <summary>
|
|
/// Address of the proxy server. It has to be in the http://proxyaddress:port form.
|
|
/// </summary>
|
|
public Uri Address { get; set; }
|
|
|
|
/// <summary>
|
|
/// Credentials for authenticating with the proxy server.
|
|
/// </summary>
|
|
public Credentials Credentials { get; set; }
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public List<string> Exceptions { get; set; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the Proxy class with the specified proxy address and credentials.
|
|
/// </summary>
|
|
/// <param name="address">The address of the proxy server.</param>
|
|
/// <param name="credentials">The credentials for proxy authentication.</param>
|
|
internal Proxy(Uri address, Credentials credentials)
|
|
{
|
|
this.Address = address;
|
|
this.Credentials = credentials;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initiates a connection through the proxy server. Used during the negotiation steps.
|
|
/// </summary>
|
|
/// <param name="parameters">Parameters for the proxy connection.</param>
|
|
internal abstract void BeginConnect(ProxyConnectParameters parameters);
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="uri">The target URI.</param>
|
|
/// <returns>The request path for proxy communication.</returns>
|
|
public abstract string GetRequestPath(Uri uri);
|
|
|
|
/// <summary>
|
|
/// Sets up an HTTP request to use the proxy as needed.
|
|
/// </summary>
|
|
/// <param name="request">The HTTP request to set up.</param>
|
|
/// <returns><c>true</c> if the request should use the proxy; otherwise, <c>false</c>.</returns>
|
|
internal abstract bool SetupRequest(HTTPRequest request);
|
|
|
|
/// <summary>
|
|
/// Determines whether the proxy should be used for a specific address based on the configured exceptions.
|
|
/// </summary>
|
|
/// <param name="address">The address to check for proxy usage.</param>
|
|
/// <returns><c>true</c> if the proxy should be used for the address; otherwise, <c>false</c>.</returns>
|
|
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;
|
|
}
|
|
}
|
|
}
|