diff --git a/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs b/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs
index d4992c91a..083b1a3f3 100644
--- a/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs
+++ b/src/Titanium.Web.Proxy/Certificates/CertificateManager.cs
@@ -120,7 +120,7 @@ private ICertificateMaker certEngine
///
internal CertificateManager(string? rootCertificateName, string? rootCertificateIssuerName,
bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin,
- ExceptionHandler exceptionFunc)
+ ExceptionHandler? exceptionFunc)
{
ExceptionFunc = exceptionFunc;
@@ -167,7 +167,7 @@ internal CertificateManager(string? rootCertificateName, string? rootCertificate
///
/// Exception handler
///
- internal ExceptionHandler ExceptionFunc { get; set; }
+ internal ExceptionHandler? ExceptionFunc { get; set; }
///
/// Select Certificate Engine.
@@ -339,7 +339,7 @@ private void installCertificate(StoreName storeName, StoreLocation storeLocation
}
catch (Exception e)
{
- ExceptionFunc(
+ onException(
new Exception("Failed to make system trust root certificate "
+ $" for {storeName}\\{storeLocation} store location. You may need admin rights.",
e));
@@ -360,7 +360,7 @@ private void uninstallCertificate(StoreName storeName, StoreLocation storeLocati
{
if (certificate == null)
{
- ExceptionFunc(new Exception("Could not remove certificate as it is null or empty."));
+ onException(new Exception("Could not remove certificate as it is null or empty."));
return;
}
@@ -374,9 +374,8 @@ private void uninstallCertificate(StoreName storeName, StoreLocation storeLocati
}
catch (Exception e)
{
- ExceptionFunc(
- new Exception("Failed to remove root certificate trust "
- + $" for {storeLocation} store location. You may need admin rights.", e));
+ onException(new Exception("Failed to remove root certificate trust "
+ + $" for {storeLocation} store location. You may need admin rights.", e));
}
finally
{
@@ -408,6 +407,11 @@ private X509Certificate2 makeCertificate(string certificateName, bool isRootCert
return certificate;
}
+ private void onException(Exception exception)
+ {
+ ExceptionFunc?.Invoke(exception);
+ }
+
private static ConcurrentDictionary saveCertificateLocks
= new ConcurrentDictionary();
@@ -434,13 +438,13 @@ private static ConcurrentDictionary saveCertificateLocks
if (certificate != null && certificate.NotAfter <= DateTime.Now)
{
- ExceptionFunc(new Exception($"Cached certificate for {subjectName} has expired."));
+ onException(new Exception($"Cached certificate for {subjectName} has expired."));
certificate = null;
}
}
catch (Exception e)
{
- ExceptionFunc(new Exception("Failed to load fake certificate.", e));
+ onException(new Exception("Failed to load fake certificate.", e));
certificate = null;
}
@@ -472,7 +476,7 @@ private static ConcurrentDictionary saveCertificateLocks
}
catch (Exception e)
{
- ExceptionFunc(new Exception("Failed to save fake certificate.", e));
+ onException(new Exception("Failed to save fake certificate.", e));
}
});
}
@@ -484,7 +488,7 @@ private static ConcurrentDictionary saveCertificateLocks
}
catch (Exception e)
{
- ExceptionFunc(e);
+ onException(e);
certificate = null;
}
@@ -628,7 +632,7 @@ public bool CreateRootCertificate(bool persistToFile = true)
if (rootCert != null && rootCert.NotAfter <= DateTime.Now)
{
- ExceptionFunc(new Exception("Loaded root certificate has expired."));
+ onException(new Exception("Loaded root certificate has expired."));
return false;
}
@@ -641,7 +645,7 @@ public bool CreateRootCertificate(bool persistToFile = true)
catch (Exception e)
{
// root cert cannot be loaded
- ExceptionFunc(new Exception("Root cert cannot be loaded.", e));
+ onException(new Exception("Root cert cannot be loaded.", e));
}
}
@@ -651,7 +655,7 @@ public bool CreateRootCertificate(bool persistToFile = true)
}
catch (Exception e)
{
- ExceptionFunc(e);
+ onException(e);
}
if (persistToFile && RootCertificate != null)
@@ -664,14 +668,14 @@ public bool CreateRootCertificate(bool persistToFile = true)
}
catch (Exception e)
{
- ExceptionFunc(new Exception("An error happened when clearing certificate cache.", e));
+ onException(new Exception("An error happened when clearing certificate cache.", e));
}
certificateCache.SaveRootCertificate(PfxFilePath, PfxPassword, RootCertificate);
}
catch (Exception e)
{
- ExceptionFunc(e);
+ onException(e);
}
}
@@ -691,7 +695,7 @@ public bool CreateRootCertificate(bool persistToFile = true)
if (rootCert != null && rootCert.NotAfter <= DateTime.Now)
{
- ExceptionFunc(new ArgumentException("Loaded root certificate has expired."));
+ onException(new ArgumentException("Loaded root certificate has expired."));
return null;
}
@@ -699,7 +703,7 @@ public bool CreateRootCertificate(bool persistToFile = true)
}
catch (Exception e)
{
- ExceptionFunc(e);
+ onException(e);
return null;
}
}
@@ -808,7 +812,7 @@ public bool TrustRootCertificateAsAdmin(bool machineTrusted = false)
}
catch (Exception e)
{
- ExceptionFunc(e);
+ onException(e);
return false;
}
@@ -1002,7 +1006,11 @@ void dispose(bool disposing)
return;
}
- clearCertificatesTokenSource.Dispose();
+ if (disposing)
+ {
+ clearCertificatesTokenSource.Dispose();
+ }
+
disposed = true;
}
diff --git a/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMaker.cs b/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMaker.cs
index c4ad9e65c..fc13eb430 100644
--- a/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMaker.cs
+++ b/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMaker.cs
@@ -34,9 +34,9 @@ internal class BCCertificateMaker : ICertificateMaker
// Set this flag to true when exception detected to avoid further exceptions
private static bool doNotSetFriendlyName;
- private readonly ExceptionHandler exceptionFunc;
+ private readonly ExceptionHandler? exceptionFunc;
- internal BCCertificateMaker(ExceptionHandler exceptionFunc, int certificateValidDays)
+ internal BCCertificateMaker(ExceptionHandler? exceptionFunc, int certificateValidDays)
{
this.certificateValidDays = certificateValidDays;
this.exceptionFunc = exceptionFunc;
diff --git a/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMakerFast.cs b/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMakerFast.cs
index 3b3f9d330..e90e6a440 100644
--- a/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMakerFast.cs
+++ b/src/Titanium.Web.Proxy/Certificates/Makers/BCCertificateMakerFast.cs
@@ -34,11 +34,11 @@ internal class BCCertificateMakerFast : ICertificateMaker
// Set this flag to true when exception detected to avoid further exceptions
private static bool doNotSetFriendlyName;
- private readonly ExceptionHandler exceptionFunc;
+ private readonly ExceptionHandler? exceptionFunc;
public AsymmetricCipherKeyPair KeyPair { get; set; }
- internal BCCertificateMakerFast(ExceptionHandler exceptionFunc, int certificateValidDays)
+ internal BCCertificateMakerFast(ExceptionHandler? exceptionFunc, int certificateValidDays)
{
this.certificateValidDays = certificateValidDays;
this.exceptionFunc = exceptionFunc;
diff --git a/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs b/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs
index 01fe8ec39..dd845679b 100644
--- a/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs
+++ b/src/Titanium.Web.Proxy/Certificates/Makers/WinCertificateMaker.cs
@@ -17,7 +17,7 @@ internal class WinCertificateMaker : ICertificateMaker
// Validity Days for Root Certificates Generated.
private int certificateValidDays;
- private readonly ExceptionHandler exceptionFunc;
+ private readonly ExceptionHandler? exceptionFunc;
private readonly string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
@@ -53,7 +53,7 @@ internal class WinCertificateMaker : ICertificateMaker
///
/// Constructor.
///
- internal WinCertificateMaker(ExceptionHandler exceptionFunc, int certificateValidDays)
+ internal WinCertificateMaker(ExceptionHandler? exceptionFunc, int certificateValidDays)
{
this.certificateValidDays = certificateValidDays;
this.exceptionFunc = exceptionFunc;
diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
index a36a36503..43644f1d1 100644
--- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
@@ -144,7 +144,7 @@ internal void OnMultipartRequestPartSent(ReadOnlySpan boundary, HeaderColl
}
catch (Exception ex)
{
- ExceptionFunc(new Exception("Exception thrown in user event", ex));
+ OnException(new Exception("Exception thrown in user event", ex));
}
}
@@ -684,7 +684,8 @@ public void TerminateServerConnection()
HttpClient.CloseServerConnection = true;
}
- private bool disposed = false;
+ private bool disposed;
+
protected override void Dispose(bool disposing)
{
if (disposed)
@@ -700,6 +701,11 @@ protected override void Dispose(bool disposing)
~SessionEventArgs()
{
+#if DEBUG
+ // Finalizer should not be called
+ System.Diagnostics.Debugger.Break();
+#endif
+
Dispose(false);
}
}
diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
index 8828999c8..68493e5f1 100644
--- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
+++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs
@@ -37,7 +37,7 @@ public abstract class SessionEventArgsBase : ProxyEventArgsBase, IDisposable
public Guid ServerConnectionId => HttpClient.HasConnection ? ServerConnection.Id : Guid.Empty;
protected readonly IBufferPool BufferPool;
- protected readonly ExceptionHandler ExceptionFunc;
+ protected readonly ExceptionHandler? ExceptionFunc;
private bool enableWinAuth;
///
@@ -150,6 +150,11 @@ public bool EnableWinAuth
///
public Exception? Exception { get; internal set; }
+ protected void OnException(Exception exception)
+ {
+ ExceptionFunc?.Invoke(exception);
+ }
+
private bool disposed = false;
protected virtual void Dispose(bool disposing)
@@ -159,19 +164,18 @@ protected virtual void Dispose(bool disposing)
return;
}
- disposed = true;
-
if (disposing)
{
CustomUpStreamProxyUsed = null;
- DataSent = null;
- DataReceived = null;
- Exception = null;
+ HttpClient.FinishSession();
}
- HttpClient.FinishSession();
+ DataSent = null;
+ DataReceived = null;
+ Exception = null;
+ disposed = true;
}
public void Dispose()
@@ -182,6 +186,11 @@ public void Dispose()
~SessionEventArgsBase()
{
+#if DEBUG
+ // Finalizer should not be called
+ System.Diagnostics.Debugger.Break();
+#endif
+
Dispose(false);
}
@@ -203,7 +212,7 @@ internal void OnDataSent(byte[] buffer, int offset, int count)
}
catch (Exception ex)
{
- ExceptionFunc(new Exception("Exception thrown in user event", ex));
+ OnException(new Exception("Exception thrown in user event", ex));
}
}
@@ -215,7 +224,7 @@ internal void OnDataReceived(byte[] buffer, int offset, int count)
}
catch (Exception ex)
{
- ExceptionFunc(new Exception("Exception thrown in user event", ex));
+ OnException(new Exception("Exception thrown in user event", ex));
}
}
diff --git a/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
index e41c1aa96..5eaf32d85 100644
--- a/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
+++ b/src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs
@@ -60,7 +60,7 @@ internal void OnDecryptedDataSent(byte[] buffer, int offset, int count)
}
catch (Exception ex)
{
- ExceptionFunc(new Exception("Exception thrown in user event", ex));
+ OnException(new Exception("Exception thrown in user event", ex));
}
}
@@ -72,8 +72,18 @@ internal void OnDecryptedDataReceived(byte[] buffer, int offset, int count)
}
catch (Exception ex)
{
- ExceptionFunc(new Exception("Exception thrown in user event", ex));
+ OnException(new Exception("Exception thrown in user event", ex));
}
}
+
+ ~TunnelConnectSessionEventArgs()
+ {
+#if DEBUG
+ // Finalizer should not be called
+ System.Diagnostics.Debugger.Break();
+#endif
+
+ Dispose(false);
+ }
}
}
diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs
index b40e80e2f..06163f5fe 100644
--- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs
+++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs
@@ -38,10 +38,10 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
Task? prefetchConnectionTask = null;
bool closeServerConnection = false;
+ TunnelConnectSessionEventArgs? connectArgs = null;
+
try
{
- TunnelConnectSessionEventArgs? connectArgs = null;
-
var method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken);
if (clientStream.IsClosed)
{
@@ -402,6 +402,7 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream,
await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection);
clientStream.Dispose();
+ connectArgs?.Dispose();
}
}
}
diff --git a/src/Titanium.Web.Proxy/Extensions/FuncExtensions.cs b/src/Titanium.Web.Proxy/Extensions/FuncExtensions.cs
index 9e7c018f3..2665e3751 100644
--- a/src/Titanium.Web.Proxy/Extensions/FuncExtensions.cs
+++ b/src/Titanium.Web.Proxy/Extensions/FuncExtensions.cs
@@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.Extensions
internal static class FuncExtensions
{
internal static async Task InvokeAsync(this AsyncEventHandler callback, object sender, T args,
- ExceptionHandler exceptionFunc)
+ ExceptionHandler? exceptionFunc)
{
var invocationList = callback.GetInvocationList();
@@ -18,7 +18,7 @@ internal static async Task InvokeAsync(this AsyncEventHandler callback, ob
}
private static async Task internalInvokeAsync(AsyncEventHandler callback, object sender, T args,
- ExceptionHandler exceptionFunc)
+ ExceptionHandler? exceptionFunc)
{
try
{
@@ -26,7 +26,7 @@ private static async Task internalInvokeAsync(AsyncEventHandler callback,
}
catch (Exception e)
{
- exceptionFunc(new Exception("Exception thrown in user event", e));
+ exceptionFunc?.Invoke(new Exception("Exception thrown in user event", e));
}
}
}
diff --git a/src/Titanium.Web.Proxy/Handlers/ProxyAuthorizationHandler.cs b/src/Titanium.Web.Proxy/Handlers/ProxyAuthorizationHandler.cs
index 4bbcbd751..67e88397a 100644
--- a/src/Titanium.Web.Proxy/Handlers/ProxyAuthorizationHandler.cs
+++ b/src/Titanium.Web.Proxy/Handlers/ProxyAuthorizationHandler.cs
@@ -72,7 +72,7 @@ private async Task checkAuthorization(SessionEventArgsBase session)
}
catch (Exception e)
{
- ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e,
+ onException(null, new ProxyAuthorizationException("Error whilst authorizing request", session, e,
httpHeaders));
// Return not authorized
diff --git a/src/Titanium.Web.Proxy/Helpers/TcpHelper.cs b/src/Titanium.Web.Proxy/Helpers/TcpHelper.cs
index 97e80301f..fe4880069 100644
--- a/src/Titanium.Web.Proxy/Helpers/TcpHelper.cs
+++ b/src/Titanium.Web.Proxy/Helpers/TcpHelper.cs
@@ -133,7 +133,7 @@ private static async Task sendRawTap(Stream clientStream, Stream serverStream, I
internal static Task SendRaw(Stream clientStream, Stream serverStream, IBufferPool bufferPool,
Action? onDataSend, Action? onDataReceive,
CancellationTokenSource cancellationTokenSource,
- ExceptionHandler exceptionFunc)
+ ExceptionHandler? exceptionFunc)
{
// todo: fix APM mode
return sendRawTap(clientStream, serverStream, bufferPool, onDataSend, onDataReceive,
diff --git a/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs b/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs
index 56d21a355..e328cf87f 100644
--- a/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs
+++ b/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs
@@ -349,32 +349,21 @@ private enum AutoWebProxyState
private bool disposed = false;
- void dispose(bool disposing)
+ public void Dispose()
{
if (disposed)
{
return;
}
- disposed = true;
-
if (session == null || session.IsInvalid)
{
return;
}
session.Close();
- }
-
- public void Dispose()
- {
- dispose(true);
- GC.SuppressFinalize(this);
- }
- ~WinHttpWebProxyFinder()
- {
- dispose(false);
+ disposed = true;
}
}
}
diff --git a/src/Titanium.Web.Proxy/Http2/Http2Helper.cs b/src/Titanium.Web.Proxy/Http2/Http2Helper.cs
index 125e5185a..3705cd42f 100644
--- a/src/Titanium.Web.Proxy/Http2/Http2Helper.cs
+++ b/src/Titanium.Web.Proxy/Http2/Http2Helper.cs
@@ -34,7 +34,7 @@ internal static async Task SendHttp2(Stream clientStream, Stream serverStream,
Func sessionFactory,
Func onBeforeRequest, Func onBeforeResponse,
CancellationTokenSource cancellationTokenSource, Guid connectionId,
- ExceptionHandler exceptionFunc)
+ ExceptionHandler? exceptionFunc)
{
var clientSettings = new Http2Settings();
var serverSettings = new Http2Settings();
@@ -62,7 +62,7 @@ private static async Task copyHttp2FrameAsync(Stream input, Stream output,
Func sessionFactory, ConcurrentDictionary sessions,
Func onBeforeRequestResponse,
Guid connectionId, bool isClient, CancellationToken cancellationToken,
- ExceptionHandler exceptionFunc)
+ ExceptionHandler? exceptionFunc)
{
int headerTableSize = 0;
Decoder? decoder = null;
@@ -281,7 +281,7 @@ private static async Task copyHttp2FrameAsync(Stream input, Stream output,
}
catch (Exception ex)
{
- exceptionFunc(new ProxyHttpException("Failed to decode HTTP/2 headers", ex, args));
+ exceptionFunc?.Invoke(new ProxyHttpException("Failed to decode HTTP/2 headers", ex, args));
}
if (!endHeaders)
@@ -351,7 +351,7 @@ private static async Task copyHttp2FrameAsync(Stream input, Stream output,
if (streamId == 0)
{
// connection error
- exceptionFunc(new ProxyHttpException("HTTP/2 connection error. Error code: " + errorCode, null, args));
+ exceptionFunc?.Invoke(new ProxyHttpException("HTTP/2 connection error. Error code: " + errorCode, null, args));
return;
}
else
@@ -361,7 +361,7 @@ private static async Task copyHttp2FrameAsync(Stream input, Stream output,
if (errorCode != 8 /*cancel*/)
{
- exceptionFunc(new ProxyHttpException("HTTP/2 stream error. Error code: " + errorCode, null, args));
+ exceptionFunc?.Invoke(new ProxyHttpException("HTTP/2 stream error. Error code: " + errorCode, null, args));
}
}
}
diff --git a/src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs
index a364a9b2d..558c6dce3 100644
--- a/src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs
+++ b/src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs
@@ -43,7 +43,7 @@ public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = tr
public event AsyncEventHandler? BeforeTunnelConnectResponse;
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
- TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
+ TunnelConnectSessionEventArgs connectArgs, ExceptionHandler? exceptionFunc)
{
if (BeforeTunnelConnectRequest != null)
{
@@ -52,7 +52,7 @@ internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
}
internal async Task InvokeBeforeTunnelConnectResponse(ProxyServer proxyServer,
- TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false)
+ TunnelConnectSessionEventArgs connectArgs, ExceptionHandler? exceptionFunc, bool isClientHello = false)
{
if (BeforeTunnelConnectResponse != null)
{
diff --git a/src/Titanium.Web.Proxy/Models/SocksProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/SocksProxyEndPoint.cs
index 3cc428011..915f005f7 100644
--- a/src/Titanium.Web.Proxy/Models/SocksProxyEndPoint.cs
+++ b/src/Titanium.Web.Proxy/Models/SocksProxyEndPoint.cs
@@ -37,7 +37,7 @@ public SocksProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true)
public event AsyncEventHandler? BeforeSslAuthenticate;
internal override async Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer,
- BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc)
+ BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler? exceptionFunc)
{
if (BeforeSslAuthenticate != null)
{
diff --git a/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs
index 9ebca387f..f4bf7a7fe 100644
--- a/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs
+++ b/src/Titanium.Web.Proxy/Models/TransparentBaseProxyEndPoint.cs
@@ -18,6 +18,6 @@ protected TransparentBaseProxyEndPoint(IPAddress ipAddress, int port, bool decry
}
internal abstract Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer,
- BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc);
+ BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler? exceptionFunc);
}
}
diff --git a/src/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs b/src/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs
index 6f58a4956..58fc755ac 100644
--- a/src/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs
+++ b/src/Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs
@@ -37,7 +37,7 @@ public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl =
public event AsyncEventHandler? BeforeSslAuthenticate;
internal override async Task InvokeBeforeSslAuthenticate(ProxyServer proxyServer,
- BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler exceptionFunc)
+ BeforeSslAuthenticateEventArgs connectArgs, ExceptionHandler? exceptionFunc)
{
if (BeforeSslAuthenticate != null)
{
diff --git a/src/Titanium.Web.Proxy/Network/RetryPolicy.cs b/src/Titanium.Web.Proxy/Network/RetryPolicy.cs
index 19863cba0..ab6048ff4 100644
--- a/src/Titanium.Web.Proxy/Network/RetryPolicy.cs
+++ b/src/Titanium.Web.Proxy/Network/RetryPolicy.cs
@@ -49,29 +49,19 @@ internal async Task ExecuteAsync(Func FillBufferAsync(CancellationToken cancellationToken
return encoding.GetString(buffer, 0, bufferDataLength);
}
- ///
- /// Read until the last new line, ignores the result
- ///
- ///
- public async Task ReadAndIgnoreAllLinesAsync(CancellationToken cancellationToken = default)
- {
- while (!string.IsNullOrEmpty(await ReadLineAsync(cancellationToken)))
- {
- }
- }
-
///
/// Base Stream.BeginRead will call this.Read and block thread (we don't want this, Network stream handles async)
/// In order to really async Reading Launch this.ReadAsync as Task will fire NetworkStream.ReadAsync
diff --git a/src/Titanium.Web.Proxy/Network/TcpConnection/TcpClientConnection.cs b/src/Titanium.Web.Proxy/Network/TcpConnection/TcpClientConnection.cs
index a1745fb37..14aa5562c 100644
--- a/src/Titanium.Web.Proxy/Network/TcpConnection/TcpClientConnection.cs
+++ b/src/Titanium.Web.Proxy/Network/TcpConnection/TcpClientConnection.cs
@@ -90,13 +90,16 @@ protected virtual void Dispose(bool disposing)
await Task.Delay(1000);
proxyServer.UpdateClientConnectionCount(false);
- try
+ if (disposing)
{
- tcpClientSocket.Close();
- }
- catch
- {
- // ignore
+ try
+ {
+ tcpClientSocket.Close();
+ }
+ catch
+ {
+ // ignore
+ }
}
});
@@ -111,6 +114,11 @@ public void Dispose()
~TcpClientConnection()
{
+#if DEBUG
+ // Finalizer should not be called
+ System.Diagnostics.Debugger.Break();
+#endif
+
Dispose(false);
}
}
diff --git a/src/Titanium.Web.Proxy/Network/TcpConnection/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/TcpConnection/TcpConnectionFactory.cs
index 23e86a54e..acd457469 100644
--- a/src/Titanium.Web.Proxy/Network/TcpConnection/TcpConnectionFactory.cs
+++ b/src/Titanium.Web.Proxy/Network/TcpConnection/TcpConnectionFactory.cs
@@ -543,14 +543,14 @@ internal Task GetServerConnection(ProxyServer proxyServer,
await stream.WriteRequestAsync(connectRequest, cancellationToken);
var httpStatus = await stream.ReadResponseStatus(cancellationToken);
+ var headers = new HeaderCollection();
+ await HeaderParser.ReadHeaders(stream, headers, cancellationToken);
if (httpStatus.StatusCode != 200 && !httpStatus.Description.EqualsIgnoreCase("OK")
&& !httpStatus.Description.EqualsIgnoreCase("Connection Established"))
{
throw new Exception("Upstream proxy failed to create a secure tunnel");
}
-
- await stream.ReadAndIgnoreAllLinesAsync(cancellationToken);
}
if (isHttps)
@@ -634,7 +634,7 @@ internal Task GetServerConnection(ProxyServer proxyServer,
///
/// The Tcp server connection to return.
/// Should we just close the connection instead of reusing?
- internal async Task Release(TcpServerConnection connection, bool close = false)
+ internal async Task Release(TcpServerConnection? connection, bool close = false)
{
if (connection == null)
{
@@ -705,7 +705,10 @@ internal async Task Release(Task? connectionCreateTask, bo
{
connection = await connectionCreateTask;
}
- catch { }
+ catch
+ {
+ // ignore
+ }
finally
{
if (connection != null)
@@ -769,18 +772,17 @@ private async Task clearOutdatedConnections()
}
catch (Exception e)
{
- Server.ExceptionFunc(new Exception("An error occurred when disposing server connections.", e));
+ Server.ExceptionFunc?.Invoke(new Exception("An error occurred when disposing server connections.", e));
}
finally
{
// cleanup every 3 seconds by default
await Task.Delay(1000 * 3);
}
-
}
}
- private bool disposed = false;
+ private bool disposed;
protected virtual void Dispose(bool disposing)
{
@@ -791,33 +793,36 @@ protected virtual void Dispose(bool disposing)
runCleanUpTask = false;
- try
+ if (disposing)
{
- @lock.Wait();
-
- foreach (var queue in cache.Select(x => x.Value).ToList())
+ try
{
- while (!queue.IsEmpty)
+ @lock.Wait();
+
+ foreach (var queue in cache.Select(x => x.Value).ToList())
{
- if (queue.TryDequeue(out var connection))
+ while (!queue.IsEmpty)
{
- disposalBag.Add(connection);
+ if (queue.TryDequeue(out var connection))
+ {
+ disposalBag.Add(connection);
+ }
}
}
- }
- cache.Clear();
- }
- finally
- {
- @lock.Release();
- }
+ cache.Clear();
+ }
+ finally
+ {
+ @lock.Release();
+ }
- while (!disposalBag.IsEmpty)
- {
- if (disposalBag.TryTake(out var connection))
+ while (!disposalBag.IsEmpty)
{
- connection?.Dispose();
+ if (disposalBag.TryTake(out var connection))
+ {
+ connection?.Dispose();
+ }
}
}
diff --git a/src/Titanium.Web.Proxy/Network/TcpConnection/TcpServerConnection.cs b/src/Titanium.Web.Proxy/Network/TcpConnection/TcpServerConnection.cs
index b783b39bc..d7132c38a 100644
--- a/src/Titanium.Web.Proxy/Network/TcpConnection/TcpServerConnection.cs
+++ b/src/Titanium.Web.Proxy/Network/TcpConnection/TcpServerConnection.cs
@@ -99,16 +99,21 @@ protected virtual void Dispose(bool disposing)
// so that server have enough time to call close first.
// This way we can push tcp Time_Wait to server side when possible.
await Task.Delay(1000);
+
proxyServer.UpdateServerConnectionCount(false);
- Stream.Dispose();
- try
- {
- TcpSocket.Close();
- }
- catch
+ if (disposing)
{
- // ignore
+ Stream.Dispose();
+
+ try
+ {
+ TcpSocket.Close();
+ }
+ catch
+ {
+ // ignore
+ }
}
});
@@ -123,6 +128,11 @@ public void Dispose()
~TcpServerConnection()
{
+#if DEBUG
+ // Finalizer should not be called
+ System.Diagnostics.Debugger.Break();
+#endif
+
Dispose(false);
}
}
diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs
index ca0220af6..232c192be 100644
--- a/src/Titanium.Web.Proxy/ProxyServer.cs
+++ b/src/Titanium.Web.Proxy/ProxyServer.cs
@@ -35,12 +35,6 @@ public partial class ProxyServer : IDisposable
internal static ByteString UriSchemeHttp8 = (ByteString)UriSchemeHttp;
internal static ByteString UriSchemeHttps8 = (ByteString)UriSchemeHttps;
-
- ///
- /// A default exception log func.
- ///
- private readonly ExceptionHandler defaultExceptionFunc = e => { };
-
///
/// Backing field for exposed public property.
///
@@ -301,9 +295,9 @@ public ProxyServer(string? rootCertificateName, string? rootCertificateIssuerNam
///
/// Callback for error events in this proxy instance.
///
- public ExceptionHandler ExceptionFunc
+ public ExceptionHandler? ExceptionFunc
{
- get => exceptionFunc ?? defaultExceptionFunc;
+ get => exceptionFunc;
set
{
exceptionFunc = value;
@@ -866,9 +860,9 @@ private async Task handleClient(Socket tcpClientSocket, ProxyEndPoint endPoint)
///
/// The client stream.
/// The exception.
- private void onException(HttpClientStream clientStream, Exception exception)
+ private void onException(HttpClientStream? clientStream, Exception exception)
{
- ExceptionFunc(exception);
+ ExceptionFunc?.Invoke(exception);
}
///
@@ -895,7 +889,14 @@ internal void UpdateClientConnectionCount(bool increment)
Interlocked.Decrement(ref clientConnectionCount);
}
- ClientConnectionCountChanged?.Invoke(this, EventArgs.Empty);
+ try
+ {
+ ClientConnectionCountChanged?.Invoke(this, EventArgs.Empty);
+ }
+ catch (Exception ex)
+ {
+ onException(null, ex);
+ }
}
///
@@ -913,7 +914,14 @@ internal void UpdateServerConnectionCount(bool increment)
Interlocked.Decrement(ref serverConnectionCount);
}
- ServerConnectionCountChanged?.Invoke(this, EventArgs.Empty);
+ try
+ {
+ ServerConnectionCountChanged?.Invoke(this, EventArgs.Empty);
+ }
+ catch (Exception ex)
+ {
+ onException(null, ex);
+ }
}
///
@@ -965,11 +973,21 @@ protected virtual void Dispose(bool disposing)
if (ProxyRunning)
{
- Stop();
+ try
+ {
+ Stop();
+ }
+ catch
+ {
+ // ignore
+ }
}
- CertificateManager?.Dispose();
- BufferPool?.Dispose();
+ if (disposing)
+ {
+ CertificateManager?.Dispose();
+ BufferPool?.Dispose();
+ }
}
public void Dispose()
diff --git a/src/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs
index ba6b502d8..78c2055a5 100644
--- a/src/Titanium.Web.Proxy/RequestHandler.cs
+++ b/src/Titanium.Web.Proxy/RequestHandler.cs
@@ -190,8 +190,15 @@ await HeaderParser.ReadHeaders(clientStream, args.HttpClient.Request.Headers,
clientStream.Connection.NegotiatedApplicationProtocol,
cancellationToken, cancellationTokenSource);
+ var newConnection = result.LatestConnection;
+ if (connection != newConnection && connection != null)
+ {
+ await tcpConnectionFactory.Release(connection);
+ }
+
// update connection to latest used
connection = result.LatestConnection;
+
closeServerConnection = !result.Continue;
// throw if exception happened
diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs
index b294244ba..72caadb4f 100644
--- a/src/Titanium.Web.Proxy/ResponseHandler.cs
+++ b/src/Titanium.Web.Proxy/ResponseHandler.cs
@@ -92,8 +92,13 @@ private async Task handleHttpSessionResponse(SessionEventArgs args)
// clear current response
await args.ClearResponse(cancellationToken);
- await handleHttpSessionRequest(args, null, args.ClientConnection.NegotiatedApplicationProtocol,
+ var result = await handleHttpSessionRequest(args, null, args.ClientConnection.NegotiatedApplicationProtocol,
cancellationToken, args.CancellationTokenSource);
+ if (result.LatestConnection != null)
+ {
+ args.HttpClient.SetConnection(result.LatestConnection);
+ }
+
return;
}