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

Commit 2b1ad86

Browse files
committed
Use Version instead of string object
1 parent 9cfe6e7 commit 2b1ad86

File tree

7 files changed

+88
-54
lines changed

7 files changed

+88
-54
lines changed

Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ internal SessionEventArgs()
3636
/// <summary>
3737
/// Does this session uses SSL
3838
/// </summary>
39-
public bool IsHttps { get; internal set; }
39+
public bool IsHttps => WebSession.Request.RequestUri.Scheme == Uri.UriSchemeHttps;
4040

4141
/// <summary>
4242
/// A web session corresponding to a single request/response sequence
@@ -87,7 +87,7 @@ private async Task ReadRequestBody()
8787
await this.Client.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength).ConfigureAwait(false);
8888

8989
}
90-
else if (WebSession.Request.HttpVersion.ToLower().Trim().Equals("http/1.0"))
90+
else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0)
9191
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(requestBodyStream, long.MaxValue).ConfigureAwait(false);
9292
}
9393
WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()).ConfigureAwait(false);
@@ -123,7 +123,7 @@ private async Task ReadResponseBody()
123123
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength).ConfigureAwait(false);
124124

125125
}
126-
else if(WebSession.Response.HttpVersion.ToLower().Trim().Equals("http/1.0"))
126+
else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0)
127127
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue).ConfigureAwait(false);
128128
}
129129

Titanium.Web.Proxy/Http/HttpWebClient.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ internal async Task SendRequest()
4646
{
4747
this.Request.Method,
4848
this.Request.RequestUri.PathAndQuery,
49-
this.Request.HttpVersion
49+
string.Format("HTTP/{0}.{1}",this.Request.HttpVersion.Major, this.Request.HttpVersion.Minor)
5050
}));
5151

5252
foreach (HttpHeader httpHeader in this.Request.RequestHeaders)
@@ -95,8 +95,18 @@ internal async Task ReceiveResponse()
9595
{
9696
await ServerConnection.StreamReader.ReadLineAsync().ConfigureAwait(false);
9797
}
98+
var httpVersion = httpResult[0].Trim().ToLower();
99+
Version version;
100+
if (httpVersion == "http/1.1")
101+
{
102+
version = new Version(1, 1);
103+
}
104+
else
105+
{
106+
version = new Version(1, 0);
107+
}
98108

99-
this.Response.HttpVersion = httpResult[0].Trim();
109+
this.Response.HttpVersion = version;
100110
this.Response.ResponseStatusCode = httpResult[1].Trim();
101111
this.Response.ResponseStatusDescription = httpResult[2].Trim();
102112

