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

Commit c3e4078

Browse files
committed
fix performance issues
1 parent ed3ce01 commit c3e4078

File tree

5 files changed

+41
-83
lines changed

5 files changed

+41
-83
lines changed

Titanium.Web.Proxy/Models/ConnectRequest.cs

Lines changed: 0 additions & 11 deletions
This file was deleted.

Titanium.Web.Proxy/Network/CustomSslStream.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ namespace Titanium.Web.Proxy.Network
1414
/// </summary>
1515
internal class CustomSslStream : SslStream
1616
{
17-
/// <summary>
18-
/// Holds the current session
19-
/// </summary>
20-
internal object Param { get; set; }
2117

2218
internal CustomSslStream(Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback clientCertificateSelectionCallback)
2319
:base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, clientCertificateSelectionCallback)

Titanium.Web.Proxy/Network/TcpConnectionManager.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,8 @@ internal class TcpConnectionManager
4040
static Dictionary<string, List<TcpConnection>> connectionCache = new Dictionary<string, List<TcpConnection>>();
4141
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
4242

43+
4344
internal static async Task<TcpConnection> GetClient(string hostname, int port, bool isHttps, Version version)
44-
{
45-
return await GetClient(null, hostname, port, isHttps, version);
46-
}
47-
internal static async Task<TcpConnection> GetClient(ConnectRequest connectRequest, string hostname, int port, bool isHttps, Version version)
4845
{
4946
List<TcpConnection> cachedConnections = null;
5047
TcpConnection cached = null;
@@ -71,14 +68,24 @@ internal static async Task<TcpConnection> GetClient(ConnectRequest connectReques
7168
finally { connectionAccessLock.Release(); }
7269

7370
if (cached != null && !cached.TcpClient.Client.IsConnected())
71+
{
72+
cached.TcpClient.Client.Dispose();
73+
cached.TcpClient.Close();
7474
continue;
75+
}
7576

7677
if (cached == null)
7778
break;
7879
}
7980

8081
if (cached == null)
81-
cached = await CreateClient(connectRequest, hostname, port, isHttps, version).ConfigureAwait(false);
82+
cached = await CreateClient(hostname, port, isHttps, version).ConfigureAwait(false);
83+
84+
if (cachedConnections == null || cachedConnections.Count() <= 2)
85+
{
86+
await CreateClient(hostname, port, isHttps, version)
87+
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
88+
}
8289

8390
return cached;
8491
}
@@ -88,7 +95,7 @@ internal static string GetConnectionKey(string hostname, int port, bool isHttps,
8895
return string.Format("{0}:{1}:{2}:{3}:{4}", hostname.ToLower(), port, isHttps, version.Major, version.Minor);
8996
}
9097

91-
private static async Task<TcpConnection> CreateClient(ConnectRequest connectRequest, string hostname, int port, bool isHttps, Version version)
98+
private static async Task<TcpConnection> CreateClient(string hostname, int port, bool isHttps, Version version)
9299
{
93100
TcpClient client;
94101
Stream stream;
@@ -132,7 +139,6 @@ private static async Task<TcpConnection> CreateClient(ConnectRequest connectRequ
132139
{
133140
sslStream = new CustomSslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate),
134141
new LocalCertificateSelectionCallback(ProxyServer.SelectClientCertificate));
135-
sslStream.Param = connectRequest;
136142
await sslStream.AuthenticateAsClientAsync(hostname, null, Constants.SupportedProtocols, false).ConfigureAwait(false);
137143
stream = (Stream)sslStream;
138144
}
@@ -172,6 +178,7 @@ private static async Task<TcpConnection> CreateClient(ConnectRequest connectRequ
172178

173179
internal static async Task ReleaseClient(TcpConnection connection)
174180
{
181+
175182
connection.LastAccess = DateTime.Now;
176183
var key = GetConnectionKey(connection.HostName, connection.port, connection.IsHttps, connection.Version);
177184
await connectionAccessLock.WaitAsync();

Titanium.Web.Proxy/RequestHandler.cs

Lines changed: 27 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -72,29 +72,23 @@ private static async void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient
7272

7373
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
7474

75-
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false);
75+
7676

7777
SslStream sslStream = null;
7878

7979
try
8080
{
81-
var connectRequest = new ConnectRequest() { Stream = clientStream, Uri = httpRemoteUri };
8281

83-
await TcpConnectionManager.GetClient(connectRequest, httpRemoteUri.Host, httpRemoteUri.Port, true, version).ConfigureAwait(false);
82+
await TcpConnectionManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version).ConfigureAwait(false);
83+
84+
sslStream = new SslStream(clientStream, true);
85+
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host, false);
86+
//Successfully managed to authenticate the client using the fake certificate
87+
await sslStream.AuthenticateAsServerAsync(certificate, false,
88+
Constants.SupportedProtocols, false).ConfigureAwait(false);
89+
//HTTPS server created - we can now decrypt the client's traffic
90+
clientStream = sslStream;
8491

