From 877a5630865a76a40fc4876125513dd852c0a1e7 Mon Sep 17 00:00:00 2001 From: Honfika Date: Sun, 21 Jul 2019 11:33:13 +0200 Subject: [PATCH 01/11] fix for #556? --- .../Network/Tcp/TcpConnectionFactory.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 2f94734b8..2678a679c 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -184,13 +184,12 @@ internal async Task GetServerConnection(string remoteHostNa { if (cache.TryGetValue(cacheKey, out var existingConnections)) { + // +3 seconds for potential delay after getting connection + var cutOff = DateTime.Now.AddSeconds(-proxyServer.ConnectionTimeOutSeconds + 3); while (existingConnections.Count > 0) { if (existingConnections.TryDequeue(out var recentConnection)) { - //+3 seconds for potential delay after getting connection - var cutOff = DateTime.Now.AddSeconds(-1 * proxyServer.ConnectionTimeOutSeconds + 3); - if (recentConnection.LastAccess > cutOff && recentConnection.TcpClient.IsGoodConnection()) { @@ -490,8 +489,7 @@ private async Task clearOutdatedConnections() { if (queue.TryDequeue(out var connection)) { - if (!Server.EnableConnectionPool - || connection.LastAccess < cutOff) + if (!Server.EnableConnectionPool || connection.LastAccess < cutOff) { disposalBag.Add(connection); } @@ -508,8 +506,8 @@ private async Task clearOutdatedConnections() { await @lock.WaitAsync(); - //clear empty queues - var emptyKeys = cache.Where(x => x.Value.Count == 0).Select(x => x.Key).ToList(); + // clear empty queues + var emptyKeys = cache.ToArray().Where(x => x.Value.Count == 0).Select(x => x.Key); foreach (string key in emptyKeys) { cache.TryRemove(key, out _); From 3e7c8499ac80de6efbad9d0a2a130debeae39d12 Mon Sep 17 00:00:00 2001 From: Honfika Date: Sun, 21 Jul 2019 11:46:35 +0200 Subject: [PATCH 02/11] write to console enabled again in proxytestcontroller --- .../ProxyTestController.cs | 8 ++++---- .../Network/Certificate/WinCertificateMaker.cs | 2 +- src/Titanium.Web.Proxy/Network/CertificateManager.cs | 2 +- .../Network/Tcp/TcpConnectionFactory.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index 6f1e6446c..04681b95c 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -119,7 +119,7 @@ public void Stop() private async Task onBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) { string hostname = e.HttpClient.Request.RequestUri.Host; - //await writeToConsole("Tunnel to: " + hostname); + await writeToConsole("Tunnel to: " + hostname); if (hostname.Contains("dropbox.com")) { @@ -138,8 +138,8 @@ private Task onBeforeTunnelConnectResponse(object sender, TunnelConnectSessionEv // intecept & cancel redirect or update requests private async Task onRequest(object sender, SessionEventArgs e) { - //await writeToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount); - //await writeToConsole(e.HttpClient.Request.Url); + await writeToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount); + await writeToConsole(e.HttpClient.Request.Url); // store it in the UserData property // It can be a simple integer, Guid, or any type @@ -189,7 +189,7 @@ private async Task multipartRequestPartSent(object sender, MultipartRequestPartS private async Task onResponse(object sender, SessionEventArgs e) { - //await writeToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount); + await writeToConsole("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount); string ext = System.IO.Path.GetExtension(e.HttpClient.Request.RequestUri.AbsolutePath); diff --git a/src/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs b/src/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs index 39827ed70..faa2ca110 100644 --- a/src/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs +++ b/src/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs @@ -105,8 +105,8 @@ private X509Certificate2 makeCertificate(string sSubjectCN, bool isRoot, // KeyLength const int keyLength = 2048; - var graceTime = DateTime.Now.AddDays(graceDays); var now = DateTime.Now; + var graceTime = now.AddDays(graceDays); var certificate = makeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, hashAlgo, graceTime, now.AddDays(validDays), isRoot ? null : signingCert); return certificate; diff --git a/src/Titanium.Web.Proxy/Network/CertificateManager.cs b/src/Titanium.Web.Proxy/Network/CertificateManager.cs index ab4655f31..38e51fa6e 100644 --- a/src/Titanium.Web.Proxy/Network/CertificateManager.cs +++ b/src/Titanium.Web.Proxy/Network/CertificateManager.cs @@ -483,7 +483,7 @@ internal async void ClearIdleCertificates() var cancellationToken = clearCertificatesTokenSource.Token; while (!cancellationToken.IsCancellationRequested) { - var cutOff = DateTime.Now.AddMinutes(-1 * CertificateCacheTimeOutMinutes); + var cutOff = DateTime.Now.AddMinutes(-CertificateCacheTimeOutMinutes); var outdated = cachedCertificates.Where(x => x.Value.LastAccess < cutOff).ToList(); diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 2678a679c..50b5cc4c2 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -480,7 +480,7 @@ private async Task clearOutdatedConnections() { try { - var cutOff = DateTime.Now.AddSeconds(-1 * Server.ConnectionTimeOutSeconds); + var cutOff = DateTime.Now.AddSeconds(-Server.ConnectionTimeOutSeconds); foreach (var item in cache) { var queue = item.Value; From 1bce2480dd7e9fc8b98c8851020d284cad765ad6 Mon Sep 17 00:00:00 2001 From: Honfika Date: Sun, 21 Jul 2019 12:10:00 +0200 Subject: [PATCH 03/11] small cleanup --- .../StreamExtended/Network/CustomBufferedStream.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs index 766a4e0ec..2b6818f26 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs @@ -51,7 +51,7 @@ static CustomBufferedStream() try { var method = typeof(NetworkStream).GetMethod(nameof(Stream.ReadAsync), - new Type[] { typeof(byte[]), typeof(int), typeof(int), typeof(CancellationToken) }); + new[] { typeof(byte[]), typeof(int), typeof(int), typeof(CancellationToken) }); if (method != null && method.DeclaringType != typeof(Stream)) { networkStreamHack = false; @@ -684,8 +684,7 @@ public override int EndRead(IAsyncResult asyncResult) return ((TaskResult)asyncResult).Result; } - - + /// /// Fix the .net bug with SslStream slow WriteAsync /// https://github.com/justcoding121/Titanium-Web-Proxy/issues/495 @@ -709,6 +708,7 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As return vAsyncResult; } + public override void EndWrite(IAsyncResult asyncResult) { if (!networkStreamHack) From c7e34cc76e468fa6f1984b543a5f4341b7c91f52 Mon Sep 17 00:00:00 2001 From: Jehonathan Thomas Date: Wed, 7 Aug 2019 06:19:18 -0600 Subject: [PATCH 04/11] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 09c8f30ef..406be8a07 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ ## Titanium Web Proxy -### Note: This Project is no longer maintained. Any pull requests for fixes are welcome. - A lightweight HTTP(S) proxy server written in C#. ![Build Status](https://ci.appveyor.com/api/projects/status/p5vvtbpx9yp250ol?svg=true) [![Join the chat at https://gitter.im/Titanium-Web-Proxy/Lobby](https://badges.gitter.im/Titanium-Web-Proxy/Lobby.svg)](https://gitter.im/Titanium-Web-Proxy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) From a5f42d7f40a697657f8792e2abe51b7e32790bb3 Mon Sep 17 00:00:00 2001 From: Honfika Date: Mon, 12 Aug 2019 20:42:58 +0200 Subject: [PATCH 05/11] server connection hack: try to use tls1.0 when tls 1.2 fails --- .../Network/Tcp/TcpConnectionFactory.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 50b5cc4c2..146f9104b 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Net.Security; using System.Net.Sockets; +using System.Security.Authentication; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -266,6 +268,10 @@ private async Task createServerConnection(string remoteHost SslApplicationProtocol negotiatedApplicationProtocol = default; + bool retry = true; + var enabledSslProtocols = proxyServer.SupportedSslProtocols; + + retry: try { tcpClient = new TcpClient(upStreamEndPoint) @@ -365,7 +371,7 @@ private async Task createServerConnection(string remoteHost ApplicationProtocols = applicationProtocols, TargetHost = remoteHostName, ClientCertificates = null, - EnabledSslProtocols = proxyServer.SupportedSslProtocols, + EnabledSslProtocols = enabledSslProtocols, CertificateRevocationCheckMode = proxyServer.CheckCertificateRevocation }; await sslStream.AuthenticateAsClientAsync(options, cancellationToken); @@ -380,6 +386,12 @@ private async Task createServerConnection(string remoteHost } } + catch (IOException ex) when (ex.HResult == unchecked((int)0x80131620) && retry) + { + enabledSslProtocols = SslProtocols.Tls; + retry = false; + goto retry; + } catch (Exception) { stream?.Dispose(); From 98925e209de568d2628795e86b81d3bce9bd9e8c Mon Sep 17 00:00:00 2001 From: Honfika Date: Sat, 17 Aug 2019 11:52:05 +0200 Subject: [PATCH 06/11] Alpn adder streams removed (not used here, and still available in StremExtensions package) --- .../StreamExtended/ClientHelloInfo.cs | 32 +++- .../Network/ClientHelloAlpnAdderStream.cs | 138 ------------------ .../Network/ServerHelloAlpnAdderStream.cs | 138 ------------------ 3 files changed, 30 insertions(+), 278 deletions(-) delete mode 100644 src/Titanium.Web.Proxy/StreamExtended/Network/ClientHelloAlpnAdderStream.cs delete mode 100644 src/Titanium.Web.Proxy/StreamExtended/Network/ServerHelloAlpnAdderStream.cs diff --git a/src/Titanium.Web.Proxy/StreamExtended/ClientHelloInfo.cs b/src/Titanium.Web.Proxy/StreamExtended/ClientHelloInfo.cs index 2ad96ae94..cbbf68058 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/ClientHelloInfo.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/ClientHelloInfo.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using System.Security.Authentication; using System.Text; using Titanium.Web.Proxy.StreamExtended.Models; @@ -51,6 +52,33 @@ public DateTime Time public Dictionary Extensions { get; set; } + public SslProtocols SslProtocol + { + get + { + int major = MajorVersion; + int minor = MinorVersion; + if (major == 3 && minor == 3) + return SslProtocols.Tls12; + + if (major == 3 && minor == 2) + return SslProtocols.Tls11; + + if (major == 3 && minor == 1) + return SslProtocols.Tls; + +#pragma warning disable 618 + if (major == 3 && minor == 0) + return SslProtocols.Ssl3; + + if (major == 2 && minor == 0) + return SslProtocols.Ssl2; +#pragma warning restore 618 + + return SslProtocols.None; + } + } + private static string SslVersionToString(int major, int minor) { string str = "Unknown"; @@ -119,4 +147,4 @@ public override string ToString() return sb.ToString(); } } -} \ No newline at end of file +} diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/ClientHelloAlpnAdderStream.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/ClientHelloAlpnAdderStream.cs deleted file mode 100644 index fcb3db54e..000000000 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/ClientHelloAlpnAdderStream.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Diagnostics; -using System.IO; -using System.Threading; -using Titanium.Web.Proxy.StreamExtended.BufferPool; - -namespace Titanium.Web.Proxy.StreamExtended.Network -{ - public class ClientHelloAlpnAdderStream : Stream - { - private readonly CustomBufferedStream stream; - private readonly IBufferPool bufferPool; - - private bool called; - - public ClientHelloAlpnAdderStream(CustomBufferedStream stream, IBufferPool bufferPool) - { - this.stream = stream; - } - - public override void Flush() - { - stream.Flush(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - stream.SetLength(value); - } - - [DebuggerStepThrough] - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (called) - { - stream.Write(buffer, offset, count); - return; - } - - called = true; - var ms = new MemoryStream(buffer, offset, count); - - //this can be non async, because reads from a memory stream - var cts = new CancellationTokenSource(); - var clientHello = SslTools.PeekClientHello(new CustomBufferedStream(ms, bufferPool, (int)ms.Length), bufferPool, cts.Token).Result; - if (clientHello != null) - { - // 0x00 0x10: ALPN identifier - // 0x00 0x0e: length of ALPN data - // 0x00 0x0c: length of ALPN data again:) - var dataToAdd = new byte[] - { - 0x0, 0x10, 0x0, 0xE, 0x0, 0xC, - 2, (byte)'h', (byte)'2', - 8, (byte)'h', (byte)'t', (byte)'t', (byte)'p', (byte)'/', (byte)'1', (byte)'.', (byte)'1' - }; - - int newByteCount = clientHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length; - var buffer2 = new byte[buffer.Length + newByteCount]; - - for (int i = 0; i < buffer.Length; i++) - { - buffer2[i] = buffer[i]; - } - - //this is a hacky solution, but works - int length = (buffer[offset + 3] << 8) + buffer[offset + 4]; - length += newByteCount; - buffer2[offset + 3] = (byte)(length >> 8); - buffer2[offset + 4] = (byte)length; - - length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8]; - length += newByteCount; - buffer2[offset + 6] = (byte)(length >> 16); - buffer2[offset + 7] = (byte)(length >> 8); - buffer2[offset + 8] = (byte)length; - - int pos = offset + clientHello.EntensionsStartPosition; - int endPos = offset + clientHello.ClientHelloLength; - if (clientHello.Extensions != null) - { - // update ALPN length - length = (buffer[pos] << 8) + buffer[pos + 1]; - length += newByteCount; - buffer2[pos] = (byte)(length >> 8); - buffer2[pos + 1] = (byte)length; - } - else - { - // add ALPN length - length = dataToAdd.Length; - buffer2[pos] = (byte)(length >> 8); - buffer2[pos + 1] = (byte)length; - endPos += 2; - } - - for (int i = 0; i < dataToAdd.Length; i++) - { - buffer2[endPos + i] = dataToAdd[i]; - } - - // copy the reamining data if any - for (int i = clientHello.ClientHelloLength; i < count; i++) - { - buffer2[offset + newByteCount + i] = buffer[offset + i]; - } - - buffer = buffer2; - count += newByteCount; - } - - stream.Write(buffer, offset, count); - } - - public override bool CanRead => stream.CanRead; - - public override bool CanSeek => stream.CanSeek; - - public override bool CanWrite => stream.CanWrite; - - public override long Length => stream.Length; - - public override long Position - { - get => stream.Position; - set => stream.Position = value; - } - } -} \ No newline at end of file diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/ServerHelloAlpnAdderStream.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/ServerHelloAlpnAdderStream.cs deleted file mode 100644 index 26dda6c7f..000000000 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/ServerHelloAlpnAdderStream.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Diagnostics; -using System.IO; -using System.Threading; -using Titanium.Web.Proxy.StreamExtended.BufferPool; - -namespace Titanium.Web.Proxy.StreamExtended.Network -{ - public class ServerHelloAlpnAdderStream : Stream - { - private readonly IBufferPool bufferPool; - private readonly CustomBufferedStream stream; - - private bool called; - - public ServerHelloAlpnAdderStream(CustomBufferedStream stream, IBufferPool bufferPool) - { - this.bufferPool = bufferPool; - this.stream = stream; - } - - public override void Flush() - { - stream.Flush(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - stream.SetLength(value); - } - - [DebuggerStepThrough] - public override int Read(byte[] buffer, int offset, int count) - { - return stream.Read(buffer, offset, count); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (called) - { - stream.Write(buffer, offset, count); - return; - } - - called = true; - var ms = new MemoryStream(buffer, offset, count); - - //this can be non async, because reads from a memory stream - var cts = new CancellationTokenSource(); - var serverHello = SslTools.PeekServerHello(new CustomBufferedStream(ms, bufferPool, (int)ms.Length), bufferPool, cts.Token).Result; - if (serverHello != null) - { - // 0x00 0x10: ALPN identifier - // 0x00 0x0e: length of ALPN data - // 0x00 0x0c: length of ALPN data again:) - var dataToAdd = new byte[] - { - 0x0, 0x10, 0x0, 0x5, 0x0, 0x3, - 2, (byte)'h', (byte)'2' - }; - - int newByteCount = serverHello.Extensions == null ? dataToAdd.Length + 2 : dataToAdd.Length; - var buffer2 = new byte[buffer.Length + newByteCount]; - - for (int i = 0; i < buffer.Length; i++) - { - buffer2[i] = buffer[i]; - } - - //this is a hacky solution, but works - int length = (buffer[offset + 3] << 8) + buffer[offset + 4]; - length += newByteCount; - buffer2[offset + 3] = (byte)(length >> 8); - buffer2[offset + 4] = (byte)length; - - length = (buffer[offset + 6] << 16) + (buffer[offset + 7] << 8) + buffer[offset + 8]; - length += newByteCount; - buffer2[offset + 6] = (byte)(length >> 16); - buffer2[offset + 7] = (byte)(length >> 8); - buffer2[offset + 8] = (byte)length; - - int pos = offset + serverHello.EntensionsStartPosition; - int endPos = offset + serverHello.ServerHelloLength; - if (serverHello.Extensions != null) - { - // update ALPN length - length = (buffer[pos] << 8) + buffer[pos + 1]; - length += newByteCount; - buffer2[pos] = (byte)(length >> 8); - buffer2[pos + 1] = (byte)length; - } - else - { - // add ALPN length - length = dataToAdd.Length; - buffer2[pos] = (byte)(length >> 8); - buffer2[pos + 1] = (byte)length; - endPos += 2; - } - - for (int i = 0; i < dataToAdd.Length; i++) - { - buffer2[endPos + i] = dataToAdd[i]; - } - - // copy the reamining data if any - for (int i = serverHello.ServerHelloLength; i < count; i++) - { - buffer2[offset + newByteCount + i] = buffer[offset + i]; - } - - buffer = buffer2; - count += newByteCount; - } - - stream.Write(buffer, offset, count); - } - - public override bool CanRead => stream.CanRead; - - public override bool CanSeek => stream.CanSeek; - - public override bool CanWrite => stream.CanWrite; - - public override long Length => stream.Length; - - public override long Position - { - get => stream.Position; - set => stream.Position = value; - } - } -} \ No newline at end of file From 67c1e265a8ac7d0aa64c5fea2fff4ea30c93af3d Mon Sep 17 00:00:00 2001 From: Honfika Date: Sun, 18 Aug 2019 10:15:51 +0200 Subject: [PATCH 07/11] try to use the same ssl protocol which is used by the client connection --- .../ExplicitClientHandler.cs | 7 +++-- .../Network/Tcp/TcpClientConnection.cs | 3 ++ .../Network/Tcp/TcpConnectionFactory.cs | 30 +++++++++++-------- .../TransparentClientHandler.cs | 3 +- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index 9bd7d4fc2..86e771f2d 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -134,6 +134,7 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, if (decryptSsl && isClientHello) { + clientConnection.SslProtocol = clientHelloInfo.SslProtocol; connectRequest.RequestUri = new Uri("https://" + httpUrl); bool http2Supported = false; @@ -165,15 +166,15 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, IPAddress[] ipAddresses = null; try { - //make sure the host can be resolved before creating the prefetch task + // make sure the host can be resolved before creating the prefetch task ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host); } catch (SocketException) { } if (ipAddresses != null && ipAddresses.Length > 0) { - //don't pass cancellation token here - //it could cause floating server connections when client exits + // don't pass cancellation token here + // it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect: true, applicationProtocols: null, noCache: false, cancellationToken: CancellationToken.None); diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs index 0445d9398..fd0442aff 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpClientConnection.cs @@ -5,6 +5,7 @@ using System.Net.Security; #endif using System.Net.Sockets; +using System.Security.Authentication; using System.Threading.Tasks; using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Helpers; @@ -32,6 +33,8 @@ internal TcpClientConnection(ProxyServer proxyServer, TcpClient tcpClient) public EndPoint RemoteEndPoint => tcpClient.Client.RemoteEndPoint; + internal SslProtocols SslProtocol { get; set; } + internal SslApplicationProtocol NegotiatedApplicationProtocol { get; set; } private readonly TcpClient tcpClient; diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 146f9104b..ed7f8679f 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -48,12 +48,12 @@ internal TcpConnectionFactory(ProxyServer server) internal string GetConnectionCacheKey(string remoteHostName, int remotePort, bool isHttps, List applicationProtocols, - ProxyServer proxyServer, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy) + IPEndPoint upStreamEndPoint, ExternalProxy externalProxy) { - //http version is ignored since its an application level decision b/w HTTP 1.0/1.1 - //also when doing connect request MS Edge browser sends http 1.0 but uses 1.1 after server sends 1.1 its response. - //That can create cache miss for same server connection unnecessarily especially when prefetching with Connect. - //http version 2 is separated using applicationProtocols below. + // http version is ignored since its an application level decision b/w HTTP 1.0/1.1 + // also when doing connect request MS Edge browser sends http 1.0 but uses 1.1 after server sends 1.1 its response. + // That can create cache miss for same server connection unnecessarily especially when prefetching with Connect. + // http version 2 is separated using applicationProtocols below. var cacheKeyBuilder = new StringBuilder($"{remoteHostName}-{remotePort}-" + //when creating Tcp client isConnect won't matter $"{isHttps}-"); @@ -103,7 +103,7 @@ internal async Task GetConnectionCacheKey(ProxyServer server, SessionEve session.HttpClient.Request.RequestUri.Host, session.HttpClient.Request.RequestUri.Port, isHttps, applicationProtocols, - server, session.HttpClient.UpStreamEndPoint ?? server.UpStreamEndPoint, + session.HttpClient.UpStreamEndPoint ?? server.UpStreamEndPoint, customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy)); } @@ -111,9 +111,11 @@ internal async Task GetConnectionCacheKey(ProxyServer server, SessionEve /// /// Create a server connection. /// + /// The proxy server. /// The session event arguments. /// Is this a CONNECT request. /// + /// if set to true [no cache]. /// The cancellation token for this async task. /// internal Task GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect, @@ -131,9 +133,11 @@ internal Task GetServerConnection(ProxyServer server, Sessi /// /// Create a server connection. /// + /// The proxy server. /// The session event arguments. /// Is this a CONNECT request. /// + /// if set to true [no cache]. /// The cancellation token for this async task. /// internal async Task GetServerConnection(ProxyServer server, SessionEventArgsBase session, bool isConnect, @@ -168,6 +172,7 @@ internal async Task GetServerConnection(ProxyServer server, /// The list of HTTPS application level protocol to negotiate if needed. /// Is this a CONNECT request. /// The current ProxyServer instance. + /// The session. /// The local upstream endpoint to make request via. /// The external proxy to make request via. /// Not from cache/create new connection. @@ -178,9 +183,9 @@ internal async Task GetServerConnection(string remoteHostNa ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, bool noCache, CancellationToken cancellationToken) { + var sslProtocol = session.ProxyClient.Connection.SslProtocol; var cacheKey = GetConnectionCacheKey(remoteHostName, remotePort, - isHttps, applicationProtocols, - proxyServer, upStreamEndPoint, externalProxy); + isHttps, applicationProtocols, upStreamEndPoint, externalProxy); if (proxyServer.EnableConnectionPool && !noCache) { @@ -204,7 +209,7 @@ internal async Task GetServerConnection(string remoteHostNa } } - var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps, + var connection = await createServerConnection(remoteHostName, remotePort, httpVersion, isHttps, sslProtocol, applicationProtocols, isConnect, proxyServer, session, upStreamEndPoint, externalProxy, cancellationToken); connection.CacheKey = cacheKey; @@ -219,6 +224,7 @@ internal async Task GetServerConnection(string remoteHostNa /// The remote port. /// The http version to use. /// Is this a HTTPS request. + /// The SSL protocol. /// The list of HTTPS application level protocol to negotiate if needed. /// Is this a CONNECT request. /// The current ProxyServer instance. @@ -228,7 +234,7 @@ internal async Task GetServerConnection(string remoteHostNa /// The cancellation token for this async task. /// private async Task createServerConnection(string remoteHostName, int remotePort, - Version httpVersion, bool isHttps, List applicationProtocols, bool isConnect, + Version httpVersion, bool isHttps, SslProtocols sslProtocol, List applicationProtocols, bool isConnect, ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, CancellationToken cancellationToken) { @@ -269,7 +275,7 @@ private async Task createServerConnection(string remoteHost SslApplicationProtocol negotiatedApplicationProtocol = default; bool retry = true; - var enabledSslProtocols = proxyServer.SupportedSslProtocols; + var enabledSslProtocols = sslProtocol; retry: try @@ -386,7 +392,7 @@ private async Task createServerConnection(string remoteHost } } - catch (IOException ex) when (ex.HResult == unchecked((int)0x80131620) && retry) + catch (IOException ex) when (ex.HResult == unchecked((int)0x80131620) && retry && enabledSslProtocols >= SslProtocols.Tls11) { enabledSslProtocols = SslProtocols.Tls; retry = false; diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs index 4a63772d9..9af6814fe 100644 --- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs +++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs @@ -62,8 +62,9 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn if (endPoint.DecryptSsl && args.DecryptSsl) { + clientConnection.SslProtocol = clientHelloInfo.SslProtocol; - //do client authentication using certificate + // do client authentication using certificate X509Certificate2 certificate = null; try { From 2eed8cb0443a48901ea9502ce9a14da94eea914d Mon Sep 17 00:00:00 2001 From: Honfika Date: Sun, 18 Aug 2019 10:35:59 +0200 Subject: [PATCH 08/11] space before the commetns --- README.md | 140 +++++++++--------- .../ProxyTestController.cs | 2 +- .../EventArguments/SessionEventArgs.cs | 16 +- .../ExplicitClientHandler.cs | 3 +- .../Extensions/TcpExtensions.cs | 4 +- src/Titanium.Web.Proxy/Helpers/Network.cs | 2 +- src/Titanium.Web.Proxy/Helpers/RunTime.cs | 2 +- src/Titanium.Web.Proxy/Network/RetryPolicy.cs | 8 +- .../Network/Tcp/TcpClientConnection.cs | 6 +- .../Network/Tcp/TcpConnectionFactory.cs | 14 +- .../Network/Tcp/TcpServerConnection.cs | 6 +- .../Network/WinAuth/Security/Common.cs | 2 +- src/Titanium.Web.Proxy/ProxyServer.cs | 10 +- src/Titanium.Web.Proxy/RequestHandler.cs | 18 +-- src/Titanium.Web.Proxy/ResponseHandler.cs | 8 +- .../StreamExtended/Network/CopyStream.cs | 4 +- .../Network/CustomBufferedStream.cs | 22 +-- .../StreamExtended/SslExtensions.cs | 56 +++---- .../StreamExtended/SslTools.cs | 20 +-- .../Setup/TestServer.cs | 2 +- 20 files changed, 174 insertions(+), 171 deletions(-) diff --git a/README.md b/README.md index 406be8a07..8ef34d3ce 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ For stable releases on [stable branch](https://github.com/justcoding121/Titanium Supports * .Net Standard 2.0 or above - * .Net Framework 4.5 or above + * .Net Framework 4.6.1 or above ### Development environment @@ -55,11 +55,11 @@ Setup HTTP proxy: ```csharp var proxyServer = new ProxyServer(); -//locally trust root certificate used by this proxy +// locally trust root certificate used by this proxy proxyServer.CertificateManager.TrustRootCertificate = true; -//optionally set the Certificate Engine -//Under Mono only BouncyCastle will be supported +// optionally set the Certificate Engine +// Under Mono only BouncyCastle will be supported //proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle; proxyServer.BeforeRequest += OnRequest; @@ -70,28 +70,28 @@ proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) { -//Use self-issued generic certificate on all https requests -//Optimizes performance by not creating a certificate for each https-enabled domain -//Useful when certificate trust is not required by proxy clients -//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") + // Use self-issued generic certificate on all https requests + // Optimizes performance by not creating a certificate for each https-enabled domain + // Useful when certificate trust is not required by proxy clients + //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") }; -//Fired when a CONNECT request is received +// Fired when a CONNECT request is received explicitEndPoint.BeforeTunnelConnect += OnBeforeTunnelConnect; -//An explicit endpoint is where the client knows about the existence of a proxy -//So client sends request in a proxy friendly manner +// An explicit endpoint is where the client knows about the existence of a proxy +// So client sends request in a proxy friendly manner proxyServer.AddEndPoint(explicitEndPoint); proxyServer.Start(); -//Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy) -//A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS -//to send data to this endPoint +// Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy) +// A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS +// to send data to this endPoint var transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true) { - //Generic Certificate hostname to use - //when SNI is disabled by client - GenericCertificateName = "google.com" + // Generic Certificate hostname to use + // when SNI is disabled by client + GenericCertificateName = "google.com" }; proxyServer.AddEndPoint(transparentEndPoint); @@ -103,14 +103,14 @@ foreach (var endPoint in proxyServer.ProxyEndPoints) Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); -//Only explicit proxies can be set as system proxy! +// Only explicit proxies can be set as system proxy! proxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint); -//wait here (You can use something else as a wait function, I am using this as a demo) +// wait here (You can use something else as a wait function, I am using this as a demo) Console.Read(); -//Unsubscribe & Quit +// Unsubscribe & Quit explicitEndPoint.BeforeTunnelConnect -= OnBeforeTunnelConnect; proxyServer.BeforeRequest -= OnRequest; proxyServer.BeforeResponse -= OnResponse; @@ -118,11 +118,11 @@ proxyServer.ServerCertificateValidationCallback -= OnCertificateValidation; proxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection; proxyServer.Stop(); - + ``` Sample request and response event handlers -```csharp +```csharp private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) { @@ -130,9 +130,9 @@ private async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSess if (hostname.Contains("dropbox.com")) { - //Exclude Https addresses you don't want to proxy - //Useful for clients that use certificate pinning - //for example dropbox.com + // Exclude Https addresses you don't want to proxy + // Useful for clients that use certificate pinning + // for example dropbox.com e.DecryptSsl = false; } } @@ -141,88 +141,88 @@ public async Task OnRequest(object sender, SessionEventArgs e) { Console.WriteLine(e.HttpClient.Request.Url); - ////read request headers + // read request headers var requestHeaders = e.HttpClient.Request.RequestHeaders; var method = e.HttpClient.Request.Method.ToUpper(); if ((method == "POST" || method == "PUT" || method == "PATCH")) { - //Get/Set request body bytes - byte[] bodyBytes = await e.GetRequestBody(); - await e.SetRequestBody(bodyBytes); - - //Get/Set request body as string - string bodyString = await e.GetRequestBodyAsString(); - await e.SetRequestBodyString(bodyString); - - //store request - //so that you can find it from response handler - e.UserData = e.HttpClient.Request; + // Get/Set request body bytes + byte[] bodyBytes = await e.GetRequestBody(); + await e.SetRequestBody(bodyBytes); + + // Get/Set request body as string + string bodyString = await e.GetRequestBodyAsString(); + await e.SetRequestBodyString(bodyString); + + // store request + // so that you can find it from response handler + e.UserData = e.HttpClient.Request; } - //To cancel a request with a custom HTML content - //Filter URL + // To cancel a request with a custom HTML content + // Filter URL if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("google.com")) { - e.Ok("" + - "

