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