Unverified Commit b27ba8cf authored by honfika's avatar honfika Committed by GitHub

Merge pull request #387 from justcoding121/develop

Merge to beta
parents 553c89ba 2b9a7d35
...@@ -69,11 +69,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -69,11 +69,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
}; };
//Fired when a CONNECT request is received //Fired when a CONNECT request is received
explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect; explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += OnBeforeTunnelConnectResponse;
explicitEndPoint.TunnelConnectRequest += OnTunnelConnectRequest;
explicitEndPoint.TunnelConnectResponse += OnTunnelConnectResponse;
//An explicit endpoint is where the client knows about the existence of a proxy //An explicit endpoint is where the client knows about the existence of a proxy
//So client sends request in a proxy friendly manner //So client sends request in a proxy friendly manner
...@@ -111,9 +108,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -111,9 +108,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
public void Stop() public void Stop()
{ {
explicitEndPoint.BeforeTunnelConnect -= OnBeforeTunnelConnect; explicitEndPoint.BeforeTunnelConnectRequest -= OnBeforeTunnelConnectRequest;
explicitEndPoint.TunnelConnectRequest -= OnTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectResponse -= OnBeforeTunnelConnectResponse;
explicitEndPoint.TunnelConnectResponse -= OnTunnelConnectResponse;
proxyServer.BeforeRequest -= OnRequest; proxyServer.BeforeRequest -= OnRequest;
proxyServer.BeforeResponse -= OnResponse; proxyServer.BeforeResponse -= OnResponse;
...@@ -126,27 +122,21 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -126,27 +122,21 @@ namespace Titanium.Web.Proxy.Examples.Basic
//proxyServer.CertificateManager.RemoveTrustedRootCertificates(); //proxyServer.CertificateManager.RemoveTrustedRootCertificates();
} }
private async Task<bool> OnBeforeTunnelConnect(string hostname) private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{ {
string hostname = e.WebSession.Request.RequestUri.Host;
Console.WriteLine("Tunnel to: " + hostname);
if (hostname.Contains("dropbox.com")) if (hostname.Contains("dropbox.com"))
{ {
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning //Useful for clients that use certificate pinning
//for example dropbox.com //for example dropbox.com
return await Task.FromResult(true); e.Excluded = true;
}
else
{
return await Task.FromResult(false);
} }
} }
private async Task OnTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) private async Task OnBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{
Console.WriteLine("Tunnel to: " + e.WebSession.Request.Host);
}
private async Task OnTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{ {
} }
......
...@@ -102,8 +102,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -102,8 +102,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
proxyServer.BeforeRequest += ProxyServer_BeforeRequest; proxyServer.BeforeRequest += ProxyServer_BeforeRequest;
proxyServer.BeforeResponse += ProxyServer_BeforeResponse; proxyServer.BeforeResponse += ProxyServer_BeforeResponse;
explicitEndPoint.TunnelConnectRequest += ProxyServer_TunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectRequest += ProxyServer_BeforeTunnelConnectRequest;
explicitEndPoint.TunnelConnectResponse += ProxyServer_TunnelConnectResponse; explicitEndPoint.BeforeTunnelConnectResponse += ProxyServer_BeforeTunnelConnectResponse;
proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); }; proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); };
proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); }; proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); };
proxyServer.Start(); proxyServer.Start();
...@@ -113,15 +113,21 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -113,15 +113,21 @@ namespace Titanium.Web.Proxy.Examples.Wpf
InitializeComponent(); InitializeComponent();
} }
private async Task ProxyServer_TunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) private async Task ProxyServer_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{ {
string hostname = e.WebSession.Request.RequestUri.Host;
if (hostname.EndsWith("webex.com"))
{
e.Excluded = true;
}
await Dispatcher.InvokeAsync(() => await Dispatcher.InvokeAsync(() =>
{ {
AddSession(e); AddSession(e);
}); });
} }
private async Task ProxyServer_TunnelConnectResponse(object sender, SessionEventArgs e) private async Task ProxyServer_BeforeTunnelConnectResponse(object sender, SessionEventArgs e)
{ {
await Dispatcher.InvokeAsync(() => await Dispatcher.InvokeAsync(() =>
{ {
......
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="StreamExtended, Version=1.0.135.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"> <Reference Include="StreamExtended, Version=1.0.138.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.135-beta\lib\net45\StreamExtended.dll</HintPath> <HintPath>..\..\packages\StreamExtended.1.0.138-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="StreamExtended" version="1.0.135-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.138-beta" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
...@@ -126,18 +126,16 @@ Sample request and response event handlers ...@@ -126,18 +126,16 @@ Sample request and response event handlers
private IDictionary<Guid, string> requestBodyHistory private IDictionary<Guid, string> requestBodyHistory
= new ConcurrentDictionary<Guid, string>(); = new ConcurrentDictionary<Guid, string>();
private async Task<bool> OnBeforeTunnelConnect(string hostname) private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{ {
string hostname = e.WebSession.Request.RequestUri.Host;
if (hostname.Contains("dropbox.com")) if (hostname.Contains("dropbox.com"))
{ {
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning //Useful for clients that use certificate pinning
//for example dropbox.com //for example dropbox.com
return await Task.FromResult(true); e.Excluded = true;
}
else
{
return await Task.FromResult(false);
} }
} }
......
...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.UnitTests
{ {
var tasks = new List<Task>(); var tasks = new List<Task>();
var mgr = new CertificateManager(null, null, false, false, false, new Lazy<Action<Exception>>(() => (e => var mgr = new CertificateManager(null, null, false, false, false, new Lazy<ExceptionHandler>(() => (e =>
{ {
//Console.WriteLine(e.ToString() + e.InnerException != null ? e.InnerException.ToString() : string.Empty); //Console.WriteLine(e.ToString() + e.InnerException != null ? e.InnerException.ToString() : string.Empty);
})).Value); })).Value);
...@@ -48,7 +48,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -48,7 +48,7 @@ namespace Titanium.Web.Proxy.UnitTests
{ {
var tasks = new List<Task>(); var tasks = new List<Task>();
var mgr = new CertificateManager(null, null, false, false, false, new Lazy<Action<Exception>>(() => (e => var mgr = new CertificateManager(null, null, false, false, false, new Lazy<ExceptionHandler>(() => (e =>
{ {
//Console.WriteLine(e.ToString() + e.InnerException != null ? e.InnerException.ToString() : string.Empty); //Console.WriteLine(e.ToString() + e.InnerException != null ? e.InnerException.ToString() : string.Empty);
})).Value); })).Value);
......
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy
}; };
//why is the sender null? //why is the sender null?
ServerCertificateValidationCallback.InvokeParallel(this, args); ServerCertificateValidationCallback.InvokeAsync(this, args, exceptionFunc).Wait();
return args.IsValid; return args.IsValid;
} }
...@@ -88,7 +88,7 @@ namespace Titanium.Web.Proxy ...@@ -88,7 +88,7 @@ namespace Titanium.Web.Proxy
}; };
//why is the sender null? //why is the sender null?
ClientCertificateSelectionCallback.InvokeParallel(this, args); ClientCertificateSelectionCallback.InvokeAsync(this, args, exceptionFunc).Wait();
return args.ClientCertificate; return args.ClientCertificate;
} }
......
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
private readonly int bufferSize; private readonly int bufferSize;
private readonly Action<Exception> exceptionFunc; private readonly ExceptionHandler exceptionFunc;
/// <summary> /// <summary>
/// Backing field for corresponding public property /// Backing field for corresponding public property
...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -105,7 +105,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
internal SessionEventArgs(int bufferSize, internal SessionEventArgs(int bufferSize,
ProxyEndPoint endPoint, ProxyEndPoint endPoint,
Action<Exception> exceptionFunc) ExceptionHandler exceptionFunc)
{ {
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
this.exceptionFunc = exceptionFunc; this.exceptionFunc = exceptionFunc;
......
...@@ -6,9 +6,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -6,9 +6,11 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class TunnelConnectSessionEventArgs : SessionEventArgs public class TunnelConnectSessionEventArgs : SessionEventArgs
{ {
public bool IsHttpsConnect { get; set; } public bool Excluded { get; set; }
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest, Action<Exception> exceptionFunc) public bool IsHttpsConnect { get; internal set; }
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, exceptionFunc) : base(bufferSize, endPoint, exceptionFunc)
{ {
WebSession.Request = connectRequest; WebSession.Request = connectRequest;
......
using System;
namespace Titanium.Web.Proxy
{
public delegate void ExceptionHandler(Exception exception);
}
\ No newline at end of file
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="message"></param> /// <param name="message"></param>
public BodyNotFoundException(string message) : base(message) internal BodyNotFoundException(string message) : base(message)
{ {
} }
} }
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
...@@ -13,13 +14,17 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -13,13 +14,17 @@ namespace Titanium.Web.Proxy.Exceptions
/// Instantiate new instance /// Instantiate new instance
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
/// <param name="session">The <see cref="SessionEventArgs"/> instance containing the event data.</param>
/// <param name="innerException">Inner exception associated to upstream proxy authorization</param> /// <param name="innerException">Inner exception associated to upstream proxy authorization</param>
/// <param name="headers">Http's headers associated</param> /// <param name="headers">Http's headers associated</param>
public ProxyAuthorizationException(string message, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException) internal ProxyAuthorizationException(string message, SessionEventArgs session, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException)
{ {
Session = session;
Headers = headers; Headers = headers;
} }
public SessionEventArgs Session { get; }
/// <summary> /// <summary>
/// Headers associated with the authorization exception /// Headers associated with the authorization exception
/// </summary> /// </summary>
......
...@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -14,7 +14,7 @@ namespace Titanium.Web.Proxy.Exceptions
/// <param name="message">Message for this exception</param> /// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param> /// <param name="innerException">Associated inner exception</param>
/// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs"/> associated to the exception</param> /// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs"/> associated to the exception</param>
public ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(message, innerException) internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(message, innerException)
{ {
SessionEventArgs = sessionEventArgs; SessionEventArgs = sessionEventArgs;
} }
......
...@@ -6,33 +6,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -6,33 +6,8 @@ namespace Titanium.Web.Proxy.Extensions
{ {
internal static class FuncExtensions internal static class FuncExtensions
{ {
public static void InvokeParallel<T>(this AsyncEventHandler<T> callback, object sender, T args)
{
var invocationList = callback.GetInvocationList();
var handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((AsyncEventHandler<T>)invocationList[i])(sender, args);
}
Task.WhenAll(handlerTasks).Wait();
}
public static async Task InvokeParallelAsync<T>(this AsyncEventHandler<T> callback, object sender, T args, Action<Exception> exceptionFunc)
{
var invocationList = callback.GetInvocationList();
var handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = InternalInvokeAsync((AsyncEventHandler<T>)invocationList[i], sender, args, exceptionFunc);
}
await Task.WhenAll(handlerTasks);
}
public static async Task InvokeAsync<T>(this AsyncEventHandler<T> callback, object sender, T args, Action<Exception> exceptionFunc) public static async Task InvokeAsync<T>(this AsyncEventHandler<T> callback, object sender, T args, ExceptionHandler exceptionFunc)
{ {
var invocationList = callback.GetInvocationList(); var invocationList = callback.GetInvocationList();
...@@ -42,16 +17,15 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -42,16 +17,15 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args, Action<Exception> exceptionFunc) private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args, ExceptionHandler exceptionFunc)
{ {
try try
{ {
await callback(sender, args); await callback(sender, args);
} }
catch (Exception ex) catch (Exception e)
{ {
var ex2 = new Exception("Exception thrown in user event", ex); exceptionFunc(new Exception("Exception thrown in user event", e));
exceptionFunc(ex2);
} }
} }
} }
......
...@@ -122,7 +122,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -122,7 +122,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize, internal static async Task SendRawApm(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<Exception> exceptionFunc) Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, ExceptionHandler exceptionFunc)
{ {
var tcs = new TaskCompletionSource<bool>(); var tcs = new TaskCompletionSource<bool>();
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
...@@ -145,7 +145,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -145,7 +145,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer, CancellationTokenSource cts, Action<byte[], int, int> onCopy, private static void BeginRead(Stream inputStream, Stream outputStream, byte[] buffer, CancellationTokenSource cts, Action<byte[], int, int> onCopy,
Action<Exception> exceptionFunc) ExceptionHandler exceptionFunc)
{ {
if (cts.IsCancellationRequested) if (cts.IsCancellationRequested)
{ {
...@@ -221,7 +221,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -221,7 +221,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize, internal static async Task SendRawTap(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<Exception> exceptionFunc) Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, ExceptionHandler exceptionFunc)
{ {
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
...@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -247,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
/// <returns></returns> /// <returns></returns>
internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize, internal static Task SendRaw(Stream clientStream, Stream serverStream, int bufferSize,
Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, Action<Exception> exceptionFunc) Action<byte[], int, int> onDataSend, Action<byte[], int, int> onDataReceive, ExceptionHandler exceptionFunc)
{ {
#if NET45 #if NET45
return SendRawApm(clientStream, serverStream, bufferSize, onDataSend, onDataReceive, exceptionFunc); return SendRawApm(clientStream, serverStream, bufferSize, onDataSend, onDataReceive, exceptionFunc);
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Models
{
/// <summary>
/// An abstract endpoint where the proxy listens
/// </summary>
public abstract class ProxyEndPoint
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
protected ProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl)
{
IpAddress = ipAddress;
Port = port;
EnableSsl = enableSsl;
}
/// <summary>
/// underlying TCP Listener object
/// </summary>
internal TcpListener Listener { get; set; }
/// <summary>
/// Ip Address we are listening.
/// </summary>
public IPAddress IpAddress { get; internal set; }
/// <summary>
/// Port we are listening.
/// </summary>
public int Port { get; internal set; }
/// <summary>
/// Enable SSL?
/// </summary>
public bool EnableSsl { get; internal set; }
/// <summary>
/// Is IPv6 enabled?
/// </summary>
public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any)
|| Equals(IpAddress, IPAddress.IPv6Loopback)
|| Equals(IpAddress, IPAddress.IPv6None);
}
/// <summary>
/// A proxy endpoint that the client is aware of
/// So client application know that it is communicating with a proxy server
/// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint
{
internal List<Regex> ExcludedHttpsHostNameRegexList;
internal List<Regex> IncludedHttpsHostNameRegexList;
internal bool IsSystemHttpProxy { get; set; }
internal bool IsSystemHttpsProxy { get; set; }
/// <summary>
/// Generic certificate to use for SSL decryption.
/// </summary>
public X509Certificate2 GenericCertificate { get; set; }
/// <summary>
/// Return true if this HTTP connect request should'nt be decrypted and instead be relayed
/// Valid only for explicit endpoints
/// </summary>
public Func<string, Task<bool>> BeforeTunnelConnect;
/// <summary>
/// Intercept tunnel connect request
/// Valid only for explicit endpoints
/// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> TunnelConnectRequest;
/// <summary>
/// Intercept tunnel connect response
/// Valid only for explicit endpoints
/// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> TunnelConnectResponse;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
{
}
internal async Task InvokeTunnectConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, Action<Exception> exceptionFunc)
{
if (TunnelConnectRequest != null)
{
await TunnelConnectRequest.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
}
}
internal async Task InvokeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, Action<Exception> exceptionFunc)
{
if (TunnelConnectResponse != null)
{
await TunnelConnectResponse.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
}
}
internal async Task InvokeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, Action<Exception> exceptionFunc, bool isClientHello)
{
if (TunnelConnectResponse != null)
{
connectArgs.IsHttpsConnect = isClientHello;
await TunnelConnectResponse.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
}
}
}
/// <summary>
/// A proxy end point client is not aware of
/// Usefull when requests are redirected to this proxy end point through port forwarding
/// </summary>
public class TransparentProxyEndPoint : ProxyEndPoint
{
/// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy)
/// This is valid only when UseServerNameIndication is set to false
/// </summary>
public string GenericCertificateName { get; set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
{
GenericCertificateName = "localhost";
}
}
}
using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Models
{
/// <summary>
/// A proxy endpoint that the client is aware of
/// So client application know that it is communicating with a proxy server
/// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint
{
internal bool IsSystemHttpProxy { get; set; }
internal bool IsSystemHttpsProxy { get; set; }
/// <summary>
/// Generic certificate to use for SSL decryption.
/// </summary>
public X509Certificate2 GenericCertificate { get; set; }
/// <summary>
/// Intercept tunnel connect request
/// Valid only for explicit endpoints
/// Set the <see cref="TunnelConnectSessionEventArgs.Excluded"/> property to true if this HTTP connect request should'nt be decrypted and instead be relayed
/// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest;
/// <summary>
/// Intercept tunnel connect response
/// Valid only for explicit endpoints
/// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectResponse;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
{
}
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
{
if (BeforeTunnelConnectRequest != null)
{
await BeforeTunnelConnectRequest.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
}
}
internal async Task InvokeBeforeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false)
{
if (BeforeTunnelConnectResponse != null)
{
connectArgs.IsHttpsConnect = isClientHello;
await BeforeTunnelConnectResponse.InvokeAsync(proxyServer, connectArgs, exceptionFunc);
}
}
}
}
\ No newline at end of file
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
namespace Titanium.Web.Proxy.Models
{
/// <summary>
/// An abstract endpoint where the proxy listens
/// </summary>
public abstract class ProxyEndPoint
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
protected ProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl)
{
IpAddress = ipAddress;
Port = port;
EnableSsl = enableSsl;
}
/// <summary>
/// underlying TCP Listener object
/// </summary>
internal TcpListener Listener { get; set; }
/// <summary>
/// Ip Address we are listening.
/// </summary>
public IPAddress IpAddress { get; }
/// <summary>
/// Port we are listening.
/// </summary>
public int Port { get; internal set; }
/// <summary>
/// Enable SSL?
/// </summary>
public bool EnableSsl { get; }
/// <summary>
/// Is IPv6 enabled?
/// </summary>
public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any)
|| Equals(IpAddress, IPAddress.IPv6Loopback)
|| Equals(IpAddress, IPAddress.IPv6None);
}
}
using System.Net;
namespace Titanium.Web.Proxy.Models
{
/// <summary>
/// A proxy end point client is not aware of
/// Usefull when requests are redirected to this proxy end point through port forwarding
/// </summary>
public class TransparentProxyEndPoint : ProxyEndPoint
{
/// <summary>
/// Name of the Certificate need to be sent (same as the hostname we want to proxy)
/// This is valid only when UseServerNameIndication is set to false
/// </summary>
public string GenericCertificateName { get; set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="enableSsl"></param>
public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
{
GenericCertificateName = "localhost";
}
}
}
\ No newline at end of file
...@@ -33,9 +33,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -33,9 +33,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
// Set this flag to true when exception detected to avoid further exceptions // Set this flag to true when exception detected to avoid further exceptions
private static bool doNotSetFriendlyName; private static bool doNotSetFriendlyName;
private readonly Action<Exception> exceptionFunc; private readonly ExceptionHandler exceptionFunc;
internal BCCertificateMaker(Action<Exception> exceptionFunc) internal BCCertificateMaker(ExceptionHandler exceptionFunc)
{ {
this.exceptionFunc = exceptionFunc; this.exceptionFunc = exceptionFunc;
} }
......
...@@ -43,12 +43,12 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -43,12 +43,12 @@ namespace Titanium.Web.Proxy.Network.Certificate
private object sharedPrivateKey; private object sharedPrivateKey;
private readonly Action<Exception> exceptionFunc; private readonly ExceptionHandler exceptionFunc;
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
internal WinCertificateMaker(Action<Exception> exceptionFunc) internal WinCertificateMaker(ExceptionHandler exceptionFunc)
{ {
this.exceptionFunc = exceptionFunc; this.exceptionFunc = exceptionFunc;
typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true); typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true);
......
...@@ -59,7 +59,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -59,7 +59,7 @@ namespace Titanium.Web.Proxy.Network
private readonly ConcurrentDictionary<string, CachedCertificate> certificateCache; private readonly ConcurrentDictionary<string, CachedCertificate> certificateCache;
private readonly ConcurrentDictionary<string, Task<X509Certificate2>> pendingCertificateCreationTasks; private readonly ConcurrentDictionary<string, Task<X509Certificate2>> pendingCertificateCreationTasks;
private readonly Action<Exception> exceptionFunc; private readonly ExceptionHandler exceptionFunc;
/// <summary> /// <summary>
/// Is the root certificate used by this proxy is valid? /// Is the root certificate used by this proxy is valid?
...@@ -107,7 +107,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -107,7 +107,9 @@ namespace Titanium.Web.Proxy.Network
if (certEngine == null) if (certEngine == null)
{ {
certEngine = engine == CertificateEngine.BouncyCastle ? (ICertificateMaker)new BCCertificateMaker(exceptionFunc) : new WinCertificateMaker(exceptionFunc); certEngine = engine == CertificateEngine.BouncyCastle
? (ICertificateMaker)new BCCertificateMaker(exceptionFunc)
: new WinCertificateMaker(exceptionFunc);
} }
} }
} }
...@@ -196,9 +198,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -196,9 +198,9 @@ namespace Titanium.Web.Proxy.Network
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param> /// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
/// <param name="userTrustRootCertificate"></param> /// <param name="userTrustRootCertificate"></param>
/// <param name="machineTrustRootCertificate">Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true</param> /// <param name="machineTrustRootCertificate">Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true</param>
/// <param name="trustRootCertificateAsAdmin "></param> /// <param name="trustRootCertificateAsAdmin"></param>
/// <param name="exceptionFunc"></param> /// <param name="exceptionFunc"></param>
internal CertificateManager(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin, Action < Exception> exceptionFunc) internal CertificateManager(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin, ExceptionHandler exceptionFunc)
{ {
this.exceptionFunc = exceptionFunc; this.exceptionFunc = exceptionFunc;
...@@ -310,6 +312,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -310,6 +312,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// Make current machine trust the Root Certificate used by this proxy /// Make current machine trust the Root Certificate used by this proxy
/// </summary> /// </summary>
/// <param name="storeName"></param>
/// <param name="storeLocation"></param> /// <param name="storeLocation"></param>
/// <returns></returns> /// <returns></returns>
private void InstallCertificate(StoreName storeName, StoreLocation storeLocation) private void InstallCertificate(StoreName storeName, StoreLocation storeLocation)
...@@ -348,7 +351,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -348,7 +351,9 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// Remove the Root Certificate trust /// Remove the Root Certificate trust
/// </summary> /// </summary>
/// <param name="storeName"></param>
/// <param name="storeLocation"></param> /// <param name="storeLocation"></param>
/// <param name="certificate"></param>
/// <returns></returns> /// <returns></returns>
private void UninstallCertificate(StoreName storeName, StoreLocation storeLocation, X509Certificate2 certificate) private void UninstallCertificate(StoreName storeName, StoreLocation storeLocation, X509Certificate2 certificate)
{ {
......
...@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy ...@@ -15,7 +15,7 @@ namespace Titanium.Web.Proxy
{ {
public partial class ProxyServer public partial class ProxyServer
{ {
private async Task<bool> CheckAuthorization(HttpResponseWriter clientStreamWriter, SessionEventArgs session) private async Task<bool> CheckAuthorization(SessionEventArgs session)
{ {
if (AuthenticateUserFunc == null) if (AuthenticateUserFunc == null)
{ {
...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy ...@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy
var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization); var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization);
if (header == null) if (header == null)
{ {
session.WebSession.Response = await SendAuthentication407Response(clientStreamWriter, "Proxy Authentication Required"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Required");
return false; return false;
} }
...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy ...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy
if (headerValueParts.Length != 2 || !headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) if (headerValueParts.Length != 2 || !headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic))
{ {
//Return not authorized //Return not authorized
session.WebSession.Response = await SendAuthentication407Response(clientStreamWriter, "Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false; return false;
} }
...@@ -46,25 +46,32 @@ namespace Titanium.Web.Proxy ...@@ -46,25 +46,32 @@ namespace Titanium.Web.Proxy
if (colonIndex == -1) if (colonIndex == -1)
{ {
//Return not authorized //Return not authorized
session.WebSession.Response = await SendAuthentication407Response(clientStreamWriter, "Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false; return false;
} }
string username = decoded.Substring(0, colonIndex); string username = decoded.Substring(0, colonIndex);
string password = decoded.Substring(colonIndex + 1); string password = decoded.Substring(colonIndex + 1);
return await AuthenticateUserFunc(username, password); bool authenticated = await AuthenticateUserFunc(username, password);
if (!authenticated)
{
//Return not authorized
session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
}
return authenticated;
} }
catch (Exception e) catch (Exception e)
{ {
ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", e, httpHeaders)); ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, httpHeaders));
//Return not authorized //Return not authorized
session.WebSession.Response = await SendAuthentication407Response(clientStreamWriter, "Proxy Authentication Invalid"); session.WebSession.Response = CreateAuthentication407Response("Proxy Authentication Invalid");
return false; return false;
} }
} }
private async Task<Response> SendAuthentication407Response(HttpResponseWriter clientStreamWriter, string description) private Response CreateAuthentication407Response(string description)
{ {
var response = new Response var response = new Response
{ {
...@@ -77,7 +84,6 @@ namespace Titanium.Web.Proxy ...@@ -77,7 +84,6 @@ namespace Titanium.Web.Proxy
response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ProxyConnectionClose); response.Headers.AddHeader(KnownHeaders.ProxyConnection, KnownHeaders.ProxyConnectionClose);
response.Headers.FixProxyHeaders(); response.Headers.FixProxyHeaders();
await clientStreamWriter.WriteResponseAsync(response);
return response; return response;
} }
} }
......
...@@ -53,12 +53,12 @@ namespace Titanium.Web.Proxy ...@@ -53,12 +53,12 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// An default exception log func /// An default exception log func
/// </summary> /// </summary>
private readonly Lazy<Action<Exception>> defaultExceptionFunc = new Lazy<Action<Exception>>(() => (e => { })); private readonly Lazy<ExceptionHandler> defaultExceptionFunc = new Lazy<ExceptionHandler>(() => (e => { }));
/// <summary> /// <summary>
/// backing exception func for exposed public property /// backing exception func for exposed public property
/// </summary> /// </summary>
private Action<Exception> exceptionFunc; private ExceptionHandler exceptionFunc;
/// <summary> /// <summary>
/// Is the proxy currently running /// Is the proxy currently running
...@@ -192,7 +192,7 @@ namespace Titanium.Web.Proxy ...@@ -192,7 +192,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Callback for error events in proxy /// Callback for error events in proxy
/// </summary> /// </summary>
public Action<Exception> ExceptionFunc public ExceptionHandler ExceptionFunc
{ {
get => exceptionFunc ?? defaultExceptionFunc.Value; get => exceptionFunc ?? defaultExceptionFunc.Value;
set => exceptionFunc = value; set => exceptionFunc = value;
...@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy ...@@ -210,7 +210,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
/// <param name="userTrustRootCertificate"></param> /// <param name="userTrustRootCertificate"></param>
/// <param name="machineTrustRootCertificate">Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true</param> /// <param name="machineTrustRootCertificate">Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true</param>
/// <param name="trustRootCertificateAsAdmin "></param> /// <param name="trustRootCertificateAsAdmin"></param>
public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) : this(null, null, userTrustRootCertificate, machineTrustRootCertificate, trustRootCertificateAsAdmin) public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) : this(null, null, userTrustRootCertificate, machineTrustRootCertificate, trustRootCertificateAsAdmin)
{ {
} }
...@@ -222,7 +222,7 @@ namespace Titanium.Web.Proxy ...@@ -222,7 +222,7 @@ namespace Titanium.Web.Proxy
/// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param> /// <param name="rootCertificateIssuerName">Name of root certificate issuer.</param>
/// <param name="userTrustRootCertificate"></param> /// <param name="userTrustRootCertificate"></param>
/// <param name="machineTrustRootCertificate">Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true</param> /// <param name="machineTrustRootCertificate">Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true</param>
/// <param name="trustRootCertificateAsAdmin "></param> /// <param name="trustRootCertificateAsAdmin"></param>
public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false) public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false)
{ {
//default values //default values
...@@ -660,6 +660,7 @@ namespace Titanium.Web.Proxy ...@@ -660,6 +660,7 @@ namespace Titanium.Web.Proxy
endPoint.Listener.Server.Dispose(); endPoint.Listener.Server.Dispose();
} }
internal void UpdateClientConnectionCount(bool increment) internal void UpdateClientConnectionCount(bool increment)
{ {
if (increment) if (increment)
......
...@@ -64,14 +64,6 @@ namespace Titanium.Web.Proxy ...@@ -64,14 +64,6 @@ namespace Titanium.Web.Proxy
var httpRemoteUri = new Uri("http://" + httpUrl); var httpRemoteUri = new Uri("http://" + httpUrl);
connectHostname = httpRemoteUri.Host; connectHostname = httpRemoteUri.Host;
//filter out excluded host names
bool excluded = false;
if(endPoint.BeforeTunnelConnect!=null)
{
excluded = await endPoint.BeforeTunnelConnect(connectHostname);
}
connectRequest = new ConnectRequest connectRequest = new ConnectRequest
{ {
RequestUri = httpRemoteUri, RequestUri = httpRemoteUri,
...@@ -85,12 +77,17 @@ namespace Titanium.Web.Proxy ...@@ -85,12 +77,17 @@ namespace Titanium.Web.Proxy
connectArgs.ProxyClient.TcpClient = tcpClient; connectArgs.ProxyClient.TcpClient = tcpClient;
connectArgs.ProxyClient.ClientStream = clientStream; connectArgs.ProxyClient.ClientStream = clientStream;
await endPoint.InvokeTunnectConnectRequest(this, connectArgs, ExceptionFunc); await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);
//filter out excluded host names
bool excluded = connectArgs.Excluded;
if (await CheckAuthorization(clientStreamWriter, connectArgs) == false) if (await CheckAuthorization(connectArgs) == false)
{ {
await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc); await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc);
//send the response
await clientStreamWriter.WriteResponseAsync(connectArgs.WebSession.Response);
return; return;
} }
...@@ -108,7 +105,7 @@ namespace Titanium.Web.Proxy ...@@ -108,7 +105,7 @@ namespace Titanium.Web.Proxy
connectRequest.ClientHelloInfo = clientHelloInfo; connectRequest.ClientHelloInfo = clientHelloInfo;
} }
await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello);
if (!excluded && isClientHello) if (!excluded && isClientHello)
{ {
...@@ -134,8 +131,9 @@ namespace Titanium.Web.Proxy ...@@ -134,8 +131,9 @@ namespace Titanium.Web.Proxy
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
} }
catch catch(Exception e)
{ {
ExceptionFunc(new Exception($"Could'nt authenticate client '{connectHostname}' with fake certificate.", e));
sslStream?.Dispose(); sslStream?.Dispose();
return; return;
} }
...@@ -239,13 +237,20 @@ namespace Titanium.Web.Proxy ...@@ -239,13 +237,20 @@ namespace Titanium.Web.Proxy
var sslStream = new SslStream(clientStream); var sslStream = new SslStream(clientStream);
clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStream = new CustomBufferedStream(sslStream, BufferSize);
string sniHostName = clientHelloInfo.GetServerName(); string sniHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
string certName = HttpHelper.GetWildCardDomainName(sniHostName ?? endPoint.GenericCertificateName); string certName = HttpHelper.GetWildCardDomainName(sniHostName);
var certificate = await CertificateManager.CreateCertificateAsync(certName); var certificate = await CertificateManager.CreateCertificateAsync(certName);
try
//Successfully managed to authenticate the client using the fake certificate {
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); //Successfully managed to authenticate the client using the fake certificate
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
}
catch (Exception e)
{
ExceptionFunc(new Exception($"Could'nt authenticate client '{sniHostName}' with fake certificate.", e));
return;
}
} }
//HTTPS server created - we can now decrypt the client's traffic //HTTPS server created - we can now decrypt the client's traffic
...@@ -350,8 +355,12 @@ namespace Titanium.Web.Proxy ...@@ -350,8 +355,12 @@ namespace Titanium.Web.Proxy
args.ProxyClient.ClientStreamWriter = clientStreamWriter; args.ProxyClient.ClientStreamWriter = clientStreamWriter;
//proxy authorization check //proxy authorization check
if (!args.IsTransparent && httpsConnectHostname == null && await CheckAuthorization(clientStreamWriter, args) == false) if (!args.IsTransparent && httpsConnectHostname == null && await CheckAuthorization(args) == false)
{ {
await InvokeBeforeResponse(args);
//send the response
await clientStreamWriter.WriteResponseAsync(args.WebSession.Response);
break; break;
} }
...@@ -370,10 +379,7 @@ namespace Titanium.Web.Proxy ...@@ -370,10 +379,7 @@ namespace Titanium.Web.Proxy
} }
//If user requested interception do it //If user requested interception do it
if (BeforeRequest != null) await InvokeBeforeRequest(args);
{
await BeforeRequest.InvokeAsync(this, args, ExceptionFunc);
}
var response = args.WebSession.Response; var response = args.WebSession.Response;
...@@ -426,9 +432,9 @@ namespace Titanium.Web.Proxy ...@@ -426,9 +432,9 @@ namespace Titanium.Web.Proxy
} }
//If user requested call back then do it //If user requested call back then do it
if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) if (!args.WebSession.Response.ResponseLocked)
{ {
await BeforeResponse.InvokeAsync(this, args, ExceptionFunc); await InvokeBeforeResponse(args);
} }
await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize,
...@@ -593,5 +599,13 @@ namespace Titanium.Web.Proxy ...@@ -593,5 +599,13 @@ namespace Titanium.Web.Proxy
requestHeaders.FixProxyHeaders(); requestHeaders.FixProxyHeaders();
} }
private async Task InvokeBeforeRequest(SessionEventArgs args)
{
if (BeforeRequest != null)
{
await BeforeRequest.InvokeAsync(this, args, ExceptionFunc);
}
}
} }
} }
...@@ -35,10 +35,10 @@ namespace Titanium.Web.Proxy ...@@ -35,10 +35,10 @@ namespace Titanium.Web.Proxy
args.ReRequest = false; args.ReRequest = false;
//If user requested call back then do it //if user requested call back then do it
if (BeforeResponse != null && !response.ResponseLocked) if (!response.ResponseLocked)
{ {
await BeforeResponse.InvokeAsync(this, args, ExceptionFunc); await InvokeBeforeResponse(args);
} }
//if user requested to send request again //if user requested to send request again
...@@ -125,5 +125,14 @@ namespace Titanium.Web.Proxy ...@@ -125,5 +125,14 @@ namespace Titanium.Web.Proxy
var compressor = CompressionFactory.GetCompression(encodingType); var compressor = CompressionFactory.GetCompression(encodingType);
return await compressor.Compress(responseBodyStream); return await compressor.Compress(responseBodyStream);
} }
private async Task InvokeBeforeResponse(SessionEventArgs args)
{
if (BeforeResponse != null)
{
await BeforeResponse.InvokeAsync(this, args, ExceptionFunc);
}
}
} }
} }
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.4" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.1.4" />
<PackageReference Include="StreamExtended" Version="1.0.135-beta" /> <PackageReference Include="StreamExtended" Version="1.0.138-beta" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'"> <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright> <copyright>Copyright &#x00A9; Titanium. All rights reserved.</copyright>
<tags></tags> <tags></tags>
<dependencies> <dependencies>
<dependency id="StreamExtended" version="1.0.110-beta" /> <dependency id="StreamExtended" version="1.0.138-beta" />
<dependency id="Portable.BouncyCastle" version="1.8.1.4" /> <dependency id="Portable.BouncyCastle" version="1.8.1.4" />
</dependencies> </dependencies>
</metadata> </metadata>
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Portable.BouncyCastle" version="1.8.1.4" targetFramework="net45" /> <package id="Portable.BouncyCastle" version="1.8.1.4" targetFramework="net45" />
<package id="StreamExtended" version="1.0.110-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.138-beta" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
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