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

Commit 6cb2ed4

Browse files
committed
Add inline comments
1 parent 0381ef5 commit 6cb2ed4

File tree

4 files changed

+52
-57
lines changed

4 files changed

+52
-57
lines changed

Titanium.Web.Proxy/Helpers/NetFramework.cs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace Titanium.Web.Proxy.Helpers
88
{
99
public class NetFrameworkHelper
1010
{
11+
//http://stackoverflow.com/questions/856885/httpwebrequest-to-url-with-dot-at-the-end
1112
public static void URLPeriodFix()
1213
{
1314
MethodInfo getSyntax = typeof(UriParser).GetMethod("GetSyntax", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

Titanium.Web.Proxy/ProxyServer.cs

+6-7
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,15 @@ public ProxyServer()
7474
ServicePointManager.DnsRefreshTimeout = 3 * 60 * 1000;//3 minutes
7575
ServicePointManager.MaxServicePointIdleTime = 3 * 60 * 1000;
7676

77+
//HttpWebRequest certificate validation callback
7778
ServicePointManager.ServerCertificateValidationCallback = delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
7879
{
7980
if (sslPolicyErrors == SslPolicyErrors.None) return true;
8081
else
8182
return false;
8283
};
8384

85+
//Fix a bug in .NET 4.0
8486
NetFrameworkHelper.URLPeriodFix();
8587

8688
}
@@ -107,6 +109,7 @@ public static bool Start()
107109
RootCertificateName = RootCertificateName == null ? "Titanium_Proxy_Test_Root" : RootCertificateName;
108110

109111
bool certTrusted = CertManager.CreateTrustedRootCertificate();
112+
//If certificate was trusted by the machine
110113
if (certTrusted)
111114
{
112115
SystemProxyHelper.EnableProxyHTTPS("localhost", ListeningPort);
@@ -143,18 +146,14 @@ private static void Listen(Object obj)
143146
{
144147
while (ShouldListen)
145148
{
146-
149+
147150
var client = listener.AcceptTcpClient();
148151
Task.Factory.StartNew(() => HandleClient(client));
149-
152+
150153
}
151154
}
152155
catch (ThreadInterruptedException) { }
153-
catch (SocketException)
154-
{
155-
156-
}
157-
156+
catch (SocketException) { }
158157

159158

160159
}

Titanium.Web.Proxy/RequestHandler.cs

+36-33
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ private static void HandleClient(TcpClient Client)
2626
{
2727

2828
string connectionGroup = null;
29-
3029
Stream clientStream = null;
3130
CustomBinaryReader clientStreamReader = null;
3231
StreamWriter connectStreamWriter = null;
3332
string tunnelHostName = null;
3433
int tunnelPort = 0;
34+
3535
try
3636
{
37-
connectionGroup = Dns.GetHostEntry(((IPEndPoint)Client.Client.RemoteEndPoint).Address).HostName;
38-
37+
//Separate HttpWebRequest connection group for each client
38+
connectionGroup = ((IPEndPoint)Client.Client.RemoteEndPoint).Address.ToString();
3939

4040
clientStream = Client.GetStream();
4141

@@ -55,7 +55,7 @@ private static void HandleClient(TcpClient Client)
5555
{
5656
throw new EndOfStreamException();
5757
}
58-
//break up the line into three components
58+
//break up the line into three components (method, remote URL & Http Version)
5959
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
6060

6161
String method = splitBuffer[0];
@@ -73,12 +73,13 @@ private static void HandleClient(TcpClient Client)
7373
RequestVersion = "HTTP/1.0";
7474
}
7575

76+
//Client wants to create a secure tcp tunnel (its a HTTPS request)
7677
if (splitBuffer[0].ToUpper() == "CONNECT")
7778
{
7879
//Browser wants to create a secure tunnel
7980
//instead = we are going to perform a man in the middle "attack"
8081
//the user's browser should warn them of the certification errors,
81-
//so we need to install our root certficate in users machine as Certificate Authority.
82+
//to avoid that we need to install our root certficate in users machine as Certificate Authority.
8283
remoteUri = "https://" + splitBuffer[1];
8384
tunnelHostName = splitBuffer[1].Split(':')[0];
8485
int.TryParse(splitBuffer[1].Split(':')[1], out tunnelPort);
@@ -109,34 +110,39 @@ private static void HandleClient(TcpClient Client)
109110
connectStreamWriter.Flush();
110111

111112

112-
113+
//If port is not 443 its not a HTTP request, so just relay
113114
if (tunnelPort != 443)
114115
{
115-
116-
117116
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream);
118117

119118
if (clientStream != null)
120119
clientStream.Close();
121120

122121
return;
123122
}
123+
124+
//Create the fake certificate signed using our fake certificate authority
124125
Monitor.Enter(certificateAccessLock);
125126
var _certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName);
126127
Monitor.Exit(certificateAccessLock);
127128

128129
SslStream sslStream = null;
130+
//Pinned certificate clients cannot be proxied
131+
//Example dropbox.com uses certificate pinning
132+
//So just relay the request after identifying it by first failure
129133
if (!pinnedCertificateClients.Contains(tunnelHostName) && isSecure)
130134
{
131135
sslStream = new SslStream(clientStream, true);
132136
try
133137
{
138+
//Successfully managed to authenticate the client using the fake certificate
134139
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
135140
}
136141

137142
catch (AuthenticationException ex)
138143
{
139-
144+
//if authentication failed it could be because client uses pinned certificates
145+
//So add the hostname to this list so that next time we can relay without touching it (tunnel the request)
140146
if (pinnedCertificateClients.Contains(tunnelHostName) == false)
141147
{
142148
pinnedCertificateClients.Add(tunnelHostName);
@@ -147,8 +153,7 @@ private static void HandleClient(TcpClient Client)
147153
}
148154
else
149155
{
150-
151-
156+
//Hostname was a previously failed request due to certificate pinning, just relay (tunnel the request)
152157
TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream);
153158

154159
if (clientStream != null)
@@ -175,6 +180,7 @@ private static void HandleClient(TcpClient Client)
175180
securehost = remoteUri;
176181
}
177182

183+
//Now create the request
178184
HandleHttpSessionRequest(Client, httpCmd, connectionGroup, clientStream, tunnelHostName, requestLines, clientStreamReader, securehost);
179185

180186

@@ -203,10 +209,8 @@ private static void HandleClient(TcpClient Client)
203209
finally
204210
{
205211

206-
207212
}
208213

209-
210214
}
211215
private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, string connectionGroup, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, string securehost)
212216
{
@@ -221,6 +225,7 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
221225
args.securehost = securehost;
222226
try
223227
{
228+
//break up the line into three components (method, remote URL & Http Version)
224229
var splitBuffer = httpCmd.Split(spaceSplit, 3);
225230

226231
if (splitBuffer.Length != 3)
@@ -264,10 +269,10 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
264269
var rawHeader = requestLines[i];
265270
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
266271

272+
//if request was upgrade to web-socket protocol then relay the request without proxying
267273
if ((header[0] == "upgrade") && (header[1] == "websocket"))
268274
{
269275

270-
271276
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
272277

273278
if (clientStream != null)
@@ -285,6 +290,7 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
285290
args.ProxyRequest.AllowAutoRedirect = false;
286291
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
287292

293+
//If requested interception
288294
if (BeforeRequest != null)
289295
{
290296
args.RequestHostname = args.ProxyRequest.RequestUri.Host;
@@ -299,6 +305,7 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
299305

300306
BeforeRequest(null, args);
301307
}
308+
302309
string tmpLine;
303310
if (args.CancelRequest)
304311
{
@@ -320,7 +327,7 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
320327
args.ProxyRequest.ConnectionGroupName = connectionGroup;
321328
args.ProxyRequest.AllowWriteStreamBuffering = true;
322329

323-
330+
//If request was modified by user
324331
if (args.RequestWasModified)
325332
{
326333
ASCIIEncoding encoding = new ASCIIEncoding();
@@ -333,14 +340,18 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
333340
}
334341
else
335342
{
343+
//If its a post/put request, then read the client html body and send it to server
336344
if (method.ToUpper() == "POST" || method.ToUpper() == "PUT")
337345
{
338346
args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args);
339347
}
340348
else
341349
{
350+
//otherwise wait for response asynchronously
342351
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
343352

353+
//Now read the next request (if keep-Alive is enabled, otherwise exit thus thread)
354+
//If client is pipeling the request, this will be immediately hit before response for previous request was made
344355
if (args.ProxyRequest.KeepAlive)
345356
{
346357
requestLines = new List<string>();
@@ -357,11 +368,6 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
357368

358369
}
359370

360-
361-
362-
363-
364-
365371
}
366372
catch (IOException)
367373
{
@@ -378,10 +384,6 @@ private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, s
378384
finally
379385
{
380386

381-
382-
383-
384-
385387
}
386388

387389

@@ -453,6 +455,8 @@ private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebReq
453455
case "user-agent":
454456
WebRequest.UserAgent = header[1];
455457
break;
458+
//revisit this, transfer-encoding is not a request header according to spec
459+
//But how to identify if client is sending chunked body for PUT/POST?
456460
case "transfer-encoding":
457461
if (header[1].ToLower() == "chunked")
458462
WebRequest.SendChunked = true;
@@ -468,7 +472,6 @@ private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebReq
468472
if (header.Length >= 2)
469473
WebRequest.Headers.Add(header[0], header[1]);
470474

471-
472475
break;
473476
}
474477

@@ -519,20 +522,16 @@ private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
519522

520523
postStream.Close();
521524
}
522-
catch (IOException ex)
525+
catch (IOException)
523526
{
524527

525-
526528
args.ProxyRequest.KeepAlive = false;
527-
Debug.WriteLine(ex.Message);
528529
return;
529530
}
530-
catch (WebException ex)
531+
catch (WebException)
531532
{
532533

533-
534534
args.ProxyRequest.KeepAlive = false;
535-
Debug.WriteLine(ex.Message);
536535
return;
537536

538537
}
@@ -616,9 +615,11 @@ private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
616615

617616
}
618617
}
619-
618+
//Http request body sent, now wait asynchronously for response
620619
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
621-
620+
621+
//Now read the next request (if keep-Alive is enabled, otherwise exit thus thread)
622+
//If client is pipeling the request, this will be immediately hit before response for previous request was made
622623
if (args.ProxyRequest.KeepAlive)
623624
{
624625
string httpCmd, tmpLine;
@@ -630,6 +631,8 @@ private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
630631
}
631632
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
632633
TcpClient Client = args.Client;
634+
635+
//Http request body sent, now wait for next request
633636
HandleHttpSessionRequest(Client, httpCmd, args.ProxyRequest.ConnectionGroupName, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.securehost);
634637
}
635638
}

0 commit comments

Comments
 (0)