85-
if (clientStream is SslStream)
86-
{
87-
sslStream = clientStream as SslStream;
88-
}
89-
else
90-
{
91-
sslStream = new SslStream(clientStream, true);
92-
//Successfully managed to authenticate the client using the fake certificate
93-
await sslStream.AuthenticateAsServerAsync(certificate, false,
94-
Constants.SupportedProtocols, false).ConfigureAwait(false);
95-
//HTTPS server created - we can now decrypt the client's traffic
96-
clientStream = sslStream;
97-
}
9892

9993
clientStreamReader = new CustomBinaryReader(sslStream);
10094
clientStreamWriter = new StreamWriter(sslStream);
@@ -192,8 +186,6 @@ await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamRea
192186
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
193187
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool isHttps)
194188
{
195-
TcpConnection connection = null;
196-
string lastRequest = null;
197189

198190
while (true)
199191
{
@@ -276,12 +268,8 @@ await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHe
276268
}
277269

278270
//construct the web request that we are going to issue on behalf of the client.
279-
connection = connection == null ?
280-
await TcpConnectionManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
281-
: lastRequest != args.WebSession.Request.RequestUri.Host ? await TcpConnectionManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
282-
: connection;
271+
var connection = await TcpConnectionManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false);
283272

284-
lastRequest = TcpConnectionManager.GetConnectionKey(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version);
285273

286274
args.WebSession.Request.RequestLocked = true;
287275

@@ -350,11 +338,12 @@ await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
350338
//if connection is closing exit
351339
if (args.WebSession.Response.ResponseKeepAlive == false)
352340
{
353-
connection.TcpClient.Close();
354341
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
355342
return;
356343
}
357344

345+
await TcpConnectionManager.ReleaseClient(connection);
346+
358347
// read the next request
359348
httpCmd = await clientStreamReader.ReadLineAsync().ConfigureAwait(false);
360349

@@ -367,8 +356,6 @@ await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
367356

368357
}
369358

370-
if (connection != null)
371-
await TcpConnectionManager.ReleaseClient(connection);
372359
}
373360

374361
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion)
@@ -460,8 +447,6 @@ internal static bool ValidateServerCertificate(
460447
X509Chain chain,
461448
SslPolicyErrors sslPolicyErrors)
462449
{
463-
var customSslStream = sender as CustomSslStream;
464-
465450
if (ServerCertificateValidationCallback != null)
466451
{
467452
var args = new CertificateValidationEventArgs();
@@ -510,43 +495,25 @@ internal static X509Certificate SelectClientCertificate(
510495
X509Certificate clientCertificate = null;
511496
var customSslStream = sender as CustomSslStream;
512497

513-
if (customSslStream.Param is ConnectRequest && remoteCertificate != null)
514-
{
515-
var connectRequest = customSslStream.Param as ConnectRequest;
516-
517-
var sslStream = new SslStream(connectRequest.Stream, true);
518-
519-
var certificate = CertManager.CreateCertificate(connectRequest.Uri.Host, false).Result;
520-
//Successfully managed to authenticate the client using the fake certificate
521-
sslStream.AuthenticateAsServerAsync(certificate, true,
522-
Constants.SupportedProtocols, false).Wait();
523-
524-
connectRequest.Stream = sslStream;
525-
526-
clientCertificate = sslStream.RemoteCertificate;
527-
528-
}
529-
else if (customSslStream.Param is ConnectRequest)
498+
if (acceptableIssuers != null &&
499+
acceptableIssuers.Length > 0 &&
500+
localCertificates != null &&
501+
localCertificates.Count > 0)
530502
{
531-
if (acceptableIssuers != null &&
532-
acceptableIssuers.Length > 0 &&
533-
localCertificates != null &&
534-
localCertificates.Count > 0)
503+
// Use the first certificate that is from an acceptable issuer.
504+
foreach (X509Certificate certificate in localCertificates)
535505
{
536-
// Use the first certificate that is from an acceptable issuer.
537-
foreach (X509Certificate certificate in localCertificates)
538-
{
539-
string issuer = certificate.Issuer;
540-
if (Array.IndexOf(acceptableIssuers, issuer) != -1)
541-
clientCertificate = certificate;
542-
}
506+
string issuer = certificate.Issuer;
507+
if (Array.IndexOf(acceptableIssuers, issuer) != -1)
508+
clientCertificate = certificate;
543509
}
544-
545-
if (localCertificates != null &&
546-
localCertificates.Count > 0)
547-
clientCertificate = localCertificates[0];
548510
}
549511

512+
if (localCertificates != null &&
513+
localCertificates.Count > 0)
514+
clientCertificate = localCertificates[0];
515+
516+
550517
if (ClientCertificateSelectionCallback != null)
551518
{
552519
var args = new CertificateSelectionEventArgs();

Titanium.Web.Proxy/Titanium.Web.Proxy.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
<Compile Include="Decompression\ZlibDecompression.cs" />
6363
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
6464
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
65-
<Compile Include="Models\ConnectRequest.cs" />
6665
<Compile Include="Network\ProxyClient.cs" />
6766
<Compile Include="Exceptions\BodyNotFoundException.cs" />
6867
<Compile Include="Extensions\HttpWebResponseExtensions.cs" />

0 commit comments

Comments
 (0)