Titanium.Web.Proxy/Http/Request.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class Request
1111
{
1212
public string Method { get; set; }
1313
public Uri RequestUri { get; set; }
14-
public string HttpVersion { get; set; }
14+
public Version HttpVersion { get; set; }
1515

1616
internal string Host
1717
{

Titanium.Web.Proxy/Http/Response.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using Titanium.Web.Proxy.Models;
66
using Titanium.Web.Proxy.Extensions;
7+
using System;
78

89
namespace Titanium.Web.Proxy.Http
910
{
@@ -31,7 +32,7 @@ internal string ContentEncoding
3132
}
3233
}
3334

34-
internal string HttpVersion { get; set; }
35+
internal Version HttpVersion { get; set; }
3536
internal bool ResponseKeepAlive
3637
{
3738
get

Titanium.Web.Proxy/Network/TcpConnectionManager.cs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,31 @@ internal TcpConnection()
3737

3838
internal class TcpConnectionManager
3939
{
40-
static List<TcpConnection> ConnectionCache = new List<TcpConnection>();
41-
40+
static List<TcpConnection> connectionCache = new List<TcpConnection>();
41+
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
4242
internal static async Task<TcpConnection> GetClient(SessionEventArgs sessionArgs, string hostname, int port, bool isSecure, Version version)
4343
{
4444
TcpConnection cached = null;
4545
while (true)
4646
{
47-
lock (ConnectionCache)
47+
await connectionAccessLock.WaitAsync();
48+
try
4849
{
49-
cached = ConnectionCache.FirstOrDefault(x => x.HostName == hostname && x.port == port &&
50+
cached = connectionCache.FirstOrDefault(x => x.HostName == hostname && x.port == port &&
5051
x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version));
5152

53+
//just create one more preemptively
54+
if (connectionCache.Where(x => x.HostName == hostname && x.port == port &&
55+
x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version)).Count() < 2)
56+
{
57+
var task = CreateClient(sessionArgs, hostname, port, isSecure, version)
58+
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
59+
}
60+
5261
if (cached != null)
53-
ConnectionCache.Remove(cached);
62+
connectionCache.Remove(cached);
5463
}
64+
finally { connectionAccessLock.Release(); }
5565

5666
if (cached != null && !cached.TcpClient.Client.IsConnected())
5767
continue;
@@ -62,15 +72,7 @@ internal static async Task<TcpConnection> GetClient(SessionEventArgs sessionArgs
6272

6373
if (cached == null)
6474
cached = await CreateClient(sessionArgs, hostname, port, isSecure, version).ConfigureAwait(false);
65-
66-
//just create one more preemptively
67-
if (ConnectionCache.Where(x => x.HostName == hostname && x.port == port &&
68-
x.IsSecure == isSecure && x.TcpClient.Connected && x.Version.Equals(version)).Count() < 2)
69-
{
70-
var task = CreateClient(sessionArgs, hostname, port, isSecure, version)
71-
.ContinueWith(x => { if (x.Status == TaskStatus.RanToCompletion) ReleaseClient(x.Result); });
72-
}
73-
75+
7476
return cached;
7577
}
7678

@@ -155,27 +157,34 @@ private static async Task<TcpConnection> CreateClient(SessionEventArgs sessionAr
155157
}
156158

157159

158-
internal static void ReleaseClient(TcpConnection Connection)
160+
internal static async Task ReleaseClient(TcpConnection Connection)
159161
{
160162
Connection.LastAccess = DateTime.Now;
161-
ConnectionCache.Add(Connection);
163+
await connectionAccessLock.WaitAsync();
164+
try
165+
{
166+
connectionCache.Add(Connection);
167+
}
168+
finally { connectionAccessLock.Release(); }
162169
}
163170

164171
internal async static void ClearIdleConnections()
165172
{
166173
while (true)
167174
{
168-
lock (ConnectionCache)
175+
await connectionAccessLock.WaitAsync();
176+
try
169177
{
170178
var cutOff = DateTime.Now.AddSeconds(-60);
171179

172-
ConnectionCache
180+
connectionCache
173181
.Where(x => x.LastAccess < cutOff)
174182
.ToList()
175183
.ForEach(x => x.TcpClient.Close());
176184

177-
ConnectionCache.RemoveAll(x => x.LastAccess < cutOff);
185+
connectionCache.RemoveAll(x => x.LastAccess < cutOff);
178186
}
187+
finally { connectionAccessLock.Release(); }
179188

180189
await Task.Delay(1000 * 60 * 3).ConfigureAwait(false);
181190
}

Titanium.Web.Proxy/RequestHandler.cs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,21 @@ private static async void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient
5252
else
5353
httpRemoteUri = new Uri(httpCmdSplit[1]);
5454

55-
string httpVersion = "HTTP/1.1";
56-
55+
Version version = new Version(1, 1);
5756
if (httpCmdSplit.Length == 3)
58-
httpVersion = httpCmdSplit[2];
57+
{
58+
string httpVersion = httpCmdSplit[1].Trim();
59+
60+
if (httpVersion == "http/1.1")
61+
{
62+
version = new Version(1, 1);
63+
}
64+
else
65+
{
66+
version = new Version(1, 0);
67+
}
68+
69+
}
5970

6071
var excluded = endPoint.ExcludedHttpsHostNameRegex != null ? endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false;
6172

@@ -65,7 +76,7 @@ private static async void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient
6576
httpRemoteUri = new Uri("https://" + httpCmdSplit[1]);
6677
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
6778

68-
await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
79+
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
6980

7081
var certificate = await CertManager.CreateCertificate(httpRemoteUri.Host);
7182

@@ -101,7 +112,7 @@ await sslStream.AuthenticateAsServerAsync(certificate, false,
101112
else if (httpVerb.ToUpper() == "CONNECT")
102113
{
103114
await clientStreamReader.ReadAllLinesAsync().ConfigureAwait(false);
104-
await WriteConnectResponse(clientStreamWriter, httpVersion).ConfigureAwait(false);
115+
await WriteConnectResponse(clientStreamWriter, version).ConfigureAwait(false);
105116

106117
await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
107118
false).ConfigureAwait(false);
@@ -178,7 +189,7 @@ private static async Task HandleHttpSessionRequest(TcpClient client, string http
178189
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool IsHttps)
179190
{
180191
TcpConnection connection = null;
181-
string lastRequestHostName = null;
192+
string lastRequest = null;
182193

183194
while (true)
184195
{
@@ -197,10 +208,10 @@ private static async Task HandleHttpSessionRequest(TcpClient client, string http
197208
var httpCmdSplit = httpCmd.Split(Constants.SpaceSplit, 3);
198209

199210
var httpMethod = httpCmdSplit[0];
200-
var httpVersion = httpCmdSplit[2];
211+
var httpVersion = httpCmdSplit[2].ToLower().Trim();
201212

202213
Version version;
203-
if (httpVersion == "HTTP/1.1")
214+
if (httpVersion == "http/1.1")
204215
{
205216
version = new Version(1, 1);
206217
}
@@ -219,26 +230,18 @@ private static async Task HandleHttpSessionRequest(TcpClient client, string http
219230
}
220231

221232
var httpRemoteUri = new Uri(!IsHttps ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host, httpCmdSplit[1])));
222-
args.IsHttps = IsHttps;
223233

224234
args.WebSession.Request.RequestUri = httpRemoteUri;
225235

226236
args.WebSession.Request.Method = httpMethod;
227-
args.WebSession.Request.HttpVersion = httpVersion;
237+
args.WebSession.Request.HttpVersion = version;
228238
args.Client.ClientStream = clientStream;
229239
args.Client.ClientStreamReader = clientStreamReader;
230240
args.Client.ClientStreamWriter = clientStreamWriter;
231241

232-
if (args.WebSession.Request.UpgradeToWebSocket)
233-
{
234-
await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
235-
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps).ConfigureAwait(false);
236-
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
237-
return;
238-
}
239-
242+
240243
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
241-
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Host;
244+
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
242245

243246
//If requested interception
244247
if (BeforeRequest != null)
@@ -251,16 +254,26 @@ await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHe
251254
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(null, args);
252255
}
253256

254-
await Task.WhenAll(handlerTasks).ConfigureAwait(false);
257+
await Task.WhenAll(handlerTasks).ConfigureAwait(false);
258+
}
259+
260+
if (args.WebSession.Request.UpgradeToWebSocket)
261+
{
262+
await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
263+
httpRemoteUri.Host, httpRemoteUri.Port, args.IsHttps).ConfigureAwait(false);
264+
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
265+
return;
255266
}
256267

257268
//construct the web request that we are going to issue on behalf of the client.
258269
connection = connection == null ?
259270
await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version).ConfigureAwait(false)
260-
: 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)
271+
: 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)
261272
: connection;
262273