" + - "Website Blocked" + - "

" + - "

Blocked by titanium web proxy.

" + - "" + - ""); + e.Ok("" + + "

" + + "Website Blocked" + + "

" + + "

Blocked by titanium web proxy.

" + + "" + + ""); } - //Redirect example + + // Redirect example if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains("wikipedia.org")) { - e.Redirect("https://www.paypal.com"); + e.Redirect("https://www.paypal.com"); } } -//Modify response +// Modify response public async Task OnResponse(object sender, SessionEventArgs e) { - //read response headers + // read response headers var responseHeaders = e.HttpClient.Response.ResponseHeaders; //if (!e.ProxySession.Request.Host.Equals("medeczane.sgk.gov.tr")) return; if (e.HttpClient.Request.Method == "GET" || e.HttpClient.Request.Method == "POST") { - if (e.HttpClient.Response.ResponseStatusCode == "200") - { - if (e.HttpClient.Response.ContentType!=null && e.HttpClient.Response.ContentType.Trim().ToLower().Contains("text/html")) - { - byte[] bodyBytes = await e.GetResponseBody(); - await e.SetResponseBody(bodyBytes); - - string body = await e.GetResponseBodyAsString(); - await e.SetResponseBodyString(body); - } - } + if (e.HttpClient.Response.ResponseStatusCode == "200") + { + if (e.HttpClient.Response.ContentType!=null && e.HttpClient.Response.ContentType.Trim().ToLower().Contains("text/html")) + { + byte[] bodyBytes = await e.GetResponseBody(); + await e.SetResponseBody(bodyBytes); + + string body = await e.GetResponseBodyAsString(); + await e.SetResponseBodyString(body); + } + } } - if(e.UserData!=null) + if (e.UserData!=null) { - //access request from UserData property where we stored it in RequestHandler - var request = (Request)e.UserData; + // access request from UserData property where we stored it in RequestHandler + var request = (Request)e.UserData; } - } -/// Allows overriding default certificate validation logic +// Allows overriding default certificate validation logic public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) { - //set IsValid to true/false based on Certificate Errors + // set IsValid to true/false based on Certificate Errors if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None) - e.IsValid = true; + e.IsValid = true; return Task.FromResult(0); } -/// Allows overriding default client certificate selection logic during mutual authentication +// Allows overriding default client certificate selection logic during mutual authentication public Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e) { - //set e.clientCertificate to override + // set e.clientCertificate to override return Task.FromResult(0); } ``` diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index 04681b95c..dbd2dbd2d 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -193,7 +193,7 @@ private async Task onResponse(object sender, SessionEventArgs e) string ext = System.IO.Path.GetExtension(e.HttpClient.Request.RequestUri.AbsolutePath); - //access user data set in request to do something with it + // access user data set in request to do something with it //var userData = e.HttpClient.UserData as CustomUserData; //if (ext == ".gif" || ext == ".png" || ext == ".jpg") diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 325f90c63..2e14f37f9 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -615,36 +615,36 @@ public void Redirect(string url, bool closeServerConnection = false) /// Close the server connection used by request if any? public void Respond(Response response, bool closeServerConnection = false) { - //request already send/ready to be sent. + // request already send/ready to be sent. if (HttpClient.Request.Locked) { - //response already received from server and ready to be sent to client. + // response already received from server and ready to be sent to client. if (HttpClient.Response.Locked) { throw new Exception("You cannot call this function after response is sent to the client."); } - //cleanup original response. + // cleanup original response. if (closeServerConnection) { - //no need to cleanup original connection. - //it will be closed any way. + // no need to cleanup original connection. + // it will be closed any way. TerminateServerConnection(); } response.SetOriginalHeaders(HttpClient.Response); - //response already received from server but not yet ready to sent to client. + // response already received from server but not yet ready to sent to client. HttpClient.Response = response; HttpClient.Response.Locked = true; } - //request not yet sent/not yet ready to be sent. + // request not yet sent/not yet ready to be sent. else { HttpClient.Request.Locked = true; HttpClient.Request.CancelRequest = true; - //set new response. + // set new response. HttpClient.Response = response; HttpClient.Response.Locked = true; } diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index 86e771f2d..496b01f0f 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -152,7 +152,8 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; - //release connection back to pool instead of closing when connection pool is enabled. + + // release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } catch (Exception) diff --git a/src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs b/src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs index e39a05f8a..21fc392db 100644 --- a/src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs +++ b/src/Titanium.Web.Proxy/Extensions/TcpExtensions.cs @@ -50,11 +50,11 @@ internal static bool IsGoodConnection(this TcpClient client) socket.Blocking = false; socket.Send(tmp, 0, 0); - //Connected. + // Connected. } catch { - //Should we let 10035 == WSAEWOULDBLOCK as valid connection? + // Should we let 10035 == WSAEWOULDBLOCK as valid connection? return false; } finally diff --git a/src/Titanium.Web.Proxy/Helpers/Network.cs b/src/Titanium.Web.Proxy/Helpers/Network.cs index 80c6b15d4..5d4afc291 100644 --- a/src/Titanium.Web.Proxy/Helpers/Network.cs +++ b/src/Titanium.Web.Proxy/Helpers/Network.cs @@ -41,7 +41,7 @@ internal static bool IsLocalIpAddress(string hostName) return true; } - //if hostname matches local host name + // if hostname matches local host name if (hostName.Equals(localhostName, StringComparison.OrdinalIgnoreCase)) { return true; diff --git a/src/Titanium.Web.Proxy/Helpers/RunTime.cs b/src/Titanium.Web.Proxy/Helpers/RunTime.cs index c116f00e5..b2d1e9847 100644 --- a/src/Titanium.Web.Proxy/Helpers/RunTime.cs +++ b/src/Titanium.Web.Proxy/Helpers/RunTime.cs @@ -42,7 +42,7 @@ public static class RunTime public static bool IsMac => isRunningOnMac; - //https://github.com/qmatteoq/DesktopBridgeHelpers/blob/master/DesktopBridge.Helpers/Helpers.cs + // https://github.com/qmatteoq/DesktopBridgeHelpers/blob/master/DesktopBridge.Helpers/Helpers.cs private class UwpHelper { const long APPMODEL_ERROR_NO_PACKAGE = 15700L; diff --git a/src/Titanium.Web.Proxy/Network/RetryPolicy.cs b/src/Titanium.Web.Proxy/Network/RetryPolicy.cs index 9300d7b7f..fa77e3b9d 100644 --- a/src/Titanium.Web.Proxy/Network/RetryPolicy.cs +++ b/src/Titanium.Web.Proxy/Network/RetryPolicy.cs @@ -37,10 +37,10 @@ internal async Task ExecuteAsync(Func ExecuteAsync(Func { - //delay calling tcp connection close() - //so that client have enough time to call close first. - //This way we can push tcp Time_Wait to client side when possible. + // delay calling tcp connection close() + // so that client have enough time to call close first. + // This way we can push tcp Time_Wait to client side when possible. await Task.Delay(1000); proxyServer.UpdateClientConnectionCount(false); tcpClient.CloseSocket(); diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index ed7f8679f..2efe31535 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -25,15 +25,15 @@ namespace Titanium.Web.Proxy.Network.Tcp internal class TcpConnectionFactory : IDisposable { - //Tcp server connection pool cache + // Tcp server connection pool cache private readonly ConcurrentDictionary> cache = new ConcurrentDictionary>(); - //Tcp connections waiting to be disposed by cleanup task + // Tcp connections waiting to be disposed by cleanup task private readonly ConcurrentBag disposalBag = new ConcurrentBag(); - //cache object race operations lock + // cache object race operations lock private readonly SemaphoreSlim @lock = new SemaphoreSlim(1); private volatile bool runCleanUpTask = true; @@ -55,7 +55,7 @@ internal string GetConnectionCacheKey(string remoteHostName, int remotePort, // That can create cache miss for same server connection unnecessarily especially when prefetching with Connect. // http version 2 is separated using applicationProtocols below. var cacheKeyBuilder = new StringBuilder($"{remoteHostName}-{remotePort}-" + - //when creating Tcp client isConnect won't matter + // when creating Tcp client isConnect won't matter $"{isHttps}-"); if (applicationProtocols != null) { @@ -238,7 +238,7 @@ private async Task createServerConnection(string remoteHost ProxyServer proxyServer, SessionEventArgsBase session, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy, CancellationToken cancellationToken) { - //deny connection to proxy end points to avoid infinite connection loop. + // deny connection to proxy end points to avoid infinite connection loop. if (Server.ProxyEndPoints.Any(x => x.Port == remotePort) && NetworkHelper.IsLocalIpAddress(remoteHostName)) { @@ -288,7 +288,7 @@ private async Task createServerConnection(string remoteHost LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds) }; - //linux has a bug with socket reuse in .net core. + // linux has a bug with socket reuse in .net core. if (proxyServer.ReuseSocket && RunTime.IsWindows) { tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); @@ -550,7 +550,7 @@ private async Task clearOutdatedConnections() } finally { - //cleanup every 3 seconds by default + // cleanup every 3 seconds by default await Task.Delay(1000 * 3); } diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs index d14de3482..93633b92e 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpServerConnection.cs @@ -90,9 +90,9 @@ public void Dispose() { Task.Run(async () => { - //delay calling tcp connection close() - //so that server have enough time to call close first. - //This way we can push tcp Time_Wait to server side when possible. + // delay calling tcp connection close() + // so that server have enough time to call close first. + // This way we can push tcp Time_Wait to server side when possible. await Task.Delay(1000); proxyServer.UpdateServerConnectionCount(false); Stream?.Dispose(); diff --git a/src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs b/src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs index 3ffbc0108..ab7c1c247 100644 --- a/src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs +++ b/src/Titanium.Web.Proxy/Network/WinAuth/Security/Common.cs @@ -210,7 +210,7 @@ public void Dispose() // int cbBuffer; // int BufferType; // pvBuffer; - //What we need to do here is to grab a hold of the pvBuffer allocate by the individual + // What we need to do here is to grab a hold of the pvBuffer allocate by the individual // SecBuffer and release it... int currentOffset = index * Marshal.SizeOf(typeof(Buffer)); var secBufferpvBuffer = Marshal.ReadIntPtr(pBuffers, diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs index c7c0bf5fd..864838cd9 100644 --- a/src/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -122,7 +122,9 @@ public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, ///
private SystemProxyManager systemProxySettingsManager { get; } - //Number of exception retries when connection pool is enabled. + /// + /// Number of exception retries when connection pool is enabled. + /// private int retries => EnableConnectionPool ? MaxCachedConnections : 0; /// @@ -660,7 +662,7 @@ private void listen(ProxyEndPoint endPoint) { endPoint.Listener = new TcpListener(endPoint.IpAddress, endPoint.Port); - //linux/macOS has a bug with socket reuse in .net core. + // linux/macOS has a bug with socket reuse in .net core. if (ReuseSocket && RunTime.IsWindows) { endPoint.Listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); @@ -871,13 +873,13 @@ internal void UpdateServerConnectionCount(bool increment) /// internal async Task InvokeConnectionCreateEvent(TcpClient client, bool isClientConnection) { - //client connection created + // client connection created if (isClientConnection && OnClientConnectionCreate != null) { await OnClientConnectionCreate.InvokeAsync(this, client, ExceptionFunc); } - //server connection created + // server connection created if (!isClientConnection && OnServerConnectionCreate != null) { await OnServerConnectionCreate.InvokeAsync(this, client, ExceptionFunc); diff --git a/src/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs index e2d3628dd..ab3701577 100644 --- a/src/Titanium.Web.Proxy/RequestHandler.cs +++ b/src/Titanium.Web.Proxy/RequestHandler.cs @@ -163,7 +163,7 @@ await clientStreamWriter.WriteResponseAsync(args.HttpClient.Response, await args.GetRequestBody(cancellationToken); } - //we need this to syphon out data from connection if API user changes them. + // we need this to syphon out data from connection if API user changes them. request.SetOriginalHeaders(); args.TimeLine["Request Received"] = DateTime.Now; @@ -191,7 +191,7 @@ await clientStreamWriter.WriteResponseAsync(args.HttpClient.Response, continue; } - //If prefetch task is available. + // If prefetch task is available. if (connection == null && prefetchTask != null) { try @@ -226,11 +226,11 @@ await clientStreamWriter.WriteResponseAsync(args.HttpClient.Response, clientConnection.NegotiatedApplicationProtocol, cancellationToken, cancellationTokenSource); - //update connection to latest used + // update connection to latest used connection = result.LatestConnection; closeServerConnection = !result.Continue; - //throw if exception happened + // throw if exception happened if (!result.IsSuccess) { throw result.Exception; @@ -241,7 +241,7 @@ await clientStreamWriter.WriteResponseAsync(args.HttpClient.Response, return; } - //user requested + // user requested if (args.HttpClient.CloseServerConnection) { closeServerConnection = true; @@ -304,13 +304,13 @@ private async Task handleHttpSessionRequest(string httpCmd, Session TcpServerConnection serverConnection, SslApplicationProtocol sslApplicationProtocol, CancellationToken cancellationToken, CancellationTokenSource cancellationTokenSource) { - //a connection generator task with captured parameters via closure. + // a connection generator task with captured parameters via closure. Func> generator = () => tcpConnectionFactory.GetServerConnection(this, args, isConnect: false, applicationProtocol: sslApplicationProtocol, noCache: false, cancellationToken: cancellationToken); - //for connection pool, retry fails until cache is exhausted. + // for connection pool, retry fails until cache is exhausted. return await retryPolicy().ExecuteAsync(async (connection) => { args.TimeLine["Connection Ready"] = DateTime.Now; @@ -390,12 +390,12 @@ private void prepareRequestHeaders(HeaderCollection requestHeaders) { var supportedAcceptEncoding = new List(); - //only allow proxy supported compressions + // only allow proxy supported compressions supportedAcceptEncoding.AddRange(acceptEncoding.Split(',') .Select(x => x.Trim()) .Where(x => ProxyConstants.ProxySupportedCompressions.Contains(x))); - //uncompressed is always supported by proxy + // uncompressed is always supported by proxy supportedAcceptEncoding.Add("identity"); requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs index 39156f637..8e8794730 100644 --- a/src/Titanium.Web.Proxy/ResponseHandler.cs +++ b/src/Titanium.Web.Proxy/ResponseHandler.cs @@ -51,8 +51,8 @@ private async Task handleHttpSessionResponse(SessionEventArgs args) } } - //save original values so that if user changes them - //we can still use original values when syphoning out data from attached tcp connection. + // save original values so that if user changes them + // we can still use original values when syphoning out data from attached tcp connection. response.SetOriginalHeaders(); // if user requested call back then do it @@ -66,10 +66,10 @@ private async Task handleHttpSessionResponse(SessionEventArgs args) var clientStreamWriter = args.ProxyClient.ClientStreamWriter; - //user set custom response by ignoring original response from server. + // user set custom response by ignoring original response from server. if (response.Locked) { - //write custom user response with body and return. + // write custom user response with body and return. await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken); if (args.HttpClient.Connection != null diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs index 08f6bf40c..025509014 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs @@ -63,7 +63,7 @@ public Task PeekBytesAsync(byte[] buffer, int offset, int index, int size, public void Flush() { - //send out the current data from from the buffer + // send out the current data from from the buffer if (bufferLength > 0) { writer.Write(buffer, 0, bufferLength); @@ -73,7 +73,7 @@ public void Flush() public async Task FlushAsync(CancellationToken cancellationToken = default) { - //send out the current data from from the buffer + // send out the current data from from the buffer if (bufferLength > 0) { await writer.WriteAsync(buffer, 0, bufferLength, cancellationToken); diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs index 2b6818f26..32e6e8879 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs @@ -257,13 +257,13 @@ public async Task PeekByteAsync(int index, CancellationToken cancellationTo await FillBufferAsync(cancellationToken); } - //When index is greater than the buffer size + // When index is greater than the buffer size if (streamBuffer.Length <= index) { throw new Exception("Requested Peek index exceeds the buffer size. Consider increasing the buffer size."); } - //When index is greater than the buffer size + // When index is greater than the buffer size if (Available <= index) { return -1; @@ -287,7 +287,7 @@ public async Task PeekBytesAsync(byte[] buffer, int offset, int index, int await FillBufferAsync(cancellationToken); } - //When index is greater than the buffer size + // When index is greater than the buffer size if (streamBuffer.Length <= (index + size)) { throw new Exception("Requested Peek index and size exceeds the buffer size. Consider increasing the buffer size."); @@ -477,8 +477,8 @@ public bool FillBuffer() if (bufferLength > 0) { - //normally we fill the buffer only when it is empty, but sometimes we need more data - //move the remaining data to the beginning of the buffer + // normally we fill the buffer only when it is empty, but sometimes we need more data + // move the remaining data to the beginning of the buffer Buffer.BlockCopy(streamBuffer, bufferPos, streamBuffer, 0, bufferLength); } @@ -521,8 +521,8 @@ public async Task FillBufferAsync(CancellationToken cancellationToken = de if (bufferLength > 0) { - //normally we fill the buffer only when it is empty, but sometimes we need more data - //move the remaining data to the beginning of the buffer + // normally we fill the buffer only when it is empty, but sometimes we need more data + // move the remaining data to the beginning of the buffer Buffer.BlockCopy(streamBuffer, bufferPos, streamBuffer, 0, bufferLength); } @@ -586,7 +586,7 @@ internal static async Task ReadLineInternalAsync(ICustomStreamReader rea byte newChar = reader.ReadByteFromBuffer(); buffer[bufferDataLength] = newChar; - //if new line + // if new line if (newChar == '\n') { if (lastChar == '\r') @@ -599,7 +599,7 @@ internal static async Task ReadLineInternalAsync(ICustomStreamReader rea bufferDataLength++; - //store last char for new line comparison + // store last char for new line comparison lastChar = newChar; if (bufferDataLength == buffer.Length) @@ -663,8 +663,8 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, Asy vAsyncResult.ContinueWith(pAsyncResult => { - //use TaskExtended to pass State as AsyncObject - //callback will call EndRead (otherwise, it will block) + // use TaskExtended to pass State as AsyncObject + // callback will call EndRead (otherwise, it will block) callback?.Invoke(new TaskResult(pAsyncResult, state)); }); diff --git a/src/Titanium.Web.Proxy/StreamExtended/SslExtensions.cs b/src/Titanium.Web.Proxy/StreamExtended/SslExtensions.cs index c6569fdad..f8d129033 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/SslExtensions.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/SslExtensions.cs @@ -16,7 +16,7 @@ internal static SslExtension GetExtension(int value, byte[] data, int position) private static string GetExtensionData(int value, byte[] data) { - //https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml + // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml switch (value) { case 0: @@ -59,8 +59,8 @@ private static string GetExtensionData(int value, byte[] data) private static string GetSupportedGroup(byte[] data) { - //https://datatracker.ietf.org/doc/draft-ietf-tls-rfc4492bis/?include_text=1 - List list = new List(); + // https://datatracker.ietf.org/doc/draft-ietf-tls-rfc4492bis/?include_text=1 + var list = new List(); if (data.Length < 2) { return string.Empty; @@ -73,70 +73,70 @@ private static string GetSupportedGroup(byte[] data) switch (namedCurve) { case 1: - list.Add("sect163k1 [0x1]"); //deprecated + list.Add("sect163k1 [0x1]"); // deprecated break; case 2: - list.Add("sect163r1 [0x2]"); //deprecated + list.Add("sect163r1 [0x2]"); // deprecated break; case 3: - list.Add("sect163r2 [0x3]"); //deprecated + list.Add("sect163r2 [0x3]"); // deprecated break; case 4: - list.Add("sect193r1 [0x4]"); //deprecated + list.Add("sect193r1 [0x4]"); // deprecated break; case 5: - list.Add("sect193r2 [0x5]"); //deprecated + list.Add("sect193r2 [0x5]"); // deprecated break; case 6: - list.Add("sect233k1 [0x6]"); //deprecated + list.Add("sect233k1 [0x6]"); // deprecated break; case 7: - list.Add("sect233r1 [0x7]"); //deprecated + list.Add("sect233r1 [0x7]"); // deprecated break; case 8: - list.Add("sect239k1 [0x8]"); //deprecated + list.Add("sect239k1 [0x8]"); // deprecated break; case 9: - list.Add("sect283k1 [0x9]"); //deprecated + list.Add("sect283k1 [0x9]"); // deprecated break; case 10: - list.Add("sect283r1 [0xA]"); //deprecated + list.Add("sect283r1 [0xA]"); // deprecated break; case 11: - list.Add("sect409k1 [0xB]"); //deprecated + list.Add("sect409k1 [0xB]"); // deprecated break; case 12: - list.Add("sect409r1 [0xC]"); //deprecated + list.Add("sect409r1 [0xC]"); // deprecated break; case 13: - list.Add("sect571k1 [0xD]"); //deprecated + list.Add("sect571k1 [0xD]"); // deprecated break; case 14: - list.Add("sect571r1 [0xE]"); //deprecated + list.Add("sect571r1 [0xE]"); // deprecated break; case 15: - list.Add("secp160k1 [0xF]"); //deprecated + list.Add("secp160k1 [0xF]"); // deprecated break; case 16: - list.Add("secp160r1 [0x10]"); //deprecated + list.Add("secp160r1 [0x10]"); // deprecated break; case 17: - list.Add("secp160r2 [0x11]"); //deprecated + list.Add("secp160r2 [0x11]"); // deprecated break; case 18: - list.Add("secp192k1 [0x12]"); //deprecated + list.Add("secp192k1 [0x12]"); // deprecated break; case 19: - list.Add("secp192r1 [0x13]"); //deprecated + list.Add("secp192r1 [0x13]"); // deprecated break; case 20: - list.Add("secp224k1 [0x14]"); //deprecated + list.Add("secp224k1 [0x14]"); // deprecated break; case 21: - list.Add("secp224r1 [0x15]"); //deprecated + list.Add("secp224r1 [0x15]"); // deprecated break; case 22: - list.Add("secp256k1 [0x16]"); //deprecated + list.Add("secp256k1 [0x16]"); // deprecated break; case 23: list.Add("secp256r1 [0x17]"); @@ -178,10 +178,10 @@ private static string GetSupportedGroup(byte[] data) list.Add("ffdhe8192 [0x0104]"); break; case 65281: - list.Add("arbitrary_explicit_prime_curves [0xFF01]"); //deprecated + list.Add("arbitrary_explicit_prime_curves [0xFF01]"); // deprecated break; case 65282: - list.Add("arbitrary_explicit_char2_curves [0xFF02]"); //deprecated + list.Add("arbitrary_explicit_char2_curves [0xFF02]"); // deprecated break; default: list.Add($"unknown [0x{namedCurve:X4}]"); @@ -318,7 +318,7 @@ private static string GetApplicationLayerProtocolNegotiation(byte[] data) private static string GetExtensionName(int value) { - //https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml + // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml switch (value) { case 0: diff --git a/src/Titanium.Web.Proxy/StreamExtended/SslTools.cs b/src/Titanium.Web.Proxy/StreamExtended/SslTools.cs index fbe6471b5..5b6b87167 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/SslTools.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/SslTools.cs @@ -34,8 +34,8 @@ public static async Task IsClientHello(CustomBufferedStream stream, IBuffe /// public static async Task PeekClientHello(CustomBufferedStream clientStream, IBufferPool bufferPool, CancellationToken cancellationToken = default) { - //detects the HTTPS ClientHello message as it is described in the following url: - //https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format + // detects the HTTPS ClientHello message as it is described in the following url: + // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format int recordType = await clientStream.PeekByteAsync(0, cancellationToken); if (recordType == -1) @@ -45,7 +45,7 @@ public static async Task PeekClientHello(CustomBufferedStream c if ((recordType & 0x80) == 0x80) { - //SSL 2 + // SSL 2 var peekStream = new CustomBufferedPeekStream(clientStream, bufferPool, 1); // length value + minimum length @@ -105,14 +105,14 @@ public static async Task PeekClientHello(CustomBufferedStream c { var peekStream = new CustomBufferedPeekStream(clientStream, bufferPool, 1); - //should contain at least 43 bytes + // should contain at least 43 bytes // 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length if (!await peekStream.EnsureBufferLength(43, cancellationToken)) { return null; } - //SSL 3.0 or TLS 1.0, 1.1 and 1.2 + // SSL 3.0 or TLS 1.0, 1.1 and 1.2 int majorVersion = peekStream.ReadByte(); int minorVersion = peekStream.ReadByte(); @@ -220,8 +220,8 @@ public static async Task IsServerHello(CustomBufferedStream stream, IBuffe /// public static async Task PeekServerHello(CustomBufferedStream serverStream, IBufferPool bufferPool, CancellationToken cancellationToken = default) { - //detects the HTTPS ClientHello message as it is described in the following url: - //https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format + // detects the HTTPS ClientHello message as it is described in the following url: + // https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format int recordType = await serverStream.PeekByteAsync(0, cancellationToken); if (recordType == -1) @@ -231,7 +231,7 @@ public static async Task PeekServerHello(CustomBufferedStream s if ((recordType & 0x80) == 0x80) { - //SSL 2 + // SSL 2 // not tested. SSL2 is deprecated var peekStream = new CustomBufferedPeekStream(serverStream, bufferPool, 1); @@ -284,14 +284,14 @@ public static async Task PeekServerHello(CustomBufferedStream s { var peekStream = new CustomBufferedPeekStream(serverStream, bufferPool, 1); - //should contain at least 43 bytes + // should contain at least 43 bytes // 2 version + 2 length + 1 type + 3 length(?) + 2 version + 32 random + 1 sessionid length if (!await peekStream.EnsureBufferLength(43, cancellationToken)) { return null; } - //SSL 3.0 or TLS 1.0, 1.1 and 1.2 + // SSL 3.0 or TLS 1.0, 1.1 and 1.2 int majorVersion = peekStream.ReadByte(); int minorVersion = peekStream.ReadByte(); diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs index de4e6b9c9..c0eacbe23 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs @@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.IntegrationTests.Setup { - //set up a kestrel test server + // set up a kestrel test server public class TestServer : IDisposable { public string ListeningHttpUrl => $"http://localhost:{HttpListeningPort}"; From 180da0d17876813ac79641a509a66a91dc2a5d0e Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Sun, 18 Aug 2019 08:37:24 +0000 Subject: [PATCH 09/11] API documentation update by build server --- docs/api/Titanium.Web.Proxy.ProxyServer.html | 104 +++++++++---------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.ProxyServer.html b/docs/api/Titanium.Web.Proxy.ProxyServer.html index 6b938cbd6..23e0df9f2 100644 --- a/docs/api/Titanium.Web.Proxy.ProxyServer.html +++ b/docs/api/Titanium.Web.Proxy.ProxyServer.html @@ -243,7 +243,7 @@

