Commit 2b1ad86f authored by titanium007's avatar titanium007

Use Version instead of string object

parent 9cfe6e7e
......@@ -36,7 +36,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Does this session uses SSL
/// </summary>
public bool IsHttps { get; internal set; }
public bool IsHttps => WebSession.Request.RequestUri.Scheme == Uri.UriSchemeHttps;
/// <summary>
/// A web session corresponding to a single request/response sequence
......@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.EventArguments
await this.Client.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false);
}
else if (WebSession.Request.HttpVersion.ToLower().Trim().Equals("http/1.0"))
else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0)
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(requestBodyStream, long.MaxValue).ConfigureAwait(false);
}
WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()).ConfigureAwait(false);
......@@ -123,7 +123,7 @@ namespace Titanium.Web.Proxy.EventArguments
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength).ConfigureAwait(false);
}
else if(WebSession.Response.HttpVersion.ToLower().Trim().Equals("http/1.0"))
else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0)
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue).ConfigureAwait(false);
}
......
......@@ -46,7 +46,7 @@ namespace Titanium.Web.Proxy.Http
{
this.Request.Method,
this.Request.RequestUri.PathAndQuery,
this.Request.HttpVersion
string.Format("HTTP/{0}.{1}",this.Request.HttpVersion.Major, this.Request.HttpVersion.Minor)
}));
foreach (HttpHeader httpHeader in this.Request.RequestHeaders)
......@@ -95,8 +95,18 @@ 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
{
version = new Version(1, 0);
}
this.Response.HttpVersion = httpResult[0].Trim();
this.Response.HttpVersion = version;
this.Response.ResponseStatusCode = httpResult[1].Trim();
this.Response.ResponseStatusDescription = httpResult[2].Trim();
......
......@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Http
{
public string Method { get; set; }
public Uri RequestUri { get; set; }
public string HttpVersion { get; set; }
public Version HttpVersion { get; set; }
internal string Host
{
......
......@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions;
using System;
namespace Titanium.Web.Proxy.Http
{
......@@ -31,7 +32,7 @@ namespace Titanium.Web.Proxy.Http
}
}
internal string HttpVersion { get; set; }
internal Version HttpVersion { get; set; }
internal bool ResponseKeepAlive
{
get
......
......@@ -37,21 +37,31 @@ namespace Titanium.Web.Proxy.Network
internal class TcpConnectionManager
{
static List<TcpConnection> ConnectionCache = new List<TcpConnection>();
static List<TcpConnection> connectionCache = new List<TcpConnection>();
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
internal static async Task<TcpConnection> GetClient(SessionEventArgs sessionArgs, string hostname, int port, bool isSecure, Version version)
{
TcpConnection cached = null;
while (true)
{
lock (ConnectionCache)
await connectionAccessLock.WaitAsync();
try
{
cached = ConnectionCache.FirstOrDefault(x => x.HostName == hostname && x.port == port &&
cached = connectionCache.FirstOrDefault(x => x.HostName == hostname && x.port == port &&
x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version));
//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)
{
var task = CreateClient(sessionArgs, hostname, port, isSecure, version)
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
}
if (cached != null)
ConnectionCache.Remove(cached);
connectionCache.Remove(cached);
}
finally { connectionAccessLock.Release(); }
if (cached != null && !cached.TcpClient.Client.IsConnected())
continue;
......@@ -62,15 +72,7 @@ namespace Titanium.Web.Proxy.Network
if (cached == null)
cached = await CreateClient(sessionArgs, hostname, port, isSecure, version).ConfigureAwait(false);
//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)
{
var task = CreateClient(sessionArgs, hostname, port, isSecure, version)
.ContinueWith(x => { if (x.Status == TaskStatus.RanToCompletion) ReleaseClient(x.Result); });
}
return cached;
}
......@@ -155,27 +157,34 @@ namespace Titanium.Web.Proxy.Network
}
internal static void ReleaseClient(TcpConnection Connection)
internal static async Task ReleaseClient(TcpConnection Connection)
{
Connection.LastAccess = DateTime.Now;
ConnectionCache.Add(Connection);
await connectionAccessLock.WaitAsync();
try
{
connectionCache.Add(Connection);
}
finally { connectionAccessLock.Release(); }
}
internal async static void ClearIdleConnections()
{
while (true)
{
lock (ConnectionCache)
await connectionAccessLock.WaitAsync();
try
{
var cutOff = DateTime.Now.AddSeconds(-60);
ConnectionCache
connectionCache
.Where(x => x.LastAccess < cutOff)
.ToList()
.ForEach(x => x.TcpClient.Close());
ConnectionCache.RemoveAll(x => x.LastAccess < cutOff);
connectionCache.RemoveAll(x => x.LastAccess < cutOff);
}
finally { connectionAccessLock.Release(); }
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false);
}
......
......@@ -52,10 +52,21 @@ namespace Titanium.Web.Proxy
else
httpRemoteUri = new Uri(httpCmdSplit[1]);
string httpVersion = "HTTP/1.1";
Version version = new Version(1, 1);
if (httpCmdSplit.Length == 3)
httpVersion = httpCmdSplit[2];
{
string httpVersion = httpCmdSplit[1].Trim();
if (httpVersion == "http/1.1")
{
version = new Version(1, 1);
}
else
{
version = new Version(1, 0);
}
}
var excluded = endPoint.ExcludedHttpsHostNameRegex != null ? endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false;
......@@ -65,7 +76,7 @@ namespace Titanium.Web.Proxy
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host);
......@@ -101,7 +112,7 @@ namespace Titanium.Web.Proxy
else if (httpVerb.ToUpper() == "CONNECT")
{
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false).ConfigureAwait(false);
......@@ -178,7 +189,7 @@ namespace Titanium.Web.Proxy
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool IsHttps)
{
TcpConnection connection = null;
string lastRequestHostName = null;
string lastRequest = null;
while (true)
{
......@@ -197,10 +208,10 @@ namespace Titanium.Web.Proxy
var httpCmdSplit = httpCmd.Split(Constants.SpaceSplit, 3);
var httpMethod = httpCmdSplit[0];
var httpVersion = httpCmdSplit[2];
var httpVersion = httpCmdSplit[2].ToLower().Trim();
Version version;
if (httpVersion == "HTTP/1.1")
if (httpVersion == "http/1.1")
{
version = new Version(1, 1);
}
......@@ -219,26 +230,18 @@ namespace Titanium.Web.Proxy
}
var httpRemoteUri = new Uri(!IsHttps ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host, httpCmdSplit[1])));
args.IsHttps = IsHttps;
args.WebSession.Request.RequestUri = httpRemoteUri;
args.WebSession.Request.Method = httpMethod;
args.WebSession.Request.HttpVersion = httpVersion;
args.WebSession.Request.HttpVersion = version;
args.Client.ClientStream = clientStream;
args.Client.ClientStreamReader = clientStreamReader;
args.Client.ClientStreamWriter = clientStreamWriter;
if (args.WebSession.Request.UpgradeToWebSocket)
{
await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps).ConfigureAwait(false);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Host;
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
//If requested interception
if (BeforeRequest != null)
......@@ -251,16 +254,26 @@ namespace Titanium.Web.Proxy
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args);
}
await Task.WhenAll(handlerTasks).ConfigureAwait(false);
await Task.WhenAll(handlerTasks).ConfigureAwait(false);
}
if (args.WebSession.Request.UpgradeToWebSocket)
{
await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps).ConfigureAwait(false);
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
return;
}
//construct the web request that we are going to issue on behalf of the client.
connection = connection == null ?
await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
: lastRequestHostName != 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;
lastRequestHostName = args.WebSession.Request.RequestUri.Host;
lastRequest = string.Concat(args.WebSession.Request.RequestUri.Host,":",
args.WebSession.Request.RequestUri.Port,":",
args.IsHttps,":", version.ToString());
args.WebSession.Request.RequestLocked = true;
......@@ -347,12 +360,12 @@ namespace Titanium.Web.Proxy
}
if (connection != null)
TcpConnectionManager.ReleaseClient(connection);
await TcpConnectionManager.ReleaseClient(connection);
}
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, string httpVersion)
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion)
{
await clientStreamWriter.WriteLineAsync(httpVersion + " 200 Connection established").ConfigureAwait(false);
await clientStreamWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2}", httpVersion.Major, httpVersion.Minor,"200 Connection established")).ConfigureAwait(false);
await clientStreamWriter.WriteLineAsync(string.Format("Timestamp: {0}", DateTime.Now)).ConfigureAwait(false);
await clientStreamWriter.WriteLineAsync().ConfigureAwait(false);
await clientStreamWriter.FlushAsync().ConfigureAwait(false);
......
......@@ -80,7 +80,8 @@ namespace Titanium.Web.Proxy
{
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || args.WebSession.Response.HttpVersion.ToLower().Trim() == "http/1.0")
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 ||
(args.WebSession.Response.HttpVersion.Major == 1 && args.WebSession.Response.HttpVersion.Minor == 0))
await WriteResponseBody(args.WebSession.ServerConnection.StreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
}
......@@ -105,10 +106,10 @@ namespace Titanium.Web.Proxy
}
private static void WriteResponseStatus(string version, string code, string description,
private static void WriteResponseStatus(Version version, string code, string description,
StreamWriter responseWriter)
{
responseWriter.WriteLineAsync(string.Format("{0} {1} {2}", version, code, description));
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