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

Commit a988e27

Browse files
committed
Merge branch 'develop' into beta
2 parents f281748 + 1ce0f7f commit a988e27

File tree

12 files changed

+546
-519
lines changed

12 files changed

+546
-519
lines changed

Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,18 @@ public ProxyTestController()
3232
proxyServer = new ProxyServer();
3333

3434
//generate root certificate without storing it in file system
35-
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
3635
//proxyServer.CertificateManager.CreateTrustedRootCertificate(false);
3736
//proxyServer.CertificateManager.TrustRootCertificate();
3837

3938
proxyServer.ExceptionFunc = exception => Console.WriteLine(exception.Message);
40-
proxyServer.TrustRootCertificate = true;
4139
proxyServer.ForwardToUpstreamGateway = true;
4240

4341
//optionally set the Certificate Engine
4442
//Under Mono or Non-Windows runtimes only BouncyCastle will be supported
45-
//proxyServer.CertificateEngine = Network.CertificateEngine.DefaultWindows;
43+
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
4644

4745
//optionally set the Root Certificate
48-
//proxyServer.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
46+
//proxyServer.CertificateManager.RootCertificate = new X509Certificate2("myCert.pfx", string.Empty, X509KeyStorageFlags.Exportable);
4947
}
5048

5149
public void StartProxy()
@@ -68,9 +66,7 @@ public void StartProxy()
6866
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
6967
};
7068

71-
//Exclude Https addresses you don't want to proxy
72-
//Useful for clients that use certificate pinning
73-
//for example google.com and dropbox.com
69+
//Fired when a CONNECT request is received
7470
explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect;
7571

7672

@@ -130,10 +126,11 @@ public void Stop()
130126