Properties Improve this Doc - View Source + View Source

BufferPool

@@ -276,7 +276,7 @@
Property Value
Improve this Doc - View Source + View Source

BufferSize

@@ -308,7 +308,7 @@
Property Value
Improve this Doc - View Source + View Source

CertificateManager

@@ -339,7 +339,7 @@
Property Value
Improve this Doc - View Source + View Source

CheckCertificateRevocation

@@ -371,7 +371,7 @@
Property Value
Improve this Doc - View Source + View Source

ClientConnectionCount

@@ -402,7 +402,7 @@
Property Value
Improve this Doc - View Source + View Source

ConnectionTimeOutSeconds

@@ -435,7 +435,7 @@
Property Value
Improve this Doc - View Source + View Source

Enable100ContinueBehaviour

@@ -468,7 +468,7 @@
Property Value
Improve this Doc - View Source + View Source

EnableConnectionPool

@@ -500,7 +500,7 @@
Property Value
Improve this Doc - View Source + View Source

EnableHttp2

@@ -536,7 +536,7 @@
Property Value
Improve this Doc - View Source + View Source

EnableTcpServerConnectionPrefetch

@@ -572,7 +572,7 @@
Property Value
Improve this Doc - View Source + View Source

EnableWinAuth

@@ -607,7 +607,7 @@
Property Value
Improve this Doc - View Source + View Source

ExceptionFunc

@@ -638,7 +638,7 @@
Property Value
Improve this Doc - View Source + View Source

ForwardToUpstreamGateway

@@ -670,7 +670,7 @@
Property Value
Improve this Doc - View Source + View Source

GetCustomUpStreamProxyFunc

@@ -702,7 +702,7 @@
Property Value
Improve this Doc - View Source + View Source

MaxCachedConnections

@@ -735,7 +735,7 @@
Property Value
Improve this Doc - View Source + View Source

NoDelay

@@ -767,7 +767,7 @@
Property Value
Improve this Doc - View Source + View Source

ProxyAuthenticationRealm

@@ -798,7 +798,7 @@
Property Value
Improve this Doc - View Source + View Source

ProxyAuthenticationSchemes

@@ -830,7 +830,7 @@
Property Value
Improve this Doc - View Source + View Source

ProxyBasicAuthenticateFunc

@@ -863,7 +863,7 @@
Property Value
Improve this Doc - View Source + View Source

ProxyEndPoints

@@ -894,7 +894,7 @@
Property Value
Improve this Doc - View Source + View Source

ProxyRunning

@@ -925,7 +925,7 @@
Property Value
Improve this Doc - View Source + View Source

ProxySchemeAuthenticateFunc

@@ -958,7 +958,7 @@
Property Value
Improve this Doc - View Source + View Source

ReuseSocket

@@ -990,7 +990,7 @@
Property Value
Improve this Doc - View Source + View Source

ServerConnectionCount

@@ -1021,7 +1021,7 @@
Property Value
Improve this Doc - View Source + View Source

SupportedSslProtocols

@@ -1052,7 +1052,7 @@
Property Value
Improve this Doc - View Source + View Source

TcpTimeWaitSeconds

@@ -1084,7 +1084,7 @@
Property Value
Improve this Doc - View Source + View Source

ThreadPoolWorkerThread

@@ -1115,7 +1115,7 @@
Property Value
Improve this Doc - View Source + View Source

UpStreamEndPoint

@@ -1147,7 +1147,7 @@
Property Value
Improve this Doc - View Source + View Source

UpStreamHttpProxy

@@ -1178,7 +1178,7 @@
Property Value
Improve this Doc - View Source + View Source

UpStreamHttpsProxy

@@ -1211,7 +1211,7 @@

Methods Improve this Doc - View Source + View Source

AddEndPoint(ProxyEndPoint)

@@ -1245,7 +1245,7 @@
Parameters
Improve this Doc - View Source + View Source

DisableAllSystemProxies()

@@ -1261,7 +1261,7 @@
Declaration
Improve this Doc - View Source + View Source

DisableSystemHttpProxy()

