Commit 46c59104 authored by Honfika's avatar Honfika

allow to get local endpoint in certificate validation/selection events #460

parent 4febcb05
......@@ -129,13 +129,21 @@ namespace Titanium.Web.Proxy.Examples.Basic
private async Task<IExternalProxy> onGetCustomUpStreamProxyFunc(SessionEventArgsBase arg)
{
// this is just to show the functionality, provided values are junk
return new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.9", Port = 9090, Password = "fake", UserName = "fake", UseDefaultCredentials = false };
return new ExternalProxy
{
BypassLocalhost = false, HostName = "127.0.0.9", Port = 9090, Password = "fake", UserName = "fake",
UseDefaultCredentials = false
};
}
private async Task<IExternalProxy> onCustomUpStreamProxyFailureFunc(SessionEventArgsBase arg)
{
// this is just to show the functionality, provided values are junk
return new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.10", Port = 9191, Password = "fake2", UserName = "fake2", UseDefaultCredentials = false };
return new ExternalProxy
{
BypassLocalhost = false, HostName = "127.0.0.10", Port = 9191, Password = "fake2", UserName = "fake2",
UseDefaultCredentials = false
};
}
private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
......
......@@ -12,17 +12,18 @@ namespace Titanium.Web.Proxy
/// Call back to override server certificate validation
/// </summary>
/// <param name="sender">The sender object.</param>
/// <param name="sessionArgs">The http session.</param>
/// <param name="certificate">The remote certificate.</param>
/// <param name="chain">The certificate chain.</param>
/// <param name="sslPolicyErrors">Ssl policy errors</param>
/// <returns>Return true if valid certificate.</returns>
internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
internal bool ValidateServerCertificate(object sender, SessionEventArgsBase sessionArgs, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
// if user callback is registered then do it
if (ServerCertificateValidationCallback != null)
{
var args = new CertificateValidationEventArgs(certificate, chain, sslPolicyErrors);
var args = new CertificateValidationEventArgs(sessionArgs, certificate, chain, sslPolicyErrors);
// why is the sender null?
ServerCertificateValidationCallback.InvokeAsync(this, args, ExceptionFunc).Wait();
......@@ -43,12 +44,13 @@ namespace Titanium.Web.Proxy
/// Call back to select client certificate used for mutual authentication
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="sessionArgs">The http session.</param>
/// <param name="targetHost">The remote hostname.</param>
/// <param name="localCertificates">Selected local certificates by SslStream.</param>
/// <param name="remoteCertificate">The remote certificate of server.</param>
/// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param>
/// <returns></returns>
internal X509Certificate? SelectClientCertificate(object sender, string targetHost,
internal X509Certificate? SelectClientCertificate(object sender, SessionEventArgsBase sessionArgs, string targetHost,
X509CertificateCollection localCertificates,
X509Certificate remoteCertificate, string[] acceptableIssuers)
{
......@@ -75,12 +77,8 @@ namespace Titanium.Web.Proxy
// If user call back is registered
if (ClientCertificateSelectionCallback != null)
{
var args = new CertificateSelectionEventArgs
var args = new CertificateSelectionEventArgs(sessionArgs, targetHost, localCertificates, remoteCertificate, acceptableIssuers)
{
TargetHost = targetHost,
LocalCertificates = localCertificates,
RemoteCertificate = remoteCertificate,
AcceptableIssuers = acceptableIssuers,
ClientCertificate = clientCertificate
};
......
......@@ -8,30 +8,40 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public class CertificateSelectionEventArgs : EventArgs
{
/// <summary>
/// The proxy server instance.
/// </summary>
public object? Sender { get; internal set; }
public CertificateSelectionEventArgs(SessionEventArgsBase session, string targetHost,
X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
{
Session = session;
TargetHost = targetHost;
LocalCertificates = localCertificates;
RemoteCertificate = remoteCertificate;
AcceptableIssuers = acceptableIssuers;
}
/// <value>
/// The session.
/// </value>
public SessionEventArgsBase Session { get; }
/// <summary>
/// The remote hostname to which we are authenticating against.
/// </summary>
public string? TargetHost { get; internal set; }
public string TargetHost { get; }
/// <summary>
/// Local certificates in store with matching issuers requested by TargetHost website.
/// </summary>
public X509CertificateCollection? LocalCertificates { get; internal set; }
public X509CertificateCollection LocalCertificates { get; }
/// <summary>
/// Certificate of the remote server.
/// </summary>
public X509Certificate? RemoteCertificate { get; internal set; }
public X509Certificate RemoteCertificate { get; }
/// <summary>
/// Acceptable issuers as listed by remote server.
/// </summary>
public string[]? AcceptableIssuers { get; internal set; }
public string[] AcceptableIssuers { get; }
/// <summary>
/// Client Certificate we selected. Set this value to override.
......
......@@ -10,13 +10,19 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
public class CertificateValidationEventArgs : EventArgs
{
public CertificateValidationEventArgs(X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
public CertificateValidationEventArgs(SessionEventArgsBase session, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
Session = session;
Certificate = certificate;
Chain = chain;
SslPolicyErrors = sslPolicyErrors;
}
/// <value>
/// The session.
/// </value>
public SessionEventArgsBase Session { get; }
/// <summary>
/// Server certificate.
/// </summary>
......
......@@ -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?
......@@ -36,8 +36,8 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, TcpClientConnection clientConnection, HttpClientStream clientStream, ConnectRequest? connectRequest, CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, clientConnection, clientStream, connectRequest, new Request(), cancellationTokenSource)
internal SessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, HttpClientStream clientStream, ConnectRequest? connectRequest, CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, clientStream, connectRequest, new Request(), cancellationTokenSource)
{
}
......
......@@ -29,7 +29,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary>
/// Holds a reference to client
/// </summary>
internal TcpClientConnection ClientConnection { get; }
internal TcpClientConnection ClientConnection => ClientStream.Connection;
internal HttpClientStream ClientStream { get; }
......@@ -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,
TcpClientConnection clientConnection, HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource)
HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource)
{
BufferPool = server.BufferPool;
ExceptionFunc = server.ExceptionFunc;
......@@ -58,9 +58,8 @@ namespace Titanium.Web.Proxy.EventArguments
CancellationTokenSource = cancellationTokenSource;
ClientConnection = clientConnection;
ClientStream = clientStream;
HttpClient = new HttpWebClient(connectRequest, request, new Lazy<int>(() => clientConnection.GetProcessId(endPoint)));
HttpClient = new HttpWebClient(connectRequest, request, new Lazy<int>(() => clientStream.Connection.GetProcessId(endPoint)));
LocalEndPoint = endPoint;
EnableWinAuth = server.EnableWinAuth && isWindowsAuthenticationSupported;
}
......
......@@ -17,8 +17,8 @@ namespace Titanium.Web.Proxy.EventArguments
private bool? isHttpsConnect;
internal TunnelConnectSessionEventArgs(ProxyServer server, ProxyEndPoint endPoint, ConnectRequest connectRequest,
TcpClientConnection clientConnection, HttpClientStream clientStream, CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, clientConnection, clientStream, connectRequest, connectRequest, cancellationTokenSource)
HttpClientStream clientStream, CancellationTokenSource cancellationTokenSource)
: base(server, endPoint, clientStream, connectRequest, connectRequest, cancellationTokenSource)
{
}
......
......@@ -36,7 +36,7 @@ namespace Titanium.Web.Proxy
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var clientStream = new HttpClientStream(clientConnection.GetStream(), BufferPool);
var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool);
Task<TcpServerConnection>? prefetchConnectionTask = null;
bool closeServerConnection = false;
......@@ -72,8 +72,7 @@ namespace Titanium.Web.Proxy
await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken);
connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest,
clientConnection, clientStream, cancellationTokenSource);
connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, clientStream, cancellationTokenSource);
clientStream.DataRead += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count);
clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count);
......@@ -137,7 +136,7 @@ namespace Titanium.Web.Proxy
if (decryptSsl && clientHelloInfo != null)
{
connectRequest.IsHttps = true; // todo: move this line to the previous "if"
clientConnection.SslProtocol = clientHelloInfo.SslProtocol;
clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol;
bool http2Supported = false;
......@@ -221,11 +220,11 @@ namespace Titanium.Web.Proxy
await sslStream.AuthenticateAsServerAsync(options, cancellationToken);
#if NETSTANDARD2_1
clientConnection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
clientStream.Connection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol;
#endif
// HTTPS server created - we can now decrypt the client's traffic
clientStream = new HttpClientStream(sslStream, BufferPool);
clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool);
sslStream = null; // clientStream was created, no need to keep SSL stream reference
clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count);
......@@ -362,13 +361,13 @@ namespace Titanium.Web.Proxy
var connectionPreface = new ReadOnlyMemory<byte>(Http2Helper.ConnectionPreface);
await connection.Stream.WriteAsync(connectionPreface, cancellationToken);
await Http2Helper.SendHttp2(clientStream, connection.Stream,
() => new SessionEventArgs(this, endPoint, clientConnection, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource)
() => new SessionEventArgs(this, endPoint, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource)
{
UserData = connectArgs?.UserData
},
async args => { await onBeforeRequest(args); },
async args => { await onBeforeResponse(args); },
connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc);
connectArgs.CancellationTokenSource, clientStream.Connection.Id, ExceptionFunc);
#endif
}
finally
......@@ -381,7 +380,7 @@ namespace Titanium.Web.Proxy
calledRequestHandler = true;
// Now create the request
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask);
await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask);
}
catch (ProxyException e)
{
......
......@@ -6,7 +6,7 @@ namespace Titanium.Web.Proxy.Extensions
{
internal static class StringExtensions
{
internal static bool EqualsIgnoreCase(this string str, string value)
internal static bool EqualsIgnoreCase(this string str, string? value)
{
return str.Equals(value, StringComparison.CurrentCultureIgnoreCase);
}
......@@ -16,12 +16,12 @@ namespace Titanium.Web.Proxy.Extensions
return str.Equals(value, StringComparison.CurrentCultureIgnoreCase);
}
internal static bool ContainsIgnoreCase(this string str, string value)
internal static bool ContainsIgnoreCase(this string str, string? value)
{
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(str, value, CompareOptions.IgnoreCase) >= 0;
}
internal static int IndexOfIgnoreCase(this string str, string value)
internal static int IndexOfIgnoreCase(this string str, string? value)
{
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(str, value, CompareOptions.IgnoreCase);
}
......
......@@ -3,15 +3,19 @@ using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Network.Tcp;
using Titanium.Web.Proxy.StreamExtended.BufferPool;
namespace Titanium.Web.Proxy.Helpers
{
internal sealed class HttpClientStream : HttpStream
{
internal HttpClientStream(Stream stream, IBufferPool bufferPool)
public TcpClientConnection Connection { get; }
internal HttpClientStream(TcpClientConnection connection, Stream stream, IBufferPool bufferPool)
: base(stream, bufferPool)
{
Connection = connection;
}
/// <summary>
......
......@@ -6,7 +6,7 @@ namespace Titanium.Web.Proxy.Helpers
internal partial class NativeMethods
{
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
internal static ConsoleEventDelegate? Handler;
[DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
......
......@@ -211,12 +211,7 @@ namespace Titanium.Web.Proxy.Helpers
if (protocolType.HasValue)
{
var endPointParts = tmp.Substring(equalsIndex + 1).Split(':');
return new HttpSystemProxyValue
{
HostName = endPointParts[0],
Port = int.Parse(endPointParts[1]),
ProtocolType = protocolType.Value
};
return new HttpSystemProxyValue(endPointParts[0], int.Parse(endPointParts[1]), protocolType.Value);
}
}
......
......@@ -9,11 +9,18 @@ namespace Titanium.Web.Proxy.Helpers
{
internal class HttpSystemProxyValue
{
internal string HostName { get; set; }
internal string HostName { get; }
internal int Port { get; set; }
internal int Port { get; }
internal ProxyProtocolType ProtocolType { get; set; }
internal ProxyProtocolType ProtocolType { get; }
public HttpSystemProxyValue(string hostName, int port, ProxyProtocolType protocolType)
{
HostName = hostName;
Port = port;
ProtocolType = protocolType;
}
public override string ToString()
{
......@@ -56,7 +63,7 @@ namespace Titanium.Web.Proxy.Helpers
AppDomain.CurrentDomain.ProcessExit += (o, args) => RestoreOriginalSettings();
if (Environment.UserInteractive && NativeMethods.GetConsoleWindow() != IntPtr.Zero)
{
NativeMethods.Handler = eventType =>
var handler = new NativeMethods.ConsoleEventDelegate(eventType =>
{
if (eventType != 2)
{
......@@ -65,10 +72,11 @@ namespace Titanium.Web.Proxy.Helpers
RestoreOriginalSettings();
return false;
};
});
NativeMethods.Handler = handler;
// On Console exit make sure we also exit the proxy
NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true);
NativeMethods.SetConsoleCtrlHandler(handler, true);
}
}
......@@ -95,22 +103,12 @@ namespace Titanium.Web.Proxy.Helpers
existingSystemProxyValues.RemoveAll(x => (protocolType & x.ProtocolType) != 0);
if ((protocolType & ProxyProtocolType.Http) != 0)
{
existingSystemProxyValues.Add(new HttpSystemProxyValue
{
HostName = hostname,
ProtocolType = ProxyProtocolType.Http,
Port = port
});
existingSystemProxyValues.Add(new HttpSystemProxyValue(hostname, port, ProxyProtocolType.Http));
}
if ((protocolType & ProxyProtocolType.Https) != 0)
{
existingSystemProxyValues.Add(new HttpSystemProxyValue
{
HostName = hostname,
ProtocolType = ProxyProtocolType.Https,
Port = port
});
existingSystemProxyValues.Add(new HttpSystemProxyValue(hostname, port, ProxyProtocolType.Https));
}
reg.DeleteValue(regAutoConfigUrl, false);
......
......@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Http
return String.AsSpan().EqualsIgnoreCase(value);
}
internal bool Equals(string value)
internal bool Equals(string? value)
{
return String.EqualsIgnoreCase(value);
}
......
......@@ -141,7 +141,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
}
Size -= removed.Size;
headerFields[tail++] = null;
headerFields[tail++] = null!;
if (tail == headerFields.Length)
{
tail = 0;
......@@ -157,7 +157,7 @@ namespace Titanium.Web.Proxy.Http2.Hpack
{
while (tail != head)
{
headerFields[tail++] = null;
headerFields[tail++] = null!;
if (tail == headerFields.Length)
{
tail = 0;
......
......@@ -705,7 +705,7 @@ namespace Titanium.Web.Proxy
throw new ArgumentNullException(nameof(endPoint));
}
if (ProxyEndPoints.Contains(endPoint) == false)
if (!ProxyEndPoints.Contains(endPoint))
{
throw new Exception("Cannot set endPoints not added to proxy as system proxy");
}
......@@ -739,7 +739,7 @@ namespace Titanium.Web.Proxy
try
{
// based on end point type call appropriate request handlers
tcpClient = endPoint.Listener.EndAcceptTcpClient(asyn);
tcpClient = endPoint.Listener!.EndAcceptTcpClient(asyn);
tcpClient.NoDelay = NoDelay;
}
catch (ObjectDisposedException)
......@@ -763,7 +763,7 @@ namespace Titanium.Web.Proxy
}
// Get the listener that handles the client request.
endPoint.Listener.BeginAcceptTcpClient(onAcceptConnection, endPoint);
endPoint.Listener!.BeginAcceptTcpClient(onAcceptConnection, endPoint);
}
......@@ -825,7 +825,7 @@ namespace Titanium.Web.Proxy
/// </summary>
private void quitListen(ProxyEndPoint endPoint)
{
endPoint.Listener.Stop();
endPoint.Listener!.Stop();
endPoint.Listener.Server.Dispose();
}
......
......@@ -29,13 +29,12 @@ namespace Titanium.Web.Proxy
/// client/server abruptly terminates connection or by normal HTTP termination.
/// </summary>
/// <param name="endPoint">The proxy endpoint.</param>
/// <param name="clientConnection">The client connection.</param>
/// <param name="clientStream">The client stream.</param>
/// <param name="cancellationTokenSource">The cancellation token source for this async task.</param>
/// <param name="connectArgs">The Connect request if this is a HTTPS request from explicit endpoint.</param>
/// <param name="prefetchConnectionTask">Prefetched server connection for current client using Connect/SNI headers.</param>
private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, TcpClientConnection clientConnection,
HttpClientStream clientStream, CancellationTokenSource cancellationTokenSource, TunnelConnectSessionEventArgs? connectArgs = null,
private async Task handleHttpSessionRequest(ProxyEndPoint endPoint, HttpClientStream clientStream,
CancellationTokenSource cancellationTokenSource, TunnelConnectSessionEventArgs? connectArgs = null,
Task<TcpServerConnection>? prefetchConnectionTask = null)
{
var connectRequest = connectArgs?.HttpClient.ConnectRequest;
......@@ -64,7 +63,7 @@ namespace Titanium.Web.Proxy
return;
}
var args = new SessionEventArgs(this, endPoint, clientConnection, clientStream, connectRequest, cancellationTokenSource)
var args = new SessionEventArgs(this, endPoint, clientStream, connectRequest, cancellationTokenSource)
{
UserData = connectArgs?.UserData
};
......@@ -163,7 +162,7 @@ namespace Titanium.Web.Proxy
// or when prefetch task has a unexpectedly different connection.
if (connection != null
&& (await tcpConnectionFactory.GetConnectionCacheKey(this, args,
clientConnection.NegotiatedApplicationProtocol)
clientStream.Connection.NegotiatedApplicationProtocol)
!= connection.CacheKey))
{
await tcpConnectionFactory.Release(connection);
......@@ -171,7 +170,7 @@ namespace Titanium.Web.Proxy
}
var result = await handleHttpSessionRequest(args, connection,
clientConnection.NegotiatedApplicationProtocol,
clientStream.Connection.NegotiatedApplicationProtocol,
cancellationToken, cancellationTokenSource);
// update connection to latest used
......
......@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var clientStream = new HttpClientStream(clientConnection.GetStream(), BufferPool);
var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool);
SslStream? sslStream = null;
......@@ -58,7 +58,7 @@ namespace Titanium.Web.Proxy
if (endPoint.DecryptSsl && args.DecryptSsl)
{
clientConnection.SslProtocol = clientHelloInfo.SslProtocol;
clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol;
// do client authentication using certificate
X509Certificate2? certificate = null;
......@@ -74,14 +74,13 @@ namespace Titanium.Web.Proxy
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
// HTTPS server created - we can now decrypt the client's traffic
clientStream = new HttpClientStream(sslStream, BufferPool);
clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool);
sslStream = null; // clientStream was created, no need to keep SSL stream reference
}
catch (Exception e)
{
var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false);
var session = new SessionEventArgs(this, endPoint, clientConnection, clientStream, null,
cancellationTokenSource);
var session = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource);
throw new ProxyConnectException(
$"Couldn't authenticate host '{httpsHostName}' with certificate '{certName}'.", e, session);
}
......@@ -89,9 +88,10 @@ namespace Titanium.Web.Proxy
}
else
{
var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port,
var sessionArgs = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource);
var connection = await tcpConnectionFactory.GetServerConnection(this, httpsHostName, endPoint.Port,
HttpHeader.VersionUnknown, false, null,
true, this, null, UpStreamEndPoint,
true, sessionArgs, UpStreamEndPoint,
UpStreamHttpsProxy, true, cancellationToken);
try
......@@ -131,7 +131,7 @@ namespace Titanium.Web.Proxy
// HTTPS server created - we can now decrypt the client's traffic
// Now create the request
await handleHttpSessionRequest(endPoint, clientConnection, clientStream, cancellationTokenSource);
await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource);
}
catch (ProxyException e)
{
......
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