Commit d94fe159 authored by justcoding121's avatar justcoding121

Optimize certificate creation for burst requests at same time

parent 6be0c005
...@@ -91,6 +91,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -91,6 +91,7 @@ namespace Titanium.Web.Proxy.Network
/// Cache dictionary /// Cache dictionary
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, CachedCertificate> certificateCache; private readonly ConcurrentDictionary<string, CachedCertificate> certificateCache;
private readonly ConcurrentDictionary<string, Task<X509Certificate2>> pendingCertificateTasks;
private readonly Action<Exception> exceptionFunc; private readonly Action<Exception> exceptionFunc;
...@@ -135,6 +136,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -135,6 +136,7 @@ namespace Titanium.Web.Proxy.Network
Engine = CertificateEngine.BouncyCastle; Engine = CertificateEngine.BouncyCastle;
certificateCache = new ConcurrentDictionary<string, CachedCertificate>(); certificateCache = new ConcurrentDictionary<string, CachedCertificate>();
pendingCertificateTasks = new ConcurrentDictionary<string, Task<X509Certificate2>>();
} }
public void ClearRootCertificate() public void ClearRootCertificate()
...@@ -443,19 +445,13 @@ namespace Titanium.Web.Proxy.Network ...@@ -443,19 +445,13 @@ namespace Titanium.Web.Proxy.Network
} }
/// <summary> /// <summary>
/// Create an SSL certificate /// Create an SSL certificate
/// </summary> /// </summary>
/// <param name="certificateName"></param> /// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param> /// <param name="isRootCertificate"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate) internal X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate)
{ {
if (certificateCache.ContainsKey(certificateName))
{
var cached = certificateCache[certificateName];
cached.LastAccess = DateTime.Now;
return cached.Certificate;
}
X509Certificate2 certificate = null; X509Certificate2 certificate = null;
try try
...@@ -494,19 +490,54 @@ namespace Titanium.Web.Proxy.Network ...@@ -494,19 +490,54 @@ namespace Titanium.Web.Proxy.Network
exceptionFunc(e); exceptionFunc(e);
} }
if (certificate != null) return certificate;
}
/// <summary>
/// Create an SSL certificate async
/// </summary>
/// <param name="certificateName"></param>
/// <returns></returns>
internal async Task<X509Certificate2> CreateCertificateAsync(string certificateName)
{
//handle burst requests with same certificate name
Task<X509Certificate2> task;
if (pendingCertificateTasks.TryGetValue(certificateName, out task))
{
await task;
pendingCertificateTasks.TryRemove(certificateName, out task);
}
//check in cache first
CachedCertificate cached;
if (certificateCache.TryGetValue(certificateName, out cached))
{
cached.LastAccess = DateTime.Now;
return cached.Certificate;
}
//run certificate creation task
task = Task.Run(() =>
{
return CreateCertificate(certificateName, false);
});
pendingCertificateTasks.TryAdd(certificateName, task);
await task;
pendingCertificateTasks.TryRemove(certificateName, out task);
if (task.Result != null)
{ {
//this is ConcurrentDictionary //this is ConcurrentDictionary
//if key exists it will silently handle; no need for locking //if key exists it will silently handle; no need for locking
certificateCache.TryAdd(certificateName, new CachedCertificate certificateCache.TryAdd(certificateName, new CachedCertificate
{ {
Certificate = certificate Certificate = task.Result
}); });
} }
return task.Result;
return certificate;
} }
/// <summary> /// <summary>
......
...@@ -132,7 +132,7 @@ namespace Titanium.Web.Proxy ...@@ -132,7 +132,7 @@ namespace Titanium.Web.Proxy
string certName = HttpHelper.GetWildCardDomainName(connectHostname); string certName = HttpHelper.GetWildCardDomainName(connectHostname);
var certificate = endPoint.GenericCertificate ?? CertificateManager.CreateCertificate(certName, false); var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false);
...@@ -252,7 +252,7 @@ namespace Titanium.Web.Proxy ...@@ -252,7 +252,7 @@ namespace Titanium.Web.Proxy
string sniHostName = clientHelloInfo.GetServerName(); string sniHostName = clientHelloInfo.GetServerName();
string certName = HttpHelper.GetWildCardDomainName(sniHostName ?? endPoint.GenericCertificateName); string certName = HttpHelper.GetWildCardDomainName(sniHostName ?? endPoint.GenericCertificateName);
var certificate = CertificateManager.CreateCertificate(certName, false); var certificate = await CertificateManager.CreateCertificateAsync(certName);
//Successfully managed to authenticate the client using the fake certificate //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment