From 045ec22fa277baf7afe4669148f2c114269481a3 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 10 Dec 2019 21:03:37 +0100 Subject: [PATCH 1/8] NetworkStream read cancellation hack --- .../EventArguments/EmptyProxyEventArgs.cs | 12 ++++ .../EventArguments/SessionEventArgs.cs | 2 +- .../ExplicitClientHandler.cs | 15 +++-- .../Extensions/StreamExtensions.cs | 6 +- .../Helpers/HttpClientStream.cs | 4 +- .../Helpers/HttpServerStream.cs | 4 +- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 63 ++++++++++++------- .../Network/Tcp/TcpConnectionFactory.cs | 4 +- src/Titanium.Web.Proxy/RequestHandler.cs | 2 +- .../TransparentClientHandler.cs | 11 ++-- 10 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs diff --git a/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs new file mode 100644 index 000000000..81d95d8c0 --- /dev/null +++ b/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs @@ -0,0 +1,12 @@ +using System; +using Titanium.Web.Proxy.Network.Tcp; + +namespace Titanium.Web.Proxy.EventArguments +{ + public class EmptyProxyEventArgs : ProxyEventArgsBase + { + internal EmptyProxyEventArgs(TcpClientConnection clientConnection) : base(clientConnection) + { + } + } +} diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index c55803426..f39658fe7 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -190,7 +190,7 @@ private async Task readResponseBodyAsync(CancellationToken cancellationToken) private async Task readBodyAsync(bool isRequest, CancellationToken cancellationToken) { using var bodyStream = new MemoryStream(); - using var writer = new HttpStream(bodyStream, BufferPool); + using var writer = new HttpStream(bodyStream, BufferPool, cancellationToken); if (isRequest) { diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index ac0baa6c5..a17597e0c 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -33,14 +33,12 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool); + var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); Task? prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; - SslStream? sslStream = null; - try { TunnelConnectSessionEventArgs? connectArgs = null; @@ -191,6 +189,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect } X509Certificate2? certificate = null; + SslStream? sslStream = null; try { sslStream = new SslStream(clientStream, false); @@ -221,7 +220,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect #endif // HTTPS server created - we can now decrypt the client's traffic - clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool); + clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count); @@ -229,6 +228,8 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect } catch (Exception e) { + sslStream?.Dispose(); + var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs); @@ -401,12 +402,16 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream, } finally { + if (!cancellationTokenSource.IsCancellationRequested) + { + cancellationTokenSource.Cancel(); + } + if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } - sslStream?.Dispose(); clientStream.Dispose(); } } diff --git a/src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs b/src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs index 4e3c5ecfa..bbe52459b 100644 --- a/src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs +++ b/src/Titanium.Web.Proxy/Extensions/StreamExtensions.cs @@ -42,8 +42,8 @@ internal static async Task CopyToAsync(this Stream input, Stream output, Action< { // cancellation is not working on Socket ReadAsync // https://github.com/dotnet/corefx/issues/15033 - int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None) - .withCancellation(cancellationToken); + int num = await input.ReadAsync(buffer, 0, buffer.Length, cancellationToken) + .WithCancellation(cancellationToken); int bytesRead; if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested) { @@ -62,7 +62,7 @@ internal static async Task CopyToAsync(this Stream input, Stream output, Action< } } - private static async Task withCancellation(this Task task, CancellationToken cancellationToken) where T : struct + internal static async Task WithCancellation(this Task task, CancellationToken cancellationToken) where T : struct { var tcs = new TaskCompletionSource(); using (cancellationToken.Register(s => ((TaskCompletionSource)s).TrySetResult(true), tcs)) diff --git a/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs index e816ba44f..594635e36 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs @@ -12,8 +12,8 @@ internal sealed class HttpClientStream : HttpStream { public TcpClientConnection Connection { get; } - internal HttpClientStream(TcpClientConnection connection, Stream stream, IBufferPool bufferPool) - : base(stream, bufferPool) + internal HttpClientStream(TcpClientConnection connection, Stream stream, IBufferPool bufferPool, CancellationToken cancellationToken) + : base(stream, bufferPool, cancellationToken) { Connection = connection; } diff --git a/src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs index df2b94c9a..a4f08f99f 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs @@ -10,8 +10,8 @@ namespace Titanium.Web.Proxy.Helpers { internal sealed class HttpServerStream : HttpStream { - internal HttpServerStream(Stream stream, IBufferPool bufferPool) - : base(stream, bufferPool) + internal HttpServerStream(Stream stream, IBufferPool bufferPool, CancellationToken cancellationToken) + : base(stream, bufferPool, cancellationToken) { } diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 82505dd85..3b9aeecc7 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Titanium.Web.Proxy.Compression; using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Shared; @@ -19,7 +20,7 @@ namespace Titanium.Web.Proxy.Helpers { internal class HttpStream : Stream, IHttpStreamWriter, IHttpStreamReader, IPeekStream { - private readonly bool swallowException; + private readonly bool isNetworkStream; private readonly bool leaveOpen; private readonly byte[] streamBuffer; @@ -37,6 +38,7 @@ internal class HttpStream : Stream, IHttpStreamWriter, IHttpStreamReader, IPeekS private bool closedRead; private readonly IBufferPool bufferPool; + private readonly CancellationToken cancellationToken; public event EventHandler? DataRead; @@ -71,18 +73,20 @@ static HttpStream() /// /// The base stream. /// Bufferpool. + /// The cancellation token. /// to leave the stream open after disposing the object; otherwise, . - internal HttpStream(Stream baseStream, IBufferPool bufferPool, bool leaveOpen = false) + internal HttpStream(Stream baseStream, IBufferPool bufferPool, CancellationToken cancellationToken, bool leaveOpen = false) { if (baseStream is NetworkStream) { - swallowException = true; + isNetworkStream = true; } this.baseStream = baseStream; this.leaveOpen = leaveOpen; streamBuffer = bufferPool.GetBuffer(); this.bufferPool = bufferPool; + this.cancellationToken = cancellationToken; } /// @@ -102,7 +106,7 @@ public override void Flush() catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -181,7 +185,7 @@ public override void Write(byte[] buffer, int offset, int count) catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -228,7 +232,7 @@ public override async Task FlushAsync(CancellationToken cancellationToken) catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -450,7 +454,7 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -476,7 +480,7 @@ public override void WriteByte(byte value) catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } finally @@ -609,7 +613,7 @@ public bool FillBuffer() } catch { - if (!swallowException) + if (!isNetworkStream) throw; } finally @@ -655,7 +659,13 @@ public async ValueTask FillBufferAsync(CancellationToken cancellationToken bool result = false; try { - int readBytes = await baseStream.ReadAsync(streamBuffer, bufferLength, bytesToRead, cancellationToken); + var readTask = baseStream.ReadAsync(streamBuffer, bufferLength, bytesToRead, cancellationToken); + if (isNetworkStream) + { + readTask = readTask.WithCancellation(cancellationToken); + } + + int readBytes = await readTask; result = readBytes > 0; if (result) { @@ -663,9 +673,14 @@ public async ValueTask FillBufferAsync(CancellationToken cancellationToken bufferLength += readBytes; } } + catch (ObjectDisposedException) + { + if (!isNetworkStream) + throw; + } catch { - if (!swallowException) + if (!isNetworkStream) throw; } finally @@ -771,14 +786,18 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, Asy return base.BeginRead(buffer, offset, count, callback, state); } - var vAsyncResult = this.ReadAsync(buffer, offset, count); + var vAsyncResult = this.ReadAsync(buffer, offset, count, cancellationToken); + if (isNetworkStream) + { + vAsyncResult = vAsyncResult.WithCancellation(cancellationToken); + } vAsyncResult.ContinueWith(pAsyncResult => { // use TaskExtended to pass State as AsyncObject // callback will call EndRead (otherwise, it will block) callback?.Invoke(new TaskResult(pAsyncResult, state)); - }); + }, cancellationToken); return vAsyncResult; } @@ -811,12 +830,12 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As return base.BeginWrite(buffer, offset, count, callback, state); } - var vAsyncResult = this.WriteAsync(buffer, offset, count); + var vAsyncResult = this.WriteAsync(buffer, offset, count, cancellationToken); vAsyncResult.ContinueWith(pAsyncResult => { callback?.Invoke(new TaskResult(pAsyncResult, state)); - }); + }, cancellationToken); return vAsyncResult; } @@ -868,7 +887,7 @@ private async ValueTask writeAsyncInternal(string value, bool addNewLine, Cancel catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } finally @@ -893,7 +912,7 @@ private async ValueTask writeAsyncInternal(string value, bool addNewLine, Cancel catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -940,7 +959,7 @@ internal async ValueTask WriteAsync(byte[] data, bool flush = false, Cancellatio catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -964,7 +983,7 @@ internal async Task WriteAsync(byte[] data, int offset, int count, bool flush, catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -1011,7 +1030,7 @@ public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOri try { - var http = new HttpStream(s, bufferPool, true); + var http = new HttpStream(s, bufferPool, cancellationToken, true); await http.CopyBodyAsync(writer, false, -1, onCopy, cancellationToken); } finally @@ -1196,7 +1215,7 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella catch { closedWrite = true; - if (!swallowException) + if (!isNetworkStream) throw; } } @@ -1217,7 +1236,7 @@ public async Task WriteAsync(ReadOnlyMemory buffer, CancellationToken canc } catch { - if (!swallowException) + if (!isNetworkStream) throw; } } diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index ba310332b..bc2c028d7 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -445,7 +445,7 @@ private async Task createServerConnection(string remoteHost await proxyServer.InvokeServerConnectionCreateEvent(tcpClient); - stream = new HttpServerStream(tcpClient.GetStream(), proxyServer.BufferPool); + stream = new HttpServerStream(tcpClient.GetStream(), proxyServer.BufferPool, cancellationToken); if (externalProxy != null && (isConnect || isHttps)) { @@ -487,7 +487,7 @@ private async Task createServerConnection(string remoteHost (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => proxyServer.SelectClientCertificate(sender, sessionArgs, targetHost, localCertificates, remoteCertificate, acceptableIssuers)); - stream = new HttpServerStream(sslStream, proxyServer.BufferPool); + stream = new HttpServerStream(sslStream, proxyServer.BufferPool, cancellationToken); var options = new SslClientAuthenticationOptions { diff --git a/src/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs index feb41f4fc..18ddedb5f 100644 --- a/src/Titanium.Web.Proxy/RequestHandler.cs +++ b/src/Titanium.Web.Proxy/RequestHandler.cs @@ -272,7 +272,7 @@ private async Task handleHttpSessionRequest(SessionEventArgs args, cancellationToken); // for connection pool, retry fails until cache is exhausted. - return await retryPolicy().ExecuteAsync(async (connection) => + return await retryPolicy().ExecuteAsync(async connection => { // set the connection and send request headers args.HttpClient.SetConnection(connection); diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs index e91f1ded8..0c8342aa3 100644 --- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs +++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs @@ -30,9 +30,7 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool); - - SslStream? sslStream = null; + var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); try { @@ -57,6 +55,7 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn // do client authentication using certificate X509Certificate2? certificate = null; + SslStream? sslStream = null; try { sslStream = new SslStream(clientStream, false); @@ -69,17 +68,18 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic - clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool); + clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference } catch (Exception e) { + sslStream?.Dispose(); + var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); var session = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource); throw new ProxyConnectException( $"Couldn't authenticate host '{httpsHostName}' with certificate '{certName}'.", e, session); } - } else { @@ -146,7 +146,6 @@ await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, } finally { - sslStream?.Dispose(); clientStream.Dispose(); } } From f5ae8813e7e52da8fc1cd1da84df27d99288460f Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 10 Dec 2019 21:19:26 +0100 Subject: [PATCH 2/8] nuget upgrade & sample projects are using netcore 3.1 --- .vscode/launch.json | 4 ++-- ...um.Web.Proxy.Examples.Basic.NetCore.csproj | 2 +- .../Titanium.Web.Proxy.Examples.Basic.csproj | 2 +- ...m.Web.Proxy.Examples.WindowsService.csproj | 6 +++--- ...nium.Web.Proxy.Examples.Wpf.NetCore.csproj | 2 +- .../Titanium.Web.Proxy.Examples.Wpf.csproj | 2 +- .../Titanium.Web.Proxy.NetCore.csproj | 19 +++++-------------- .../Titanium.Web.Proxy.csproj | 4 ++-- .../Titanium.Web.Proxy.nuspec | 12 ++++++------ ...Titanium.Web.Proxy.IntegrationTests.csproj | 4 ++-- 10 files changed, 24 insertions(+), 33 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 20840235b..a7ca58048 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "NetCore|Debug|Basic Example", "type": "coreclr", "request": "launch", - "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/netcoreapp2.0/Titanium.Web.Proxy.Examples.Basic.NetCore.dll", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Debug/netcoreapp3.1/Titanium.Web.Proxy.Examples.Basic.NetCore.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, @@ -16,7 +16,7 @@ "name": "NetCore|Release|Basic Example", "type": "coreclr", "request": "launch", - "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Release/netcoreapp2.0/Titanium.Web.Proxy.Examples.Basic.NetCore.dll", + "program": "${workspaceRoot}/examples/Titanium.Web.Proxy.Examples.Basic/bin/Release/netcoreapp3.1/Titanium.Web.Proxy.Examples.Basic.NetCore.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj index 4744326f0..2d250e8df 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.NetCore.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.1 + netcoreapp3.1 false 7.1 diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj index d924886a0..5bd979326 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Basic/Titanium.Web.Proxy.Examples.Basic.csproj @@ -2,7 +2,7 @@ Exe - net461;netcoreapp3.0 + net461;netcoreapp3.1 false 7.1 diff --git a/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj b/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj index a035141b6..de3e324bc 100644 --- a/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj +++ b/examples/Titanium.Web.Proxy.Examples.WindowsService/Titanium.Web.Proxy.Examples.WindowsService.csproj @@ -103,16 +103,16 @@ - 4.6.0 + 4.7.0 4.5.0 - 4.6.0 + 4.7.0 - 4.6.0 + 4.7.0 4.5.3 diff --git a/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.NetCore.csproj b/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.NetCore.csproj index 2379187e2..5964493db 100644 --- a/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.NetCore.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.NetCore.csproj @@ -2,7 +2,7 @@ WinExe - netcoreapp3.0 + netcoreapp3.1 true diff --git a/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj b/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj index 89dd81498..ccf8d5a78 100644 --- a/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj +++ b/examples/Titanium.Web.Proxy.Examples.Wpf/Titanium.Web.Proxy.Examples.Wpf.csproj @@ -2,7 +2,7 @@ WinExe - net461;netcoreapp3.0 + net461;netcoreapp3.1 true diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj index de71aa587..8bd384189 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.NetCore.csproj @@ -1,37 +1,28 @@  - netstandard2.0;netcoreapp2.1 + netstandard2.1 Titanium.Web.Proxy false True StrongNameKey.snk False True + enable 8.0 - - + - 4.6.0 + 4.7.0 - 4.6.0 - - - - - - 4.6.0 - - - 4.6.0 + 4.7.0 diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj index 6a8b943ca..e665ae3d4 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj @@ -25,10 +25,10 @@ - 4.6.0 + 4.7.0 - 4.6.0 + 4.7.0 diff --git a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec index 07d33b737..54faceebd 100644 --- a/src/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec +++ b/src/Titanium.Web.Proxy/Titanium.Web.Proxy.nuspec @@ -24,26 +24,26 @@ - + - + - + - + - - + + diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index a6b38e20d..95923b1fb 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0 + netcoreapp3.1 StrongNameKey.snk true @@ -16,7 +16,7 @@ - + From 1fe10a9274118a4501ef44ff2561e8197ac358e2 Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 10 Dec 2019 21:32:51 +0100 Subject: [PATCH 3/8] Kestrel is part of aspnetcore --- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 5 ----- .../Titanium.Web.Proxy.IntegrationTests.csproj | 2 -- 2 files changed, 7 deletions(-) diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 3b9aeecc7..22a8a7aa4 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -673,11 +673,6 @@ public async ValueTask FillBufferAsync(CancellationToken cancellationToken bufferLength += readBytes; } } - catch (ObjectDisposedException) - { - if (!isNetworkStream) - throw; - } catch { if (!isNetworkStream) diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index 95923b1fb..ec24902b5 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -14,8 +14,6 @@ - - From 9c2bc8bbb2fa0e448ba61fde2e49431d1b2f86fe Mon Sep 17 00:00:00 2001 From: Honfika Date: Tue, 10 Dec 2019 22:43:24 +0100 Subject: [PATCH 4/8] No body for head request (#695) --- src/Titanium.Web.Proxy/Http/HttpWebClient.cs | 2 ++ src/Titanium.Web.Proxy/Http/Response.cs | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/Titanium.Web.Proxy/Http/HttpWebClient.cs b/src/Titanium.Web.Proxy/Http/HttpWebClient.cs index 0ffcd4cc9..092728095 100644 --- a/src/Titanium.Web.Proxy/Http/HttpWebClient.cs +++ b/src/Titanium.Web.Proxy/Http/HttpWebClient.cs @@ -166,6 +166,8 @@ internal async Task ReceiveResponse(CancellationToken cancellationToken) return; } + Response.RequestMethod = Request.Method; + var httpStatus = await Connection.Stream.ReadResponseStatus(cancellationToken); Response.HttpVersion = httpStatus.Version; Response.StatusCode = httpStatus.StatusCode; diff --git a/src/Titanium.Web.Proxy/Http/Response.cs b/src/Titanium.Web.Proxy/Http/Response.cs index 80eb3ecd0..99c64dfef 100644 --- a/src/Titanium.Web.Proxy/Http/Response.cs +++ b/src/Titanium.Web.Proxy/Http/Response.cs @@ -36,6 +36,8 @@ public Response(byte[] body) /// public string StatusDescription { get; set; } = string.Empty; + internal string RequestMethod { get; set; } + /// /// Has response body? /// @@ -43,6 +45,11 @@ public override bool HasBody { get { + if (RequestMethod == "HEAD") + { + return false; + } + long contentLength = ContentLength; // If content length is set to 0 the response has no body From 4c6a8f502555cef4cda800aaabb65bae2fed73dd Mon Sep 17 00:00:00 2001 From: Honfika Date: Mon, 23 Dec 2019 19:13:38 +0100 Subject: [PATCH 5/8] Add property for client local endoint (not the lsitening endpoint, the actual EP for the connection) --- .../MainWindow.xaml | 2 +- .../MainWindow.xaml.cs | 3 ++- .../SessionListItem.cs | 4 ++- .../EventArguments/SessionEventArgs.cs | 4 +-- .../EventArguments/SessionEventArgsBase.cs | 9 +++++-- .../ExplicitClientHandler.cs | 11 +++----- src/Titanium.Web.Proxy/Helpers/NullWriter.cs | 4 +++ .../Network/Tcp/TcpConnectionFactory.cs | 26 ++++++++++--------- 8 files changed, 37 insertions(+), 26 deletions(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml b/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml index aafa6ae6f..0098d1a19 100644 --- a/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml +++ b/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml @@ -31,7 +31,7 @@ - + diff --git a/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs index 47211f090..5573205ac 100644 --- a/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs +++ b/examples/Titanium.Web.Proxy.Examples.Wpf/MainWindow.xaml.cs @@ -229,7 +229,8 @@ private SessionListItem createSessionListItem(SessionEventArgsBase e) ClientConnectionId = e.ClientConnectionId, ServerConnectionId = e.ServerConnectionId, HttpClient = e.HttpClient, - ClientEndPoint = e.ClientEndPoint, + ClientRemoteEndPoint = e.ClientRemoteEndPoint, + ClientLocalEndPoint = e.ClientLocalEndPoint, IsTunnelConnect = isTunnelConnect }; diff --git a/examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs b/examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs index 6429ab21b..513e0ffc2 100644 --- a/examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs +++ b/examples/Titanium.Web.Proxy.Examples.Wpf/SessionListItem.cs @@ -38,7 +38,9 @@ public Guid ServerConnectionId public HttpWebClient HttpClient { get; set; } - public IPEndPoint ClientEndPoint { get; set; } + public IPEndPoint ClientLocalEndPoint { get; set; } + + public IPEndPoint ClientRemoteEndPoint { get; set; } public bool IsTunnelConnect { get; set; } diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index f39658fe7..5f426155a 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -25,7 +25,7 @@ public class SessionEventArgs : SessionEventArgsBase /// private bool reRequest; - private WebSocketDecoder webSocketDecoder; + private WebSocketDecoder? webSocketDecoder; /// /// Is this session a HTTP/2 promise? @@ -221,7 +221,7 @@ internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancell var reader = isRequest ? (HttpStream)ClientStream : HttpClient.Connection.Stream; - await reader.CopyBodyAsync(requestResponse, true, new NullWriter(), TransformationMode.None, null, cancellationToken); + await reader.CopyBodyAsync(requestResponse, true, NullWriter.Instance, TransformationMode.None, null, cancellationToken); } /// diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs index 11f09245a..081ea4561 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs @@ -94,9 +94,14 @@ public bool EnableWinAuth public bool IsHttps => HttpClient.Request.IsHttps; /// - /// Client End Point. + /// Client Local End Point. /// - public IPEndPoint ClientEndPoint => (IPEndPoint)ClientConnection.RemoteEndPoint; + public IPEndPoint ClientLocalEndPoint => (IPEndPoint)ClientConnection.LocalEndPoint; + + /// + /// Client Remote End Point. + /// + public IPEndPoint ClientRemoteEndPoint => (IPEndPoint)ClientConnection.RemoteEndPoint; /// /// The web client used to communicate with server for this session. diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index a17597e0c..e023ffae4 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -37,7 +37,6 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect Task? prefetchConnectionTask = null; bool closeServerConnection = false; - bool calledRequestHandler = false; try { @@ -375,10 +374,11 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream, } } - calledRequestHandler = true; + var prefetchTask = prefetchConnectionTask; + prefetchConnectionTask = null; // Now create the request - await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchConnectionTask); + await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchTask); } catch (ProxyException e) { @@ -407,10 +407,7 @@ await Http2Helper.SendHttp2(clientStream, connection.Stream, cancellationTokenSource.Cancel(); } - if (!calledRequestHandler) - { - await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); - } + await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); clientStream.Dispose(); } diff --git a/src/Titanium.Web.Proxy/Helpers/NullWriter.cs b/src/Titanium.Web.Proxy/Helpers/NullWriter.cs index d74161b69..55ac32b5b 100644 --- a/src/Titanium.Web.Proxy/Helpers/NullWriter.cs +++ b/src/Titanium.Web.Proxy/Helpers/NullWriter.cs @@ -8,6 +8,10 @@ internal class NullWriter : IHttpStreamWriter { public static NullWriter Instance { get; } = new NullWriter(); + private NullWriter() + { + } + public void Write(byte[] buffer, int offset, int count) { } diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index bc2c028d7..1b507802f 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -580,20 +580,22 @@ internal async Task Release(TcpServerConnection connection, bool close = false) internal async Task Release(Task? connectionCreateTask, bool closeServerConnection) { - if (connectionCreateTask != null) + if (connectionCreateTask == null) { - TcpServerConnection? connection = null; - try - { - connection = await connectionCreateTask; - } - catch { } - finally + return; + } + + TcpServerConnection? connection = null; + try + { + connection = await connectionCreateTask; + } + catch { } + finally + { + if (connection != null) { - if (connection != null) - { - await Release(connection, closeServerConnection); - } + await Release(connection, closeServerConnection); } } } From b8cefa4cb2b8af5de9ef87e8427ee7154949f5ab Mon Sep 17 00:00:00 2001 From: Honfika Date: Mon, 23 Dec 2019 19:47:36 +0100 Subject: [PATCH 6/8] LocalEndPoint renamed, old names are obsolate --- .../EventArguments/SessionEventArgsBase.cs | 12 +++++++++--- src/Titanium.Web.Proxy/WinAuthHandler.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs index 081ea4561..c77e02070 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs @@ -59,7 +59,7 @@ private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoin ClientStream = clientStream; HttpClient = new HttpWebClient(connectRequest, request, new Lazy(() => clientStream.Connection.GetProcessId(endPoint))); - LocalEndPoint = endPoint; + ProxyEndPoint = endPoint; EnableWinAuth = server.EnableWinAuth && isWindowsAuthenticationSupported; } @@ -103,6 +103,9 @@ public bool EnableWinAuth /// public IPEndPoint ClientRemoteEndPoint => (IPEndPoint)ClientConnection.RemoteEndPoint; + [Obsolete("Use ClientRemoteEndPoint instead.")] + public IPEndPoint ClientEndPoint => ClientRemoteEndPoint; + /// /// The web client used to communicate with server for this session. /// @@ -119,12 +122,15 @@ public bool EnableWinAuth /// /// Local endpoint via which we make the request. /// - public ProxyEndPoint LocalEndPoint { get; } + public ProxyEndPoint ProxyEndPoint { get; } + + [Obsolete("Use ProxyEndPoint instead.")] + public ProxyEndPoint LocalEndPoint => ProxyEndPoint; /// /// Is this a transparent endpoint? /// - public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint; + public bool IsTransparent => ProxyEndPoint is TransparentProxyEndPoint; /// /// The last exception that happened. diff --git a/src/Titanium.Web.Proxy/WinAuthHandler.cs b/src/Titanium.Web.Proxy/WinAuthHandler.cs index c72d333e1..4ea7bd073 100644 --- a/src/Titanium.Web.Proxy/WinAuthHandler.cs +++ b/src/Titanium.Web.Proxy/WinAuthHandler.cs @@ -175,7 +175,7 @@ private async Task rewriteUnauthorizedResponse(SessionEventArgs args) // Add custom div to body to clarify that the proxy (not the client browser) failed authentication string authErrorMessage = "

NTLM authentication through Titanium.Web.Proxy (" + - args.ClientConnection.LocalEndPoint + + args.ClientLocalEndPoint + ") failed. Please check credentials.

"; string originalErrorMessage = "

Response from remote web server below.


"; From 3d746940d86c805f35e010c45bd552e59b77ac2a Mon Sep 17 00:00:00 2001 From: Honfika Date: Mon, 23 Dec 2019 20:00:48 +0100 Subject: [PATCH 7/8] Allow to set upstream proxy in before request handler --- .../ProxyTestController.cs | 5 +++ .../EventArguments/SessionEventArgsBase.cs | 8 +++++ .../Helpers/WinHttp/WinHttpWebProxyFinder.cs | 13 ++----- .../Models/ExternalProxy.cs | 34 ++++++++++++++++++- .../Network/Tcp/TcpConnectionFactory.cs | 8 ++--- .../NestedProxyTests.cs | 6 +--- .../Setup/TestProxyServer.cs | 13 ++----- 7 files changed, 55 insertions(+), 32 deletions(-) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index 1f9d3ed16..148ac606d 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -207,6 +207,11 @@ private async Task onRequest(object sender, SessionEventArgs e) { e.GetState().PipelineInfo.AppendLine(nameof(onRequest) + ":" + e.HttpClient.Request.RequestUri); + if (e.HttpClient.Request.Url.Contains("yahoo.com")) + { + e.CustomUpStreamProxy = new ExternalProxy("localhost", 8888); + } + await writeToConsole("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount); await writeToConsole(e.HttpClient.Request.Url); diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs index c77e02070..c362317ae 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs @@ -114,6 +114,14 @@ public bool EnableWinAuth [Obsolete("Use HttpClient instead.")] public HttpWebClient WebSession => HttpClient; + /// + /// Gets or sets the custom up stream proxy. + /// + /// + /// The custom up stream proxy. + /// + public IExternalProxy? CustomUpStreamProxy { get; set; } + /// /// Are we using a custom upstream HTTP(S) proxy? /// diff --git a/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs b/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs index 8b8ec3295..1aed46492 100644 --- a/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs +++ b/src/Titanium.Web.Proxy/Helpers/WinHttp/WinHttpWebProxyFinder.cs @@ -114,11 +114,7 @@ public bool GetAutoProxies(Uri destination, out IList? proxyList) } // TODO: Apply authorization - var systemProxy = new ExternalProxy - { - HostName = proxyStr, - Port = port - }; + var systemProxy = new ExternalProxy(proxyStr, port); return systemProxy; } @@ -134,12 +130,7 @@ public bool GetAutoProxies(Uri destination, out IList? proxyList) HttpSystemProxyValue? value = null; if (ProxyInfo?.Proxies?.TryGetValue(protocolType.Value, out value) == true) { - var systemProxy = new ExternalProxy - { - HostName = value!.HostName, - Port = value.Port - }; - + var systemProxy = new ExternalProxy(value!.HostName, value.Port); return systemProxy; } } diff --git a/src/Titanium.Web.Proxy/Models/ExternalProxy.cs b/src/Titanium.Web.Proxy/Models/ExternalProxy.cs index 931248233..70ae99caf 100644 --- a/src/Titanium.Web.Proxy/Models/ExternalProxy.cs +++ b/src/Titanium.Web.Proxy/Models/ExternalProxy.cs @@ -69,6 +69,39 @@ public string? Password ///
public int Port { get; set; } + /// + /// Initializes a new instance of the class. + /// + public ExternalProxy() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the host. + /// The port. + public ExternalProxy(string hostName, int port) + { + HostName = hostName; + Port = port; + } + + /// + /// Initializes a new instance of the class. + /// + /// Name of the host. + /// The port. + /// Name of the user. + /// The password. + public ExternalProxy(string hostName, int port, string userName, string password) + { + HostName = hostName; + Port = port; + UserName = userName; + Password = password; + } + /// /// returns data in Hostname:port format. /// @@ -77,6 +110,5 @@ public override string ToString() { return $"{HostName}:{Port}"; } - } } diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 1b507802f..62d9e935e 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -114,10 +114,10 @@ internal async Task GetConnectionCacheKey(ProxyServer server, SessionEve applicationProtocols = new List { applicationProtocol }; } - IExternalProxy? customUpStreamProxy = null; + IExternalProxy? customUpStreamProxy = session.CustomUpStreamProxy; bool isHttps = session.IsHttps; - if (server.GetCustomUpStreamProxyFunc != null) + if (customUpStreamProxy == null && server.GetCustomUpStreamProxyFunc != null) { customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(session); } @@ -169,10 +169,10 @@ internal Task GetServerConnection(ProxyServer proxyServer, internal async Task GetServerConnection(ProxyServer proxyServer, SessionEventArgsBase session, bool isConnect, List? applicationProtocols, bool noCache, CancellationToken cancellationToken) { - IExternalProxy? customUpStreamProxy = null; + IExternalProxy? customUpStreamProxy = session.CustomUpStreamProxy; bool isHttps = session.IsHttps; - if (proxyServer.GetCustomUpStreamProxyFunc != null) + if (customUpStreamProxy == null && proxyServer.GetCustomUpStreamProxyFunc != null) { customUpStreamProxy = await proxyServer.GetCustomUpStreamProxyFunc(session); } diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs index 3f1f8a2ca..ef2c088a9 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs @@ -59,11 +59,7 @@ public async Task Smoke_Test_Nested_Proxy_UserData() { Assert.AreEqual("Test", session.UserData); - return await Task.FromResult(new Models.ExternalProxy - { - HostName = "localhost", - Port = proxy2.ProxyEndPoints[0].Port - }); + return await Task.FromResult(new Models.ExternalProxy("localhost", proxy2.ProxyEndPoints[0].Port)); }; var client = testSuite.GetClient(proxy1, true); diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs index 7a8d80c3d..d85ef4240 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs @@ -22,17 +22,8 @@ public TestProxyServer(bool isReverseProxy, ProxyServer upStreamProxy = null) if (upStreamProxy != null) { - ProxyServer.UpStreamHttpProxy = new ExternalProxy - { - HostName = "localhost", - Port = upStreamProxy.ProxyEndPoints[0].Port - }; - - ProxyServer.UpStreamHttpsProxy = new ExternalProxy - { - HostName = "localhost", - Port = upStreamProxy.ProxyEndPoints[0].Port - }; + ProxyServer.UpStreamHttpProxy = new ExternalProxy("localhost", upStreamProxy.ProxyEndPoints[0].Port); + ProxyServer.UpStreamHttpsProxy = new ExternalProxy("localhost", upStreamProxy.ProxyEndPoints[0].Port); } ProxyServer.Start(); From d21ea35424fce676044de23fa5f3967fc87b0479 Mon Sep 17 00:00:00 2001 From: Honfika Date: Mon, 23 Dec 2019 20:08:46 +0100 Subject: [PATCH 8/8] add UpStreamEndPoint to sample --- .../ProxyTestController.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index 148ac606d..f7ffeb7b9 100644 --- a/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -207,6 +207,12 @@ private async Task onRequest(object sender, SessionEventArgs e) { e.GetState().PipelineInfo.AppendLine(nameof(onRequest) + ":" + e.HttpClient.Request.RequestUri); + var clientLocalIp = e.ClientLocalEndPoint.Address; + if (!clientLocalIp.Equals(IPAddress.Loopback) && !clientLocalIp.Equals(IPAddress.IPv6Loopback)) + { + e.HttpClient.UpStreamEndPoint = new IPEndPoint(clientLocalIp, 0); + } + if (e.HttpClient.Request.Url.Contains("yahoo.com")) { e.CustomUpStreamProxy = new ExternalProxy("localhost", 8888);