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

Commit 1651c92

Browse files
committed
Merge branch 'develop' into beta
2 parents 4477f6d + f9c7ba4 commit 1651c92

File tree

8 files changed

+266
-286
lines changed

8 files changed

+266
-286
lines changed

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

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
1414
public class ProxyTestController
1515
{
1616
private readonly ProxyServer proxyServer;
17-
17+
private ExplicitProxyEndPoint explicitEndPoint;
1818

1919
//keep track of request headers
2020
private readonly IDictionary<Guid, HeaderCollection> requestHeaderHistory = new ConcurrentDictionary<Guid, HeaderCollection>();
@@ -52,38 +52,31 @@ public void StartProxy()
5252
{
5353
proxyServer.BeforeRequest += OnRequest;
5454
proxyServer.BeforeResponse += OnResponse;
55-
proxyServer.TunnelConnectRequest += OnTunnelConnectRequest;
56-
proxyServer.TunnelConnectResponse += OnTunnelConnectResponse;
55+
5756
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
5857
proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
5958

6059
//proxyServer.EnableWinAuth = true;
6160

62-
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
61+
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
6362
{
64-
//Exclude Https addresses you don't want to proxy
65-
//Useful for clients that use certificate pinning
66-
//for example google.com and dropbox.com
67-
ExcludedHttpsHostNameRegex = new List<string>
68-
{
69-
"dropbox.com"
70-
},
71-
72-
//Include Https addresses you want to proxy (others will be excluded)
73-
//for example github.com
74-
//IncludedHttpsHostNameRegex = new List<string>
75-
//{
76-
// "github.com"
77-
//},
78-
79-
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
80-
81-
//Use self-issued generic certificate on all https requests
82-
//Optimizes performance by not creating a certificate for each https-enabled domain
83-
//Useful when certificate trust is not required by proxy clients
84-
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
63+
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
64+
65+
//Use self-issued generic certificate on all https requests
66+
//Optimizes performance by not creating a certificate for each https-enabled domain
67+
//Useful when certificate trust is not required by proxy clients
68+
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
8569
};
8670

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
74+
explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect;
75+
76+
77+
explicitEndPoint.TunnelConnectRequest += OnTunnelConnectRequest;
78+
explicitEndPoint.TunnelConnectResponse += OnTunnelConnectResponse;
79+
8780
//An explicit endpoint is where the client knows about the existence of a proxy
8881
//So client sends request in a proxy friendly manner
8982
proxyServer.AddEndPoint(explicitEndPoint);
@@ -120,8 +113,10 @@ public void StartProxy()
120113

121114
public void Stop()
122115
{
123-
proxyServer.TunnelConnectRequest -= OnTunnelConnectRequest;
124-
proxyServer.TunnelConnectResponse -= OnTunnelConnectResponse;
116+
explicitEndPoint.BeforeTunnelConnect -= OnBeforeTunnelConnect;
117+
explicitEndPoint.TunnelConnectRequest -= OnTunnelConnectRequest;
118+
explicitEndPoint.TunnelConnectResponse -= OnTunnelConnectResponse;
119+
125120
proxyServer.BeforeRequest -= OnRequest;
126121
proxyServer.BeforeResponse -= OnResponse;
127122
proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;
@@ -133,6 +128,20 @@ public void Stop()
133128
//proxyServer.CertificateManager.RemoveTrustedRootCertificates();
134129
}
135130

131+
private async Task<bool> OnBeforeTunnelConnect(string hostname)
132+
{
133+
if (hostname.Contains("amazon.com") || hostname.Contains("paypal.com"))
134+
{
135+
//exclude bing.com and google.com from being decrypted
136+
//instead it will be relayed via a secure TCP tunnel
137+
return await Task.FromResult(true);
138+
}
139+
else
140+
{
141+
return await Task.FromResult(false);
142+
}
143+
}
144+
136145
private async Task OnTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
137146
{
138147
Console.WriteLine("Tunnel to: " + e.WebSession.Request.Host);
@@ -172,7 +181,7 @@ private async Task OnRequest(object sender, SessionEventArgs e)
172181

173182
//To cancel a request with a custom HTML content
174183
//Filter URL
175-
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("google.com"))
184+
if (e.WebSession.Request.RequestUri.AbsoluteUri.Contains("yahoo.com"))
176185
{
177186
await e.Ok("<!DOCTYPE html>" +
178187
"<html><body><h1>" +

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ public MainWindow()
109109

110110
proxyServer.BeforeRequest += ProxyServer_BeforeRequest;
111111
proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
112-
proxyServer.TunnelConnectRequest += ProxyServer_TunnelConnectRequest;
113-
proxyServer.TunnelConnectResponse += ProxyServer_TunnelConnectResponse;
112+
explicitEndPoint.TunnelConnectRequest += ProxyServer_TunnelConnectRequest;
113+
explicitEndPoint.TunnelConnectResponse += ProxyServer_TunnelConnectResponse;
114114
proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); };
115115
proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); };
116116
proxyServer.Start();

Titanium.Web.Proxy/Helpers/Firefox.cs

Lines changed: 0 additions & 52 deletions
This file was deleted.

