Commit 1849d31e authored by justcoding121's avatar justcoding121

optimize connection manager; fix asyn/await

parent f38199d0
......@@ -18,11 +18,11 @@ namespace Titanium.Web.Proxy.Helpers
{
public string HostName { get; set; }
public int Port { get; set; }
public bool IsSecure { get; set; }
public bool IsHttps { get; set; }
public override string ToString()
{
if (!IsSecure)
if (!IsHttps)
return "http=" + HostName + ":" + Port;
else
return "https=" + HostName + ":" + Port;
......@@ -44,11 +44,11 @@ namespace Titanium.Web.Proxy.Helpers
var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => !x.IsSecure);
existingSystemProxyValues.RemoveAll(x => !x.IsHttps);
existingSystemProxyValues.Add(new HttpSystemProxyValue()
{
HostName = hostname,
IsSecure = false,
IsHttps = false,
Port = port
});
......@@ -71,7 +71,7 @@ namespace Titanium.Web.Proxy.Helpers
var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => !x.IsSecure);
existingSystemProxyValues.RemoveAll(x => !x.IsHttps);
if (!(existingSystemProxyValues.Count() == 0))
{
......@@ -101,11 +101,11 @@ namespace Titanium.Web.Proxy.Helpers
var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => x.IsSecure);
existingSystemProxyValues.RemoveAll(x => x.IsHttps);
existingSystemProxyValues.Add(new HttpSystemProxyValue()
{
HostName = hostname,
IsSecure = true,
IsHttps = true,
Port = port
});
......@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.Helpers
var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => x.IsSecure);
existingSystemProxyValues.RemoveAll(x => x.IsHttps);
if (!(existingSystemProxyValues.Count() == 0))
{
......@@ -197,7 +197,7 @@ namespace Titanium.Web.Proxy.Helpers
{
HostName = endPoint.Split(':')[0],
Port = int.Parse(endPoint.Split(':')[1]),
IsSecure = false
IsHttps = false
};
}
else if (tmp.StartsWith("https="))
......@@ -207,7 +207,7 @@ namespace Titanium.Web.Proxy.Helpers
{
HostName = endPoint.Split(':')[0],
Port = int.Parse(endPoint.Split(':')[1]),
IsSecure = true
IsHttps = true
};
}
return null;
......
......@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.Http
public Request Request { get; set; }
public Response Response { get; set; }
public bool IsSecure
public bool IsHttps
{
get
{
......@@ -96,12 +96,9 @@ namespace Titanium.Web.Proxy.Http
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
}
var httpVersion = httpResult[0].Trim().ToLower();
Version version;
if (httpVersion == "http/1.1")
{
version = new Version(1, 1);
}
else
var version = new Version(1,1);
if (httpVersion == "http/1.0")
{
version = new Version(1, 0);
}
......
......@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Network
{
internal string HostName { get; set; }
internal int port { get; set; }
internal bool IsSecure { get; set; }
internal bool IsHttps { get; set; }
internal Version Version { get; set; }
internal TcpClient TcpClient { get; set; }
......@@ -37,29 +37,31 @@ namespace Titanium.Web.Proxy.Network
internal class TcpConnectionManager
{
static List<TcpConnection> connectionCache = new List<TcpConnection>();
static Dictionary<string, List<TcpConnection>> connectionCache = new Dictionary<string, List<TcpConnection>>();
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
internal static async Task<TcpConnection> GetClient(SessionEventArgs sessionArgs, string hostname, int port, bool isSecure, Version version)
internal static async Task<TcpConnection> GetClient(SessionEventArgs sessionArgs, string hostname, int port, bool isHttps, Version version)
{
List<TcpConnection> cachedConnections = null;
TcpConnection cached = null;
var key = GetConnectionKey(hostname, port, isHttps, version);
while (true)
{
await connectionAccessLock.WaitAsync();
try
{
cached = connectionCache.FirstOrDefault(x => x.HostName == hostname && x.port == port &&
x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version));
connectionCache.TryGetValue(key, out cachedConnections);
//just create one more preemptively
if (connectionCache.Where(x => x.HostName == hostname && x.port == port &&
x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version)).Count() < 2)
if (cachedConnections != null && cachedConnections.Count > 0)
{
var task = CreateClient(sessionArgs, hostname, port, isSecure, version)
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
cached = cachedConnections.First();
cachedConnections.Remove(cached);
}
else
{
cached = null;
}
if (cached != null)
connectionCache.Remove(cached);
}
finally { connectionAccessLock.Release(); }
......@@ -71,17 +73,30 @@ namespace Titanium.Web.Proxy.Network
}
if (cached == null)
cached = await CreateClient(sessionArgs, hostname, port, isSecure, version).ConfigureAwait(false);
cached = await CreateClient(sessionArgs, hostname, port, isHttps, version).ConfigureAwait(false);
//just create one more preemptively
if (cachedConnections == null || cachedConnections.Count() < 2)
{
var task = CreateClient(sessionArgs, hostname, port, isHttps, version)
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
}
return cached;
}
private static async Task<TcpConnection> CreateClient(SessionEventArgs sessionArgs, string hostname, int port, bool isSecure, Version version)
internal static string GetConnectionKey(string hostname, int port, bool isHttps, Version version)
{
return string.Format("{0}:{1}:{2}:{3}:{4}", hostname.ToLower(), port, isHttps, version.Major, version.Minor);
}
private static async Task<TcpConnection> CreateClient(SessionEventArgs sessionArgs, string hostname, int port, bool isHttps, Version version)
{
TcpClient client;
Stream stream;
if (isSecure)
if (isHttps)
{
CustomSslStream sslStream = null;
......@@ -148,7 +163,7 @@ namespace Titanium.Web.Proxy.Network
{
HostName = hostname,
port = port,
IsSecure = isSecure,
IsHttps = isHttps,
TcpClient = client,
StreamReader = new CustomBinaryReader(stream),
Stream = stream,
......@@ -157,14 +172,23 @@ namespace Titanium.Web.Proxy.Network
}
internal static async Task ReleaseClient(TcpConnection Connection)
internal static async Task ReleaseClient(TcpConnection connection)
{
Connection.LastAccess = DateTime.Now;
connection.LastAccess = DateTime.Now;
var key = GetConnectionKey(connection.HostName, connection.port, connection.IsHttps, connection.Version);
await connectionAccessLock.WaitAsync();
try
{
connectionCache.Add(Connection);
List<TcpConnection> cachedConnections;
connectionCache.TryGetValue(key, out cachedConnections);
if (cachedConnections != null)
cachedConnections.Add(connection);
else
connectionCache.Add(key, new List<TcpConnection>() { connection });
}
finally { connectionAccessLock.Release(); }
}
......@@ -178,11 +202,12 @@ namespace Titanium.Web.Proxy.Network
var cutOff = DateTime.Now.AddSeconds(-60);
connectionCache
.SelectMany(x => x.Value)
.Where(x => x.LastAccess < cutOff)
.ToList()
.ForEach(x => x.TcpClient.Close());
connectionCache.RemoveAll(x => x.LastAccess < cutOff);
connectionCache.ToList().ForEach(x => x.Value.RemoveAll(y => y.LastAccess < cutOff));
}
finally { connectionAccessLock.Release(); }
......
......@@ -57,11 +57,7 @@ namespace Titanium.Web.Proxy
{
string httpVersion = httpCmdSplit[1].Trim();
if (httpVersion == "http/1.1")
{
version = new Version(1, 1);
}
else
if (httpVersion == "http/1.0")
{
version = new Version(1, 0);
}
......@@ -186,7 +182,7 @@ namespace Titanium.Web.Proxy
}
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool IsHttps)
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool isHttps)
{
TcpConnection connection = null;
string lastRequest = null;
......@@ -229,7 +225,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
}
var httpRemoteUri = new Uri(!IsHttps ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host, httpCmdSplit[1])));
var httpRemoteUri = new Uri(!isHttps ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host, httpCmdSplit[1])));
args.WebSession.Request.RequestUri = httpRemoteUri;
......@@ -271,9 +267,7 @@ namespace Titanium.Web.Proxy
: lastRequest != args.WebSession.Request.RequestUri.Host ? await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
: connection;
lastRequest = string.Concat(args.WebSession.Request.RequestUri.Host,":",
args.WebSession.Request.RequestUri.Port,":",
args.IsHttps,":", version.ToString());
lastRequest = TcpConnectionManager.GetConnectionKey(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version);
args.WebSession.Request.RequestLocked = true;
......@@ -292,13 +286,13 @@ namespace Titanium.Web.Proxy
if (Enable100ContinueBehaviour)
if (args.WebSession.Request.Is100Continue)
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Request.ExpectationFailed)
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
}
......
......@@ -44,19 +44,19 @@ namespace Titanium.Web.Proxy
if (args.WebSession.Response.Is100Continue)
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
"Continue", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
}
else if (args.WebSession.Response.ExpectationFailed)
{
WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417",
"Expectation Failed", args.Client.ClientStreamWriter);
await args.Client.ClientStreamWriter.WriteLineAsync();
}
WriteResponseStatus(args.WebSession.Response.HttpVersion, args.WebSession.Response.ResponseStatusCode,
args.WebSession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter);
await WriteResponseStatus(args.WebSession.Response.HttpVersion, args.WebSession.Response.ResponseStatusCode,
args.WebSession.Response.ResponseStatusDescription, args.Client.ClientStreamWriter);
if (args.WebSession.Response.ResponseBodyRead)
{
......@@ -106,10 +106,10 @@ namespace Titanium.Web.Proxy
}
private static void WriteResponseStatus(Version version, string code, string description,
private static async Task WriteResponseStatus(Version version, string code, string description,
StreamWriter responseWriter)
{
responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description));
await responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description));
}
private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)
......
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