263-
lastRequestHostName = args.WebSession.Request.RequestUri.Host;
274+
lastRequest = string.Concat(args.WebSession.Request.RequestUri.Host,":",
275+
args.WebSession.Request.RequestUri.Port,":",
276+
args.IsHttps,":", version.ToString());
264277

265278
args.WebSession.Request.RequestLocked = true;
266279

@@ -347,12 +360,12 @@ await TcpConnectionManager.GetClient(args, args.WebSession.Request.RequestUri.Ho
347360
}
348361

349362
if (connection != null)
350-
TcpConnectionManager.ReleaseClient(connection);
363+
await TcpConnectionManager.ReleaseClient(connection);
351364
}
352365

353-
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, string httpVersion)
366+
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion)
354367
{
355-
await clientStreamWriter.WriteLineAsync(httpVersion + " 200 Connection established").ConfigureAwait(false);
368+
await clientStreamWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2}", httpVersion.Major, httpVersion.Minor,"200 Connection established")).ConfigureAwait(false);
356369
await clientStreamWriter.WriteLineAsync(string.Format("Timestamp: {0}", DateTime.Now)).ConfigureAwait(false);
357370
await clientStreamWriter.WriteLineAsync().ConfigureAwait(false);
358371
await clientStreamWriter.FlushAsync().ConfigureAwait(false);

Titanium.Web.Proxy/ResponseHandler.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ public static async Task HandleHttpSessionResponse(SessionEventArgs args)
8080
{
8181
await WriteResponseHeaders(args.Client.ClientStreamWriter, args.WebSession.Response.ResponseHeaders);
8282

83-
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || args.WebSession.Response.HttpVersion.ToLower().Trim() == "http/1.0")
83+
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 ||
84+
(args.WebSession.Response.HttpVersion.Major == 1 && args.WebSession.Response.HttpVersion.Minor == 0))
8485
await WriteResponseBody(args.WebSession.ServerConnection.StreamReader, args.Client.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength).ConfigureAwait(false);
8586
}
8687

@@ -105,10 +106,10 @@ private static async Task<byte[]> GetCompressedResponseBody(string encodingType,
105106
}
106107

107108

108-
private static void WriteResponseStatus(string version, string code, string description,
109+
private static void WriteResponseStatus(Version version, string code, string description,
109110
StreamWriter responseWriter)
110111
{
111-
responseWriter.WriteLineAsync(string.Format("{0} {1} {2}", version, code, description));
112+
responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description));
112113
}
113114

114115
private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)

0 commit comments

Comments
 (0)