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

Commit 8a5cc3f

Browse files
Володько А ВВолодько А В
authored andcommitted
Introduce asynchronous RequestState and simplify error logging
1 parent f1fd7c7 commit 8a5cc3f

27 files changed

+1307
-955
lines changed

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

Lines changed: 349 additions & 295 deletions
Large diffs are not rendered by default.

examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf_lmb5j4or_wpftmp.csproj

Lines changed: 174 additions & 0 deletions
Large diffs are not rendered by default.

src/Titanium.Web.Proxy/CertificateHandler.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,22 @@
66

77
namespace Titanium.Web.Proxy
88
{
9-
public partial class ProxyServer
9+
public partial class RequestStateBase
10+
{
11+
internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
12+
SslPolicyErrors sslPolicyErrors)
13+
{
14+
return Server.ValidateServerCertificate(this, sender, certificate, chain, sslPolicyErrors);
15+
}
16+
internal X509Certificate? SelectClientCertificate(object sender, string targetHost,
17+
X509CertificateCollection localCertificates,
18+
X509Certificate remoteCertificate, string[] acceptableIssuers)
19+
{
20+
return Server.SelectClientCertificate(this, sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers);
21+
}
22+
23+
}
24+
public partial class ProxyServerBase
1025
{
1126
/// <summary>
1227
/// Call back to override server certificate validation
@@ -16,16 +31,16 @@ public partial class ProxyServer
1631
/// <param name="chain">The certificate chain.</param>
1732
/// <param name="sslPolicyErrors">Ssl policy errors</param>
1833
/// <returns>Return true if valid certificate.</returns>
19-
internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
34+
internal bool ValidateServerCertificate(RequestStateBase state, object sender, X509Certificate certificate, X509Chain chain,
2035
SslPolicyErrors sslPolicyErrors)
2136
{
2237
// if user callback is registered then do it
2338
if (ServerCertificateValidationCallback != null)
2439
{
25-
var args = new CertificateValidationEventArgs(certificate, chain, sslPolicyErrors);
40+
var args = new CertificateValidationEventArgs(state, certificate, chain, sslPolicyErrors);
2641

2742
// why is the sender null?
28-
ServerCertificateValidationCallback.InvokeAsync(this, args, ExceptionFunc).Wait();
43+
ServerCertificateValidationCallback.InvokeAsync(this, args, state.OnError).Wait();
2944
return args.IsValid;
3045
}
3146

@@ -48,7 +63,7 @@ internal bool ValidateServerCertificate(object sender, X509Certificate certifica
4863
/// <param name="remoteCertificate">The remote certificate of server.</param>
4964
/// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param>
5065
/// <returns></returns>
51-
internal X509Certificate? SelectClientCertificate(object sender, string targetHost,
66+
internal X509Certificate? SelectClientCertificate(RequestStateBase state, object sender, string targetHost,
5267
X509CertificateCollection localCertificates,
5368
X509Certificate remoteCertificate, string[] acceptableIssuers)
5469
{
@@ -75,7 +90,7 @@ internal bool ValidateServerCertificate(object sender, X509Certificate certifica
7590
// If user call back is registered
7691
if (ClientCertificateSelectionCallback != null)
7792
{
78-
var args = new CertificateSelectionEventArgs
93+
var args = new CertificateSelectionEventArgs(state)
7994
{
8095
TargetHost = targetHost,
8196
LocalCertificates = localCertificates,

src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ namespace Titanium.Web.Proxy.EventArguments
66
/// <summary>
77
/// This is used in transparent endpoint before authenticating client.
88
/// </summary>
9-
public class BeforeSslAuthenticateEventArgs : EventArgs
9+
public class BeforeSslAuthenticateEventArgs : ProxyEventArgsBase
1010
{
1111
internal readonly CancellationTokenSource TaskCancellationSource;
1212

13-
internal BeforeSslAuthenticateEventArgs(CancellationTokenSource taskCancellationSource, string sniHostName)
13+
internal BeforeSslAuthenticateEventArgs(RequestStateBase state ,CancellationTokenSource taskCancellationSource, string sniHostName)
14+
:base(state)
1415
{
1516
TaskCancellationSource = taskCancellationSource;
1617
SniHostName = sniHostName;

src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ namespace Titanium.Web.Proxy.EventArguments
66
/// <summary>
77
/// An argument passed on to user for client certificate selection during mutual SSL authentication.
88
/// </summary>
9-
public class CertificateSelectionEventArgs : EventArgs
9+
public class CertificateSelectionEventArgs : ProxyEventArgsBase
1010
{
11+
public CertificateSelectionEventArgs(RequestStateBase state)
12+
:base(state)
13+
{ }
1114
/// <summary>
1215
/// The proxy server instance.
1316
/// </summary>

src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ namespace Titanium.Web.Proxy.EventArguments
88
/// An argument passed on to the user for validating the server certificate
99
/// during SSL authentication.
1010
/// </summary>
11-
public class CertificateValidationEventArgs : EventArgs
11+
public class CertificateValidationEventArgs : ProxyEventArgsBase
1212
{
13-
public CertificateValidationEventArgs(X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
13+
public CertificateValidationEventArgs(RequestStateBase state, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
14+
:base(state)
1415
{
1516
Certificate = certificate;
1617
Chain = chain;

src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
using System;
1+
using System;
22
using Titanium.Web.Proxy.Http;
33

44
namespace Titanium.Web.Proxy.EventArguments
55
{
66
/// <summary>
77
/// Class that wraps the multipart sent request arguments.
88
/// </summary>
9-
public class MultipartRequestPartSentEventArgs : EventArgs
9+
public class MultipartRequestPartSentEventArgs : ProxyEventArgsBase
1010
{
11-
internal MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers)
11+
internal MultipartRequestPartSentEventArgs(RequestStateBase state, string boundary, HeaderCollection headers)
12+
:base(state)
1213
{
1314
Boundary = boundary;
1415
Headers = headers;

src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ public class SessionEventArgs : SessionEventArgsBase
3434
/// <summary>
3535
/// Constructor to initialize the proxy
3636
/// </summary>
37-
internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, TcpClientConnection clientConnection, HttpClientStream clientStream, ConnectRequest? connectRequest, CancellationTokenSource cancellationTokenSource)
38-
: base(server, endPoint, clientConnection, clientStream, connectRequest, new Request(), cancellationTokenSource)
37+
internal SessionEventArgs(RequestStateBase state, ProxyEndPoint endPoint, TcpClientConnection clientConnection, HttpClientStream clientStream, ConnectRequest? connectRequest, CancellationTokenSource cancellationTokenSource)
38+
: base(state, endPoint, clientConnection, clientStream, connectRequest, new Request(), cancellationTokenSource)
3939
{
4040
}
4141

@@ -123,7 +123,7 @@ internal void OnMultipartRequestPartSent(ReadOnlySpan<char> boundary, HeaderColl
123123
{
124124
try
125125
{
126-
MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(boundary.ToString(), headers));
126+
MultipartRequestPartSent?.Invoke(this, new MultipartRequestPartSentEventArgs(this.State, boundary.ToString(), headers));
127127
}
128128
catch (Exception ex)
129129
{

src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,22 @@
1212

1313
namespace Titanium.Web.Proxy.EventArguments
1414
{
15+
public abstract class ProxyEventArgsBase : EventArgs
16+
{
17+
public readonly RequestStateBase State;
18+
public ProxyEventArgsBase(RequestStateBase state)
19+
{
20+
this.State = state;
21+
}
22+
23+
}
1524
/// <summary>
1625
/// Holds info related to a single proxy session (single request/response sequence).
1726
/// A proxy session is bounded to a single connection from client.
1827
/// A proxy session ends when client terminates connection to proxy
1928
/// or when server terminates connection from proxy.
2029
/// </summary>
21-
public abstract class SessionEventArgsBase : EventArgs, IDisposable
30+
public abstract class SessionEventArgsBase : ProxyEventArgsBase, IDisposable
2231
{
2332
private static bool isWindowsAuthenticationSupported => RunTime.IsWindows;
2433

@@ -49,9 +58,11 @@ public abstract class SessionEventArgsBase : EventArgs, IDisposable
4958
/// <summary>
5059
/// Initializes a new instance of the <see cref="SessionEventArgsBase" /> class.
5160
/// </summary>
52-
private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint,
61+
private protected SessionEventArgsBase(RequestStateBase state, ProxyEndPoint endPoint,
5362
TcpClientConnection clientConnection, HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource)
63+
:base(state)
5464
{
65+
var server = state.Server;
5566
BufferPool = server.BufferPool;
5667
ExceptionFunc = server.ExceptionFunc;
5768
TimeLine["Session Created"] = DateTime.Now;

src/Titanium.Web.Proxy/EventArguments/TunnelConnectEventArgs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ public class TunnelConnectSessionEventArgs : SessionEventArgsBase
1616
{
1717
private bool? isHttpsConnect;
1818

19-
internal TunnelConnectSessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, ConnectRequest connectRequest,
19+
internal TunnelConnectSessionEventArgs(RequestStateBase state, ProxyEndPoint endPoint, ConnectRequest connectRequest,
2020
TcpClientConnection clientConnection, HttpClientStream clientStream, CancellationTokenSource cancellationTokenSource)
21-
: base(server, endPoint, clientConnection, clientStream, connectRequest, connectRequest, cancellationTokenSource)
21+
: base(state, endPoint, clientConnection, clientStream, connectRequest, connectRequest, cancellationTokenSource)
2222
{
2323
}
2424

src/Titanium.Web.Proxy/ExplicitClientHandler.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@
2222

2323
namespace Titanium.Web.Proxy
2424
{
25-
public partial class ProxyServer
26-
{
25+
public partial class ProxyServerBase
26+
{
2727
/// <summary>
2828
/// This is called when client is aware of proxy
2929
/// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy
3030
/// </summary>
3131
/// <param name="endPoint">The explicit endpoint.</param>
3232
/// <param name="clientConnection">The client connection.</param>
3333
/// <returns>The task.</returns>
34-
private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection)
34+
internal async Task handleClient(ExplicitProxyEndPoint endPoint, RequestStateBase state)
3535
{
36+
TcpClientConnection clientConnection = state;
3637
var cancellationTokenSource = new CancellationTokenSource();
3738
var cancellationToken = cancellationTokenSource.Token;
3839

@@ -66,7 +67,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
6667

6768
await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);
6869

69-
connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest,
70+
connectArgs = new TunnelConnectSessionEventArgs(state, endPoint, connectRequest,
7071
clientConnection, clientStream, cancellationTokenSource);
7172
clientStream.DataRead += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count);
7273
clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count);
@@ -137,7 +138,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
137138
try
138139
{
139140
// todo: this is a hack, because Titanium does not support HTTP protocol changing currently
140-
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
141+
var connection = await tcpConnectionFactory.GetServerConnection(state, connectArgs,
141142
true, SslExtensions.Http2ProtocolAsList,
142143
true, cancellationToken);
143144

@@ -167,7 +168,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
167168
{
168169
// don't pass cancellation token here
169170
// it could cause floating server connections when client exits
170-
prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs,
171+
prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(state, connectArgs,
171172
true, null, false,
172173
CancellationToken.None);
173174
}
@@ -252,7 +253,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect
252253
// create new connection to server.
253254
// If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then
254255
// this connection should not be HTTPS.
255-
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
256+
var connection = await tcpConnectionFactory.GetServerConnection(state, connectArgs,
256257
true, SslExtensions.Http2ProtocolAsList,
257258
true, cancellationToken);
258259

@@ -329,7 +330,7 @@ await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool,
329330
throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received");
330331
}
331332

332-
var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs,
333+
var connection = await tcpConnectionFactory.GetServerConnection(state, connectArgs,
333334
true, SslExtensions.Http2ProtocolAsList,
334335
true, cancellationToken);
335336
try
@@ -338,7 +339,7 @@ await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool,
338339
var connectionPreface = new ReadOnlyMemory<byte>(Http2Helper.ConnectionPreface);
339340
await connection.Stream.WriteAsync(connectionPreface, cancellationToken);
340341
await Http2Helper.SendHttp2(clientStream, connection.Stream,
341-
() => new SessionEventArgs(this, endPoint, clientConnection, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource)
342+
() => new SessionEventArgs(state, endPoint, clientConnection, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource)
342343
{
343344
UserData = connectArgs?.UserData
344345
},
@@ -357,7 +358,7 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream,
357358
calledRequestHandler = true;
358359

359360
// Now create the request
360-
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask);
361+
await handleHttpSessionRequest(endPoint, state, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask);
361362
}
362363
catch (ProxyException e)
363364
{

src/Titanium.Web.Proxy/Helpers/ProxyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,11 @@ private static string convertRegexReservedChars(string rawString)
140140
}
141141

142142
ProxyProtocolType? protocolType = null;
143-
if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttp, StringComparison.InvariantCultureIgnoreCase))
143+
if (protocolTypeStr.Equals(Proxy.ProxyServerBase.UriSchemeHttp, StringComparison.InvariantCultureIgnoreCase))
144144
{
145145
protocolType = ProxyProtocolType.Http;
146146
}
147-
else if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttps,
147+
else if (protocolTypeStr.Equals(Proxy.ProxyServerBase.UriSchemeHttps,
148148
StringComparison.InvariantCultureIgnoreCase))
149149
{
150150
protocolType = ProxyProtocolType.Https;

src/Titanium.Web.Proxy/Helpers/SystemProxy.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ public override string ToString()
2121
switch (ProtocolType)
2222
{
2323
case ProxyProtocolType.Http:
24-
protocol = ProxyServer.UriSchemeHttp;
24+
protocol = ProxyServerBase.UriSchemeHttp;
2525
break;
2626
case ProxyProtocolType.Https:
27-
protocol = ProxyServer.UriSchemeHttps;
27+
protocol = ProxyServerBase.UriSchemeHttps;
2828
break;
2929
default:
3030
throw new Exception("Unsupported protocol type");

src/Titanium.Web.Proxy/Http/Request.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal ByteString RequestUriString8
3535
var scheme = getUriScheme(value);
3636
if (scheme.Length > 0)
3737
{
38-
IsHttps = scheme.Equals(ProxyServer.UriSchemeHttps8);
38+
IsHttps = scheme.Equals(ProxyServerBase.UriSchemeHttps8);
3939
}
4040
}
4141
}

src/Titanium.Web.Proxy/Http2/Http2Helper.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ private static async Task copyHttp2FrameAsync(Stream input, Stream output,
263263

264264
request.HttpVersion = HttpVersion.Version20;
265265
request.Method = method.GetString();
266-
request.IsHttps = headerListener.Scheme == ProxyServer.UriSchemeHttps;
266+
request.IsHttps = headerListener.Scheme == ProxyServerBase.UriSchemeHttps;
267267
request.Authority = headerListener.Authority;
268268
request.RequestUriString8 = path;
269269

@@ -592,14 +592,14 @@ public string Scheme
592592
{
593593
get
594594
{
595-
if (scheme.Equals(ProxyServer.UriSchemeHttp8))
595+
if (scheme.Equals(ProxyServerBase.UriSchemeHttp8))
596596
{
597-
return ProxyServer.UriSchemeHttp;
597+
return ProxyServerBase.UriSchemeHttp;
598598
}
599599

600-
if (scheme.Equals(ProxyServer.UriSchemeHttps8))
600+
if (scheme.Equals(ProxyServerBase.UriSchemeHttps8))
601601
{
602-
return ProxyServer.UriSchemeHttps;
602+
return ProxyServerBase.UriSchemeHttps;
603603
}
604604

605605
return string.Empty;

src/Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = tr
4242
/// </summary>
4343
public event AsyncEventHandler<TunnelConnectSessionEventArgs>? BeforeTunnelConnectResponse;
4444

45-
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
45+
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServerBase proxyServer,
4646
TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
4747
{
4848
if (BeforeTunnelConnectRequest != null)
@@ -51,7 +51,7 @@ internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
5151
}
5252
}
5353

54-
internal async Task InvokeBeforeTunnelConnectResponse(ProxyServer proxyServer,
54+
internal async Task InvokeBeforeTunnelConnectResponse(ProxyServerBase proxyServer,
5555
TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false)
5656
{
5757
if (BeforeTunnelConnectResponse != null)

0 commit comments

Comments
 (0)