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