Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Adds ability to handle upstream proxy connect failures #678

Merged
merged 1 commit into from
Nov 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public ProxyTestController()
proxyServer.ForwardToUpstreamGateway = true;
proxyServer.CertificateManager.SaveFakeCertificates = true;

// this is just to show the functionality, provided implementations use junk value
//proxyServer.GetCustomUpStreamProxyFunc = onGetCustomUpStreamProxyFunc;
//proxyServer.CustomUpStreamProxyFailureFunc = onCustomUpStreamProxyFailureFunc;

// optionally set the Certificate Engine
// Under Mono or Non-Windows runtimes only BouncyCastle will be supported
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
Expand Down Expand Up @@ -116,6 +120,18 @@ public void Stop()
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
}

private async Task<IExternalProxy> onGetCustomUpStreamProxyFunc(SessionEventArgsBase arg)
{
// this is just to show the functionality, provided values are junk
return new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.9", Port = 9090, Password = "fake", UserName = "fake", UseDefaultCredentials = false };
}

private async Task<IExternalProxy> onCustomUpStreamProxyFailureFunc(SessionEventArgsBase arg)
{
// this is just to show the functionality, provided values are junk
return new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.10", Port = 9191, Password = "fake2", UserName = "fake2", UseDefaultCredentials = false };
}

private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.HttpClient.Request.RequestUri.Host;
Expand Down
10 changes: 10 additions & 0 deletions src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,16 @@ private async Task<TcpServerConnection> createServerConnection(string remoteHost

if (tcpClient == null)
{
if (session != null && proxyServer.CustomUpStreamProxyFailureFunc != null)
{
var newUpstreamProxy = await proxyServer.CustomUpStreamProxyFailureFunc(session);
if (newUpstreamProxy != null)
{
session.CustomUpStreamProxyUsed = newUpstreamProxy;
session.TimeLine["Retrying Upstream Proxy Connection"] = DateTime.Now;
return await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps, sslProtocol, applicationProtocols, isConnect, proxyServer, session, upStreamEndPoint, externalProxy, cacheKey, cancellationToken);
}
}
throw new Exception($"Could not establish connection to {hostname}", lastException);
}

Expand Down
6 changes: 6 additions & 0 deletions src/Titanium.Web.Proxy/ProxyServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ public ProxyServer(string? rootCertificateName, string? rootCertificateIssuerNam
/// </summary>
public Func<SessionEventArgsBase, Task<IExternalProxy?>>? GetCustomUpStreamProxyFunc { get; set; }

/// <summary>
/// A callback to provide a chance for an upstream proxy failure to be handled by a new upstream proxy.
/// User should return the ExternalProxy object with valid credentials or null.
/// </summary>
public Func<SessionEventArgsBase, Task<IExternalProxy?>>? CustomUpStreamProxyFailureFunc { get; set; }

/// <summary>
/// Callback for error events in this proxy instance.
/// </summary>
Expand Down