@@ -1277,7 +1277,7 @@
Declaration
Improve this Doc - View Source + View Source

DisableSystemHttpsProxy()

@@ -1293,7 +1293,7 @@
Declaration
Improve this Doc - View Source + View Source

DisableSystemProxy(ProxyProtocolType)

@@ -1326,7 +1326,7 @@
Parameters
Improve this Doc - View Source + View Source

Dispose()

@@ -1342,7 +1342,7 @@
Declaration
Improve this Doc - View Source + View Source

RemoveEndPoint(ProxyEndPoint)

@@ -1377,7 +1377,7 @@
Parameters
Improve this Doc - View Source + View Source

RestoreOriginalProxySettings()

@@ -1393,7 +1393,7 @@
Declaration
Improve this Doc - View Source + View Source

SetAsSystemHttpProxy(ExplicitProxyEndPoint)

@@ -1427,7 +1427,7 @@
Parameters
Improve this Doc - View Source + View Source

SetAsSystemHttpsProxy(ExplicitProxyEndPoint)

@@ -1461,7 +1461,7 @@
Parameters
Improve this Doc - View Source + View Source

SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType)

@@ -1501,7 +1501,7 @@
Parameters
Improve this Doc - View Source + View Source

Start()

@@ -1517,7 +1517,7 @@
Declaration
Improve this Doc - View Source + View Source

