Commit 5c618dee authored by Honfika's avatar Honfika

Add client user data, which is unique for each client connection (but not for...

Add client user data, which is unique for each client connection (but not for each request) Similar to PR #690
parent 46c59104
using Titanium.Web.Proxy.EventArguments;
namespace Titanium.Web.Proxy.Examples.Basic
{
public static class ProxyEventArgsBaseExtensions
{
public static SampleClientState GetState(this ProxyEventArgsBase args)
{
if (args.ClientUserData == null)
{
args.ClientUserData = new SampleClientState();
}
return (SampleClientState)args.ClientUserData;
}
}
}
......@@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments;
......@@ -64,6 +64,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
{
proxyServer.BeforeRequest += onRequest;
proxyServer.BeforeResponse += onResponse;
proxyServer.AfterResponse += onAfterResponse;
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
......@@ -128,6 +129,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task<IExternalProxy> onGetCustomUpStreamProxyFunc(SessionEventArgsBase arg)
{
arg.GetState().PipelineInfo.AppendLine(nameof(onGetCustomUpStreamProxyFunc));
// this is just to show the functionality, provided values are junk
return new ExternalProxy
{
......@@ -138,6 +141,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task<IExternalProxy> onCustomUpStreamProxyFailureFunc(SessionEventArgsBase arg)
{
arg.GetState().PipelineInfo.AppendLine(nameof(onCustomUpStreamProxyFailureFunc));
// this is just to show the functionality, provided values are junk
return new ExternalProxy
{
......@@ -149,6 +154,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{
string hostname = e.HttpClient.Request.RequestUri.Host;
e.GetState().PipelineInfo.AppendLine(nameof(onBeforeTunnelConnectRequest) + ":" + hostname);
await writeToConsole("Tunnel to: " + hostname);
if (hostname.Contains("dropbox.com"))
......@@ -194,12 +200,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
private Task onBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
{
e.GetState().PipelineInfo.AppendLine(nameof(onBeforeTunnelConnectResponse) + ":" + e.HttpClient.Request.RequestUri);
return Task.FromResult(false);
}
// intercept & cancel redirect or update requests
private async Task onRequest(object sender, SessionEventArgs e)
{
e.GetState().PipelineInfo.AppendLine(nameof(onRequest) + ":" + e.HttpClient.Request.RequestUri);
await writeToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
await writeToConsole(e.HttpClient.Request.Url);
......@@ -241,6 +251,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
// Modify response
private async Task multipartRequestPartSent(object sender, MultipartRequestPartSentEventArgs e)
{
e.GetState().PipelineInfo.AppendLine(nameof(multipartRequestPartSent));
var session = (SessionEventArgs)sender;
await writeToConsole("Multipart form data headers:");
foreach (var header in e.Headers)
......@@ -251,6 +263,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task onResponse(object sender, SessionEventArgs e)
{
e.GetState().PipelineInfo.AppendLine(nameof(onResponse));
if (e.HttpClient.ConnectRequest?.TunnelType == TunnelType.Websocket)
{
e.DataSent += WebSocket_DataSent;
......@@ -301,6 +315,11 @@ namespace Titanium.Web.Proxy.Examples.Basic
//}
}
private async Task onAfterResponse(object sender, SessionEventArgs e)
{
await writeToConsole($"Pipelineinfo: {e.GetState().PipelineInfo}", ConsoleColor.Yellow);
}
/// <summary>
/// Allows overriding default certificate validation logic
/// </summary>
......@@ -308,6 +327,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
/// <param name="e"></param>
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{
e.GetState().PipelineInfo.AppendLine(nameof(OnCertificateValidation));
// set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == SslPolicyErrors.None)
{
......@@ -324,6 +345,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
/// <param name="e"></param>
public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)
{
e.GetState().PipelineInfo.AppendLine(nameof(OnCertificateSelection));
// set e.clientCertificate to override
return Task.FromResult(0);
......@@ -360,3 +383,4 @@ namespace Titanium.Web.Proxy.Examples.Basic
//}
}
}
using System;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Examples.Basic
{
public class SampleClientState
{
public StringBuilder PipelineInfo { get; } = new StringBuilder();
}
}
using System;
using System.Threading;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// This is used in transparent endpoint before authenticating client.
/// </summary>
public class BeforeSslAuthenticateEventArgs : EventArgs
public class BeforeSslAuthenticateEventArgs : ProxyEventArgsBase
{
internal readonly CancellationTokenSource TaskCancellationSource;
internal BeforeSslAuthenticateEventArgs(CancellationTokenSource taskCancellationSource, string sniHostName)
internal BeforeSslAuthenticateEventArgs(TcpClientConnection clientConnection, CancellationTokenSource taskCancellationSource, string sniHostName) : base(clientConnection)
{
TaskCancellationSource = taskCancellationSource;
SniHostName = sniHostName;
......
......@@ -6,10 +6,10 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// An argument passed on to user for client certificate selection during mutual SSL authentication.
/// </summary>
public class CertificateSelectionEventArgs : EventArgs
public class CertificateSelectionEventArgs : ProxyEventArgsBase
{
public CertificateSelectionEventArgs(SessionEventArgsBase session, string targetHost,
X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) : base(session.ClientConnection)
{
Session = session;
TargetHost = targetHost;
......
......@@ -8,9 +8,9 @@ namespace Titanium.Web.Proxy.EventArguments
/// An argument passed on to the user for validating the server certificate
/// during SSL authentication.
/// </summary>
public class CertificateValidationEventArgs : EventArgs
public class CertificateValidationEventArgs : ProxyEventArgsBase
{
public CertificateValidationEventArgs(SessionEventArgsBase session, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
public CertificateValidationEventArgs(SessionEventArgsBase session, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) : base(session.ClientConnection)
{
Session = session;
Certificate = certificate;
......
using System;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// Class that wraps the multipart sent request arguments.
/// </summary>
public class MultipartRequestPartSentEventArgs : EventArgs
public class MultipartRequestPartSentEventArgs : ProxyEventArgsBase
{
internal MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers)
internal MultipartRequestPartSentEventArgs(SessionEventArgs session, string boundary, HeaderCollection headers) : base(session.ClientConnection)
{
Session = session;
Boundary = boundary;
Headers = headers;
}
/// <value>
/// The session arguments.
/// </value>
public SessionEventArgs Session { get; }
/// <summary>
/// Boundary.
/// </summary>
......
using System;
using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy.EventArguments
{
/// <summary>
/// The base event arguments
/// </summary>
/// <seealso cref="System.EventArgs" />
public abstract class ProxyEventArgsBase : EventArgs
{
private readonly TcpClientConnection clientConnection;
public object ClientUserData
{
get => clientConnection.ClientUserData;
set => clientConnection.ClientUserData = value;
}
internal ProxyEventArgsBase(TcpClientConnection clientConnection)
{
this.clientConnection = clientConnection;
}
}
}
......@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
private bool reRequest;
private WebSocketDecoder? webSocketDecoder;
private WebSocketDecoder webSocketDecoder;
/// <summary>
/// Is this session a HTTP/2 promise?
......@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.EventArguments
{
try
{
MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(boundary.ToString(), headers));
MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(this, boundary.ToString(), headers));
}
catch (Exception ex)
{
......
......@@ -18,7 +18,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy.
/// </summary>
public abstract class SessionEventArgsBase : EventArgs, IDisposable
public abstract class SessionEventArgsBase : ProxyEventArgsBase, IDisposable
{
private static bool isWindowsAuthenticationSupported => RunTime.IsWindows;
......@@ -50,7 +50,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
/// </summary>
private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource)
HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource) : base(clientStream.Connection)
{
BufferPool = server.BufferPool;
ExceptionFunc = server.ExceptionFunc;
......
......@@ -16,6 +16,8 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary>
internal class TcpClientConnection : IDisposable
{
public object ClientUserData { get; set; }
internal TcpClientConnection(ProxyServer proxyServer, TcpClient tcpClient)
{
this.tcpClient = tcpClient;
......
......@@ -445,7 +445,7 @@ retry:
sessionArgs.TimeLine["Connection Established"] = DateTime.Now;
}
await proxyServer.InvokeConnectionCreateEvent(tcpClient, false);
await proxyServer.InvokeServerConnectionCreateEvent(tcpClient);
stream = new HttpServerStream(tcpClient.GetStream(), proxyServer.BufferPool);
......
......@@ -795,7 +795,7 @@ namespace Titanium.Web.Proxy
tcpClient.LingerState = new LingerOption(true, TcpTimeWaitSeconds);
await InvokeConnectionCreateEvent(tcpClient, true);
await InvokeClientConnectionCreateEvent(tcpClient);
using (var clientConnection = new TcpClientConnection(this, tcpClient))
{
......@@ -866,21 +866,28 @@ namespace Titanium.Web.Proxy
}
/// <summary>
/// Invoke client/server tcp connection events if subscribed by API user.
/// Invoke client tcp connection events if subscribed by API user.
/// </summary>
/// <param name="client">The TcpClient object.</param>
/// <param name="isClientConnection">Is this a client connection created event? If not then we would assume that its a server connection create event.</param>
/// <returns></returns>
internal async Task InvokeConnectionCreateEvent(TcpClient client, bool isClientConnection)
internal async Task InvokeClientConnectionCreateEvent(TcpClient client)
{
// client connection created
if (isClientConnection && OnClientConnectionCreate != null)
if (OnClientConnectionCreate != null)
{
await OnClientConnectionCreate.InvokeAsync(this, client, ExceptionFunc);
}
}
/// <summary>
/// Invoke server tcp connection events if subscribed by API user.
/// </summary>
/// <param name="client">The TcpClient object.</param>
/// <returns></returns>
internal async Task InvokeServerConnectionCreateEvent(TcpClient client)
{
// server connection created
if (!isClientConnection && OnServerConnectionCreate != null)
if (OnServerConnectionCreate != null)
{
await OnServerConnectionCreate.InvokeAsync(this, client, ExceptionFunc);
}
......
......@@ -41,13 +41,11 @@ namespace Titanium.Web.Proxy
{
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
string? httpsHostName = null;
if (clientHelloInfo != null)
{
httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
var httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource, httpsHostName);
var args = new BeforeSslAuthenticateEventArgs(clientConnection, cancellationTokenSource, httpsHostName);
await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc);
......
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