131127
private async Task<bool> OnBeforeTunnelConnect(string hostname)
132128
{
133-
if (hostname.Contains("amazon.com") || hostname.Contains("paypal.com"))
129+
if (hostname.Contains("dropbox.com"))
134130
{
135-
//exclude bing.com and google.com from being decrypted
136-
//instead it will be relayed via a secure TCP tunnel
131+
//Exclude Https addresses you don't want to proxy
132+
//Useful for clients that use certificate pinning
133+
//for example dropbox.com
137134
return await Task.FromResult(true);
138135
}
139136
else
@@ -183,7 +180,7 @@ private async Task OnRequest(object sender, SessionEventArgs e)
183180
//Filter URL
184181
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("yahoo.com"))
185182
{
186-
await e.Ok("<!DOCTYPE html>" +
183+
e.Ok("<!DOCTYPE html>" +
187184
"<html><body><h1>" +
188185
"Website Blocked" +
189186
"</h1>" +
@@ -195,7 +192,7 @@ await e.Ok("<!DOCTYPE html>" +
195192
////Redirect example
196193
//if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
197194
//{
198-
// await e.Redirect("https://www.paypal.com");
195+
// e.Redirect("https://www.paypal.com");
199196
//}
200197
}
201198

Examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,25 @@ public int ServerConnectionCount
6262
public MainWindow()
6363
{
6464
proxyServer = new ProxyServer();
65-
//proxyServer.CertificateEngine = CertificateEngine.DefaultWindows;
65+
//proxyServer.CertificateManager.CertificateEngine = CertificateEngine.DefaultWindows;
6666

6767
////Set a password for the .pfx file
68-
//proxyServer.PfxPassword = "PfxPassword";
68+
//proxyServer.CertificateManager.PfxPassword = "PfxPassword";
6969

7070
////Set Name(path) of the Root certificate file
71-
//proxyServer.PfxFilePath = @"C:\NameFolder\rootCert.pfx";
71+
//proxyServer.CertificateManager.PfxFilePath = @"C:\NameFolder\rootCert.pfx";
7272

7373
////do you want Replace an existing Root certificate file(.pfx) if password is incorrect(RootCertificate=null)? yes====>true
74-
//proxyServer.OverwritePfxFile = true;
74+
//proxyServer.CertificateManager.OverwritePfxFile = true;
7575

7676
////save all fake certificates in folder "crts"(will be created in proxy dll directory)
7777
////if create new Root certificate file(.pfx) ====> delete folder "crts"
78-
//proxyServer.SaveFakeCertificates = true;
79-
80-
//Trust Root Certificate
81-
proxyServer.TrustRootCertificate = true;
82-
proxyServer.TrustRootCertificateAsAdministrator = true;
78+
//proxyServer.CertificateManager.SaveFakeCertificates = true;
8379

8480
proxyServer.ForwardToUpstreamGateway = true;
8581

8682
////if you need Load or Create Certificate now. ////// "true" if you need Enable===> Trust the RootCertificate used by this proxy server
87-
//proxyServer.EnsureRootCertificate(true);
83+
//proxyServer.CertificateManager.EnsureRootCertificate(true);
8884

8985
////or load directly certificate(As Administrator if need this)
9086
////and At the same time chose path and password

README.md

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ Setup HTTP proxy:
5252
var proxyServer = new ProxyServer();
5353

5454
//locally trust root certificate used by this proxy
55-
proxyServer.TrustRootCertificate = true;
55+
proxyServer.CertificateManager.TrustRootCertificate = true;
5656

5757
//optionally set the Certificate Engine
5858
//Under Mono only BouncyCastle will be supported
59-
//proxyServer.CertificateEngine = Network.CertificateEngine.BouncyCastle;
59+
//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;
6060
6161
proxyServer.BeforeRequest += OnRequest;
6262
proxyServer.BeforeResponse += OnResponse;
@@ -66,17 +66,17 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
6666

6767
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
6868
{
69-
//Exclude HTTPS addresses you don't want to proxy
70-
//Useful for clients that use certificate pinning
71-
//for example dropbox.com
72-
// ExcludedHttpsHostNameRegex = new List<string>() { "google.com", "dropbox.com" }
69+
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
7370
74-
//Use self-issued generic certificate on all HTTPS requests
75-
//Optimizes performance by not creating a certificate for each HTTPS-enabled domain
71+
//Use self-issued generic certificate on all https requests
72+
//Optimizes performance by not creating a certificate for each https-enabled domain
7673
//Useful when certificate trust is not required by proxy clients
77-
// GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
74+
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
7875
};
7976

77+
//Fired when a CONNECT request is received
78+
explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect;
79+
8080
//An explicit endpoint is where the client knows about the existence of a proxy
8181
//So client sends request in a proxy friendly manner
8282
proxyServer.AddEndPoint(explicitEndPoint);
@@ -109,6 +109,7 @@ proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
109109
Console.Read();
110110

111111
//Unsubscribe & Quit
112+
explicitEndPoint.BeforeTunnelConnect -= OnBeforeTunnelConnect;
112113
proxyServer.BeforeRequest -= OnRequest;
113114
proxyServer.BeforeResponse -= OnResponse;
114115
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
@@ -125,6 +126,21 @@ Sample request and response event handlers
125126
private IDictionary<Guid, string> requestBodyHistory
126127
= new ConcurrentDictionary<Guid, string>();
127128

129+
private async Task<bool> OnBeforeTunnelConnect(string hostname)
130+
{
131+
if (hostname.Contains("dropbox.com"))
132+
{
133+
//Exclude Https addresses you don't want to proxy
134+
//Useful for clients that use certificate pinning
135+
//for example dropbox.com
136+
return await Task.FromResult(true);
137+
}
138+
else
139+
{
140+
return await Task.FromResult(false);
141+
}
142+
}
143+
128144
public async Task OnRequest(object sender, SessionEventArgs e)
129145
{
130146
Console.WriteLine(e.WebSession.Request.Url);
@@ -152,7 +168,7 @@ public async Task OnRequest(object sender, SessionEventArgs e)
152168
//Filter URL
153169
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))
154170
{
155-
await e.Ok("<!DOCTYPE html>" +
171+
e.Ok("<!DOCTYPE html>" +
156172
"<html><body><h1>" +
157173
"Website Blocked" +
158174
"</h1>" +
@@ -163,7 +179,7 @@ public async Task OnRequest(object sender, SessionEventArgs e)
163179
//Redirect example
164180
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org"))
165181
{
166-
await e.Redirect("https://www.paypal.com");
182+
e.Redirect("https://www.paypal.com");
167183
}
168184
}
169185

Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public class ProxyTestController
5151
public ProxyTestController()
5252
{
5353
proxyServer = new ProxyServer();
54-
proxyServer.TrustRootCertificate = true;
5554
}
5655

5756
public void StartProxy(int proxyPort)

Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,53 @@ private static readonly string[] hostNames
1515
private readonly Random random = new Random();
1616

1717
[TestMethod]
18-
public async Task Simple_Create_Certificate_Stress_Test()
18+
public async Task Simple_Create_Certificate_Test()
1919
{
2020
var tasks = new List<Task>();
2121

2222
var mgr = new CertificateManager(new Lazy<Action<Exception>>(() => (e => { })).Value);
2323

24-
mgr.ClearIdleCertificates(1);
24+
mgr.ClearIdleCertificates();
2525

26-
for (int i = 0; i < 1000; i++)
26+
foreach (string host in hostNames)
2727
{
28-
foreach (string host in hostNames)
28+
tasks.Add(Task.Run(async () =>
2929
{
30-
tasks.Add(Task.Run(async () =>
31-
{
32-
await Task.Delay(random.Next(0, 10) * 1000);
3330

34-
//get the connection
35-
var certificate = mgr.CreateCertificate(host, false);
31+
//get the connection
32+
var certificate = await mgr.CreateCertificateAsync(host);
3633

37-
Assert.IsNotNull(certificate);
38-
}));
39-
}
34+
Assert.IsNotNull(certificate);
35+
}));
36+
}
37+
38+
await Task.WhenAll(tasks.ToArray());
39+
40+
mgr.StopClearIdleCertificates();
41+
}
42+
43+
//uncomment this to compare WinCert maker performance with BC (BC takes more time for same test above)
44+
//cannot run this test in build server since trusting the certificate won't happen successfully
45+
//[TestMethod]
46+
public async Task Simple_Create_Win_Certificate_Test()
47+
{
48+
var tasks = new List<Task>();
49+
50+
var mgr = new CertificateManager(new Lazy<Action<Exception>>(() => (e => { })).Value);
51+
mgr.CreateRootCertificate(true);
52+
mgr.TrustRootCertificate();
53+
mgr.ClearIdleCertificates();
54+
mgr.CertificateEngine = CertificateEngine.DefaultWindows;
55+
56+
foreach (string host in hostNames)
57+
{
58+
tasks.Add(Task.Run(async () =>
59+
{
60+
//get the connection
61+
var certificate = await mgr.CreateCertificateAsync(host);
62+
63+
Assert.IsNotNull(certificate);
64+
}));
4065
}
4166

4267
await Task.WhenAll(tasks.ToArray());

Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ private async Task<byte[]> GetDecompressedBodyAsync(string encodingType, byte[]
531531
/// </summary>
532532
/// <param name="html"></param>
533533
/// <param name="headers"></param>
534-
public async Task Ok(string html, Dictionary<string, HttpHeader> headers = null)
534+
public void Ok(string html, Dictionary<string, HttpHeader> headers = null)
535535
{
536536
var response = new OkResponse();
537537
if (headers != null)
@@ -542,7 +542,7 @@ public async Task Ok(string html, Dictionary<string, HttpHeader> headers = null)
542542
response.HttpVersion = WebSession.Request.HttpVersion;
543543
response.Body = response.Encoding.GetBytes(html ?? string.Empty);
544544

545-
await Respond(response);
545+
Respond(response);
546546
}
547547

548548
/// <summary>
@@ -552,14 +552,14 @@ public async Task Ok(string html, Dictionary<string, HttpHeader> headers = null)
552552
/// </summary>
553553
/// <param name="result"></param>
554554
/// <param name="headers"></param>
555-
public async Task Ok(byte[] result, Dictionary<string, HttpHeader> headers = null)
555+
public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null)
556556
{
557557
var response = new OkResponse();
558558
response.Headers.AddHeaders(headers);
559559
response.HttpVersion = WebSession.Request.HttpVersion;
560560
response.Body = result;
561561

562-
await Respond(response);
562+
Respond(response);
563563
}
564564

565565
/// <summary>
@@ -572,14 +572,14 @@ public async Task Ok(byte[] result, Dictionary<string, HttpHeader> headers = nul
572572
/// <param name="status"></param>
573573
/// <param name="headers"></param>
574574
/// <returns></returns>
575-
public async Task GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null)
575+
public void GenericResponse(string html, HttpStatusCode status, Dictionary<string, HttpHeader> headers = null)
576576
{
577577
var response = new GenericResponse(status);
578578
response.HttpVersion = WebSession.Request.HttpVersion;
579579
response.Headers.AddHeaders(headers);
580580
response.Body = response.Encoding.GetBytes(html ?? string.Empty);
581581

582-
await Respond(response);
582+
Respond(response);
583583
}
584584

585585
/// <summary>
@@ -592,33 +592,33 @@ public async Task GenericResponse(string html, HttpStatusCode status, Dictionary
592592
/// <param name="status"></param>
593593
/// <param name="headers"></param>
594594
/// <returns></returns>
595-
public async Task GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers)
595+
public void GenericResponse(byte[] result, HttpStatusCode status, Dictionary<string, HttpHeader> headers)
596596
{
597597
var response = new GenericResponse(status);
598598
response.HttpVersion = WebSession.Request.HttpVersion;
599599
response.Headers.AddHeaders(headers);
600600
response.Body = result;
601601

602-
await Respond(response);
602+
Respond(response);
603603
}
604604

605605
/// <summary>
606606
/// Redirect to URL.
607607
/// </summary>
608608
/// <param name="url"></param>
609609
/// <returns></returns>
610-
public async Task Redirect(string url)
610+
public void Redirect(string url)
611611
{
612612
var response = new RedirectResponse();
613613
response.HttpVersion = WebSession.Request.HttpVersion;
614614
response.Headers.AddHeader(KnownHeaders.Location, url);
615615
response.Body = emptyData;
616616

617-
await Respond(response);
617+
Respond(response);
618618
}
619619

620620
/// a generic responder method
621-
public async Task Respond(Response response)
621+
public void Respond(Response response)
622622
{
623623
if (WebSession.Request.RequestLocked)
624624
{

0 commit comments

Comments
 (0)