Stop()

@@ -1535,7 +1535,7 @@

Events Improve this Doc - View Source + View Source

AfterResponse

Intercept after response event from server.

@@ -1565,7 +1565,7 @@
Event Type
Improve this Doc - View Source + View Source

BeforeRequest

Intercept request event to server.

@@ -1595,7 +1595,7 @@
Event Type
Improve this Doc - View Source + View Source

BeforeResponse

Intercept response event from server.

@@ -1625,7 +1625,7 @@
Event Type
Improve this Doc - View Source + View Source

ClientCertificateSelectionCallback

Event to override client certificate selection during mutual SSL authentication.

@@ -1655,7 +1655,7 @@
Event Type
Improve this Doc - View Source + View Source

ClientConnectionCountChanged

Event occurs when client connection count changed.

@@ -1685,7 +1685,7 @@
Event Type
Improve this Doc - View Source + View Source

OnClientConnectionCreate

Customize TcpClient used for client connection upon create.

@@ -1715,7 +1715,7 @@
Event Type
Improve this Doc - View Source + View Source

OnServerConnectionCreate

Customize TcpClient used for server connection upon create.

@@ -1745,7 +1745,7 @@
Event Type
Improve this Doc - View Source + View Source

ServerCertificateValidationCallback

Event to override the default verification logic of remote SSL certificate received during authentication.