Titanium.Web.Proxy/Helpers/HttpHelper.cs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System;
1+
using StreamExtended.Network;
2+
using System;
23
using System.Text;
4+
using System.Threading.Tasks;
35
using Titanium.Web.Proxy.Extensions;
46
using Titanium.Web.Proxy.Http;
57
using Titanium.Web.Proxy.Shared;
@@ -113,5 +115,45 @@ internal static string GetWildCardDomainName(string hostname)
113115
//return as it is
114116
return hostname;
115117
}
118+
119+
/// <summary>
120+
/// Determines whether is connect method.
121+
/// </summary>
122+
/// <param name="clientStream">The client stream.</param>
123+
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
124+
internal static async Task<int> IsConnectMethod(CustomBufferedStream clientStream)
125+
{
126+
bool isConnect = true;
127+
int legthToCheck = 10;
128+
for (int i = 0; i < legthToCheck; i++)
129+
{
130+
int b = await clientStream.PeekByteAsync(i);
131+
if (b == -1)
132+
{
133+
return -1;
134+
}
135+
136+
if (b == ' ' && i > 2)
137+
{
138+
// at least 3 letters and a space
139+
return isConnect ? 1 : 0;
140+
}
141+
142+
char ch = (char)b;
143+
if (!char.IsLetter(ch))
144+
{
145+
// non letter or too short
146+
return -1;
147+
}
148+
149+
if (i > 6 || ch != "CONNECT"[i])
150+
{
151+
isConnect = false;
152+
}
153+
}
154+
155+
// only letters
156+
return isConnect ? 1 : 0;
157+
}
116158
}
117159
}

Titanium.Web.Proxy/Models/EndPoint.cs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
using System.Net.Sockets;
66
using System.Security.Cryptography.X509Certificates;
77
using System.Text.RegularExpressions;
8+
using System.Threading.Tasks;
9+
using Titanium.Web.Proxy.EventArguments;
10+
using Titanium.Web.Proxy.Extensions;
811

912
namespace Titanium.Web.Proxy.Models
1013
{
@@ -67,9 +70,15 @@ public class ExplicitProxyEndPoint : ProxyEndPoint
6770

6871
internal bool IsSystemHttpsProxy { get; set; }
6972

73+
/// <summary>
74+
/// Generic certificate to use for SSL decryption.
75+
/// </summary>
76+
public X509Certificate2 GenericCertificate { get; set; }
77+
7078
/// <summary>
7179
/// List of host names to exclude using Regular Expressions.
7280
/// </summary>
81+
[Obsolete("ExcludedHttpsHostNameRegex is deprecated, please use BeforeTunnelConnect event instead.")]
7382
public IEnumerable<string> ExcludedHttpsHostNameRegex
7483
{
7584
get { return ExcludedHttpsHostNameRegexList?.Select(x => x.ToString()).ToList(); }
@@ -87,6 +96,7 @@ public IEnumerable<string> ExcludedHttpsHostNameRegex
8796
/// <summary>
8897
/// List of host names to exclude using Regular Expressions.
8998
/// </summary>
99+
[Obsolete("IncludedHttpsHostNameRegex is deprecated, please use BeforeTunnelConnect event instead.")]
90100
public IEnumerable<string> IncludedHttpsHostNameRegex
91101
{
92102
get { return IncludedHttpsHostNameRegexList?.Select(x => x.ToString()).ToList(); }
@@ -102,10 +112,22 @@ public IEnumerable<string> IncludedHttpsHostNameRegex
102112
}
103113

104114
/// <summary>
105-
/// Generic certificate to use for SSL decryption.
115+
/// Return true if this HTTP connect request should'nt be decrypted and instead be relayed
116+
/// Valid only for explicit endpoints
106117
/// </summary>
107-
public X509Certificate2 GenericCertificate { get; set; }
118+
public Func<string, Task<bool>> BeforeTunnelConnect;
108119

120+
/// <summary>
121+
/// Intercept tunnel connect request
122+
/// Valid only for explicit endpoints
123+
/// </summary>
124+
public event AsyncEventHandler<TunnelConnectSessionEventArgs> TunnelConnectRequest;
125+
126+
/// <summary>
127+
/// Intercept tunnel connect response
128+
/// Valid only for explicit endpoints
129+
/// </summary>
130+
public event AsyncEventHandler<TunnelConnectSessionEventArgs> TunnelConnectResponse;
109131
/// <summary>
110132
/// Constructor.
111133
/// </summary>
@@ -115,6 +137,31 @@ public IEnumerable<string> IncludedHttpsHostNameRegex
115137
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
116138
{
117139
}
140+
141+
internal async Task InvokeTunnectConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, Action<Exception> exceptionFunc)
142+
{
143+
if (TunnelConnectRequest != null)
144+
{
145+
await TunnelConnectRequest.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
146+
}
147+
}
148+
149+
internal async Task InvokeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, Action<Exception> exceptionFunc)
150+
{
151+
if (TunnelConnectResponse != null)
152+
{
153+
await TunnelConnectResponse.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
154+
}
155+
}
156+
157+
internal async Task InvokeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, Action<Exception> exceptionFunc, bool isClientHello)
158+
{
159+
if (TunnelConnectResponse != null)
160+
{
161+
connectArgs.IsHttpsConnect = isClientHello;
162+
await TunnelConnectResponse.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
163+
}
164+
}
118165
}
119166

120167
/// <summary>

0 commit comments

Comments
 (0)