@@ -1775,7 +1775,7 @@
Event Type
Improve this Doc - View Source + View Source

ServerConnectionCountChanged

Event occurs when server connection count changed.

From 5d23aeffc6bed33a302234459c4d9f2f7fcd610e Mon Sep 17 00:00:00 2001 From: Honfika Date: Mon, 26 Aug 2019 19:17:32 +0200 Subject: [PATCH 10/11] IPv6 fix --- .../Network/Tcp/TcpConnectionFactory.cs | 36 +++++++++++-------- src/Titanium.Web.Proxy/ProxyServer.cs | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 2efe31535..258513b0c 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -71,7 +71,6 @@ internal string GetConnectionCacheKey(string remoteHostName, int remotePort, cacheKeyBuilder.Append(externalProxy != null ? $"{externalProxy.GetCacheKey()}-" : string.Empty); return cacheKeyBuilder.ToString(); - } /// @@ -280,20 +279,6 @@ private async Task createServerConnection(string remoteHost retry: try { - tcpClient = new TcpClient(upStreamEndPoint) - { - NoDelay = proxyServer.NoDelay, - ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000, - SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000, - LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds) - }; - - // linux has a bug with socket reuse in .net core. - if (proxyServer.ReuseSocket && RunTime.IsWindows) - { - tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - } - var hostname = useUpstreamProxy ? externalProxy.HostName : remoteHostName; var port = useUpstreamProxy ? externalProxy.Port : remotePort; @@ -312,6 +297,27 @@ private async Task createServerConnection(string remoteHost { try { + var ipAddress = ipAddresses[i]; + if (upStreamEndPoint == null) + { + tcpClient = new TcpClient(ipAddress.AddressFamily); + } + else + { + tcpClient = new TcpClient(upStreamEndPoint); + } + + tcpClient.NoDelay = proxyServer.NoDelay; + tcpClient.ReceiveTimeout = proxyServer.ConnectionTimeOutSeconds * 1000; + tcpClient.SendTimeout = proxyServer.ConnectionTimeOutSeconds * 1000; + tcpClient.LingerState = new LingerOption(true, proxyServer.TcpTimeWaitSeconds); + + // linux has a bug with socket reuse in .net core. + if (proxyServer.ReuseSocket && RunTime.IsWindows) + { + tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + } + await tcpClient.ConnectAsync(ipAddresses[i], port); break; } diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs index 864838cd9..26148e835 100644 --- a/src/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -268,7 +268,7 @@ public ProxyServer(string rootCertificateName, string rootCertificateIssuerName, /// Local adapter/NIC endpoint where proxy makes request via. /// Defaults via any IP addresses of this machine. /// - public IPEndPoint UpStreamEndPoint { get; set; } = new IPEndPoint(IPAddress.Any, 0); + public IPEndPoint UpStreamEndPoint { get; set; } /// /// A list of IpAddress and port this proxy is listening to. From ba428196aa2be2c45fb68bdc9cb82cfe5eb238ee Mon Sep 17 00:00:00 2001 From: Honfika Date: Fri, 30 Aug 2019 13:16:41 +0200 Subject: [PATCH 11/11] Fix for #593 and #596 --- .../Extensions/UriExtensions.cs | 16 ++++++++++++++++ src/Titanium.Web.Proxy/Http/HttpWebClient.cs | 3 +-- .../Network/Tcp/TcpConnectionFactory.cs | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/Titanium.Web.Proxy/Extensions/UriExtensions.cs diff --git a/src/Titanium.Web.Proxy/Extensions/UriExtensions.cs b/src/Titanium.Web.Proxy/Extensions/UriExtensions.cs new file mode 100644 index 000000000..5003c622f --- /dev/null +++ b/src/Titanium.Web.Proxy/Extensions/UriExtensions.cs @@ -0,0 +1,16 @@ +using System; + +namespace Titanium.Web.Proxy.Extensions +{ + internal static class UriExtensions + { + internal static string GetOriginalPathAndQuery(this Uri uri) + { + string leftPart = uri.GetLeftPart(UriPartial.Authority); + if (uri.OriginalString.StartsWith(leftPart)) + return uri.OriginalString.Substring(leftPart.Length); + + return uri.IsWellFormedOriginalString() ? uri.PathAndQuery : uri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); + } + } +} diff --git a/src/Titanium.Web.Proxy/Http/HttpWebClient.cs b/src/Titanium.Web.Proxy/Http/HttpWebClient.cs index 1fba12e5c..92b18d858 100644 --- a/src/Titanium.Web.Proxy/Http/HttpWebClient.cs +++ b/src/Titanium.Web.Proxy/Http/HttpWebClient.cs @@ -104,8 +104,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTranspar } else { - var uri = Request.RequestUri; - url = uri.IsWellFormedOriginalString() ? uri.PathAndQuery : uri.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped); + url = Request.RequestUri.GetOriginalPathAndQuery(); } // prepare the request & headers diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 258513b0c..1548164c2 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -327,6 +327,9 @@ private async Task createServerConnection(string remoteHost { throw new Exception($"Could not establish connection to {hostname}", e); } + + // dispose the current TcpClient and try the next address + tcpClient?.Dispose(); } }