From 8a32fa99116afa82fad55476eef3ce161efad355 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Thu, 22 Apr 2021 16:53:10 -0600 Subject: [PATCH 01/14] #823 Add before write body prototype --- .../EventArguments/BeforeBodySendEventArgs.cs | 46 +++++++++++++++++++ src/Titanium.Web.Proxy/ProxyServer.cs | 12 +++++ 2 files changed, 58 insertions(+) create mode 100644 src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs diff --git a/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs new file mode 100644 index 000000000..b51ae5c63 --- /dev/null +++ b/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs @@ -0,0 +1,46 @@ +#if DEBUG +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Titanium.Web.Proxy.EventArguments +{ + + public class BeforeBodyWriteEventArgs : ProxyEventArgsBase + { + internal BeforeBodyWriteEventArgs(SessionEventArgs session, byte[] bodyBytes, bool isChunked, bool isFinalChunk) : base(session.ClientConnection) + { + Session = session; + BodyBytes = bodyBytes; + IsChunked = isChunked; + IsFinalChunk = isFinalChunk; + } + + + /// + /// The session arguments. + /// + public SessionEventArgs Session { get; } + + /// + /// Indicates whether body is written chunked stream. + /// If this is true, BeforeRequestBodySend or BeforeResponseBodySend will be called until IsLastChunk is false. + /// + public bool IsChunked { get; } + + /// + /// Indicates if this is the last chunk from client or server stream, when request is chunked. + /// Override this property to true if there are more bytes to write. + /// + public bool IsFinalChunk { get; set; } + + /// + /// The bytes about to be written. If IsChunked is true, this will be a chunk of the bytes to be written. + /// Override this property with custom bytes if needed, and adjust IsLastChunk accordingly. + /// + public byte[] BodyBytes { get; set; } + } +} +#endif diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs index d7ee15b85..719256e66 100644 --- a/src/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -350,11 +350,23 @@ public ExceptionHandler ExceptionFunc /// public event AsyncEventHandler? BeforeRequest; +#if DEBUG + /// + /// Intercept request body send event to server. + /// + public event AsyncEventHandler? OnRequestBodyWrite; +#endif /// /// Intercept response event from server. /// public event AsyncEventHandler? BeforeResponse; +#if DEBUG + /// + /// Intercept request body send event to client. + /// + public event AsyncEventHandler? OnResponseBodyWrite; +#endif /// /// Intercept after response event from server. /// From 22989e540246ce0093a964cb637992307d8b95e2 Mon Sep 17 00:00:00 2001 From: buildbot171 Date: Thu, 22 Apr 2021 22:54:46 +0000 Subject: [PATCH 02/14] API documentation update by build server --- docs/api/Titanium.Web.Proxy.ProxyServer.html | 40 ++++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.ProxyServer.html b/docs/api/Titanium.Web.Proxy.ProxyServer.html index 1b0a11ea9..c315e0665 100644 --- a/docs/api/Titanium.Web.Proxy.ProxyServer.html +++ b/docs/api/Titanium.Web.Proxy.ProxyServer.html @@ -1121,7 +1121,7 @@
Property Value
Improve this Doc - View Source + View Source

ThreadPoolWorkerThread

@@ -1248,7 +1248,7 @@

Methods Improve this Doc - View Source + View Source

AddEndPoint(ProxyEndPoint)

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

DisableAllSystemProxies()

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

DisableSystemHttpProxy()

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

DisableSystemHttpsProxy()

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

DisableSystemProxy(ProxyProtocolType)

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

Dispose()

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

Dispose(Boolean)

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

Finalize()

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

RemoveEndPoint(ProxyEndPoint)

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

RestoreOriginalProxySettings()

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

SetAsSystemHttpProxy(ExplicitProxyEndPoint)

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

SetAsSystemHttpsProxy(ExplicitProxyEndPoint)

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

SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType)

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

Start()

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

Stop()

@@ -1618,7 +1618,7 @@

Events Improve this Doc - View Source + View Source

AfterResponse

Intercept after response event from server.

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

BeforeResponse

Intercept response event from server.

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

OnClientConnectionCreate

Customize TcpClient used for client connection upon create.

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

OnServerConnectionCreate

Customize TcpClient used for server connection upon create.

From ad04876bb563282cfa0bd8f911539dc4620d8eb1 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Fri, 23 Apr 2021 06:12:10 -0600 Subject: [PATCH 03/14] #823 Pass ProxyServer object to HttpStream --- .../EventArguments/BeforeBodySendEventArgs.cs | 2 +- .../EventArguments/BeforeSslAuthenticateEventArgs.cs | 2 +- .../EventArguments/CertificateSelectionEventArgs.cs | 2 +- .../EventArguments/CertificateValidationEventArgs.cs | 2 +- .../EventArguments/EmptyProxyEventArgs.cs | 2 +- .../EventArguments/MultipartRequestPartSentEventArgs.cs | 2 +- .../EventArguments/ProxyEventArgsBase.cs | 5 +++-- src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs | 2 +- .../EventArguments/SessionEventArgsBase.cs | 2 +- src/Titanium.Web.Proxy/ExplicitClientHandler.cs | 4 ++-- src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs | 4 ++-- src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs | 4 ++-- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 8 +++++--- .../Network/Tcp/TcpConnectionFactory.cs | 4 ++-- src/Titanium.Web.Proxy/TransparentClientHandler.cs | 6 +++--- 15 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs index b51ae5c63..cf77ec68f 100644 --- a/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs @@ -10,7 +10,7 @@ namespace Titanium.Web.Proxy.EventArguments public class BeforeBodyWriteEventArgs : ProxyEventArgsBase { - internal BeforeBodyWriteEventArgs(SessionEventArgs session, byte[] bodyBytes, bool isChunked, bool isFinalChunk) : base(session.ClientConnection) + internal BeforeBodyWriteEventArgs(SessionEventArgs session, byte[] bodyBytes, bool isChunked, bool isFinalChunk) : base(session.Server, session.ClientConnection) { Session = session; BodyBytes = bodyBytes; diff --git a/src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs index 3482061db..1e752d1c7 100644 --- a/src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/BeforeSslAuthenticateEventArgs.cs @@ -10,7 +10,7 @@ public class BeforeSslAuthenticateEventArgs : ProxyEventArgsBase { internal readonly CancellationTokenSource TaskCancellationSource; - internal BeforeSslAuthenticateEventArgs(TcpClientConnection clientConnection, CancellationTokenSource taskCancellationSource, string sniHostName) : base(clientConnection) + internal BeforeSslAuthenticateEventArgs(ProxyServer server, TcpClientConnection clientConnection, CancellationTokenSource taskCancellationSource, string sniHostName) : base(server, clientConnection) { TaskCancellationSource = taskCancellationSource; SniHostName = sniHostName; diff --git a/src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs index 3da92e710..47dc0023c 100644 --- a/src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs @@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.EventArguments public class CertificateSelectionEventArgs : ProxyEventArgsBase { public CertificateSelectionEventArgs(SessionEventArgsBase session, string targetHost, - X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) : base(session.ClientConnection) + X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) : base(session.Server, session.ClientConnection) { Session = session; TargetHost = targetHost; diff --git a/src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs index 50d2a7d53..064eb4d7c 100644 --- a/src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs @@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.EventArguments /// public class CertificateValidationEventArgs : ProxyEventArgsBase { - public CertificateValidationEventArgs(SessionEventArgsBase session, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) : base(session.ClientConnection) + public CertificateValidationEventArgs(SessionEventArgsBase session, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) : base(session.Server, session.ClientConnection) { Session = session; Certificate = certificate; diff --git a/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs index 364c61285..67f6bf295 100644 --- a/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/EmptyProxyEventArgs.cs @@ -4,7 +4,7 @@ namespace Titanium.Web.Proxy.EventArguments { public class EmptyProxyEventArgs : ProxyEventArgsBase { - internal EmptyProxyEventArgs(TcpClientConnection clientConnection) : base(clientConnection) + internal EmptyProxyEventArgs(ProxyServer server, TcpClientConnection clientConnection) : base(server, clientConnection) { } } diff --git a/src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs index 22d4ead8a..bd8b174e6 100644 --- a/src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/MultipartRequestPartSentEventArgs.cs @@ -7,7 +7,7 @@ namespace Titanium.Web.Proxy.EventArguments /// public class MultipartRequestPartSentEventArgs : ProxyEventArgsBase { - internal MultipartRequestPartSentEventArgs(SessionEventArgs session, string boundary, HeaderCollection headers) : base(session.ClientConnection) + internal MultipartRequestPartSentEventArgs(SessionEventArgs session, string boundary, HeaderCollection headers) : base(session.Server, session.ClientConnection) { Session = session; Boundary = boundary; diff --git a/src/Titanium.Web.Proxy/EventArguments/ProxyEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/ProxyEventArgsBase.cs index f115896f1..42bad2d4c 100644 --- a/src/Titanium.Web.Proxy/EventArguments/ProxyEventArgsBase.cs +++ b/src/Titanium.Web.Proxy/EventArguments/ProxyEventArgsBase.cs @@ -10,16 +10,17 @@ namespace Titanium.Web.Proxy.EventArguments public abstract class ProxyEventArgsBase : EventArgs { private readonly TcpClientConnection clientConnection; - + internal readonly ProxyServer Server; public object ClientUserData { get => clientConnection.ClientUserData; set => clientConnection.ClientUserData = value; } - internal ProxyEventArgsBase(TcpClientConnection clientConnection) + internal ProxyEventArgsBase(ProxyServer server, TcpClientConnection clientConnection) { this.clientConnection = clientConnection; + this.Server = server; } } } diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 7a47e6fdc..5339c9694 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -197,7 +197,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, cancellationToken); + using var writer = new HttpStream(Server, bodyStream, BufferPool, cancellationToken); if (isRequest) { diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs index 33f65c846..8828999c8 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgsBase.cs @@ -49,7 +49,7 @@ public abstract class SessionEventArgsBase : ProxyEventArgsBase, IDisposable /// Initializes a new instance of the class. /// private protected SessionEventArgsBase(ProxyServer server, ProxyEndPoint endPoint, - HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource) : base(clientStream.Connection) + HttpClientStream clientStream, ConnectRequest? connectRequest, Request request, CancellationTokenSource cancellationTokenSource) : base(server, clientStream.Connection) { BufferPool = server.BufferPool; ExceptionFunc = server.ExceptionFunc; diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index fb58a6c47..b40e80e2f 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -33,7 +33,7 @@ private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnect var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; - var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); + var clientStream = new HttpClientStream(this, clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); Task? prefetchConnectionTask = null; bool closeServerConnection = false; @@ -211,7 +211,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, cancellationToken); + clientStream = new HttpClientStream(this, 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); diff --git a/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs index 7a13157e8..57dc88d0a 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpClientStream.cs @@ -11,8 +11,8 @@ internal sealed class HttpClientStream : HttpStream { public TcpClientConnection Connection { get; } - internal HttpClientStream(TcpClientConnection connection, Stream stream, IBufferPool bufferPool, CancellationToken cancellationToken) - : base(stream, bufferPool, cancellationToken) + internal HttpClientStream(ProxyServer server, TcpClientConnection connection, Stream stream, IBufferPool bufferPool, CancellationToken cancellationToken) + : base(server, stream, bufferPool, cancellationToken) { Connection = connection; } diff --git a/src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpServerStream.cs index 8376f19fe..5b95e9c1c 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, CancellationToken cancellationToken) - : base(stream, bufferPool, cancellationToken) + internal HttpServerStream(ProxyServer server, Stream stream, IBufferPool bufferPool, CancellationToken cancellationToken) + : base(server, stream, bufferPool, cancellationToken) { } diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 06c7aa844..44ea1dd0a 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -68,7 +68,7 @@ static HttpStream() } private static readonly byte[] newLine = ProxyConstants.NewLineBytes; - + private readonly ProxyServer server; /// /// Initializes a new instance of the class. /// @@ -76,8 +76,10 @@ static HttpStream() /// Bufferpool. /// The cancellation token. /// to leave the stream open after disposing the object; otherwise, . - internal HttpStream(Stream baseStream, IBufferPool bufferPool, CancellationToken cancellationToken, bool leaveOpen = false) + internal HttpStream(ProxyServer server, Stream baseStream, IBufferPool bufferPool, CancellationToken cancellationToken, bool leaveOpen = false) { + this.server = server; + if (baseStream is NetworkStream) { isNetworkStream = true; @@ -1026,7 +1028,7 @@ public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOri try { - var http = new HttpStream(s, bufferPool, cancellationToken, true); + var http = new HttpStream(server, s, bufferPool, cancellationToken, true); await http.CopyBodyAsync(writer, false, -1, onCopy, cancellationToken); } finally diff --git a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 0277b01a1..7d7f5f30a 100644 --- a/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -513,7 +513,7 @@ internal Task GetServerConnection(ProxyServer proxyServer, await proxyServer.InvokeServerConnectionCreateEvent(tcpServerSocket); - stream = new HttpServerStream(new NetworkStream(tcpServerSocket, true), proxyServer.BufferPool, cancellationToken); + stream = new HttpServerStream(proxyServer, new NetworkStream(tcpServerSocket, true), proxyServer.BufferPool, cancellationToken); if (externalProxy != null && externalProxy.ProxyType == ExternalProxyType.Http && (isConnect || isHttps)) { @@ -555,7 +555,7 @@ internal Task GetServerConnection(ProxyServer proxyServer, (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => proxyServer.SelectClientCertificate(sender, sessionArgs, targetHost, localCertificates, remoteCertificate, acceptableIssuers)); - stream = new HttpServerStream(sslStream, proxyServer.BufferPool, cancellationToken); + stream = new HttpServerStream(proxyServer, sslStream, proxyServer.BufferPool, cancellationToken); var options = new SslClientAuthenticationOptions { diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs index ce8d3ff8e..17e6e28c5 100644 --- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs +++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs @@ -36,7 +36,7 @@ private async Task handleClient(TransparentBaseProxyEndPoint endPoint, TcpClient int port, CancellationTokenSource cancellationTokenSource, CancellationToken cancellationToken) { bool isHttps = false; - var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); + var clientStream = new HttpClientStream(this, clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); try { @@ -46,7 +46,7 @@ private async Task handleClient(TransparentBaseProxyEndPoint endPoint, TcpClient { var httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; - var args = new BeforeSslAuthenticateEventArgs(clientConnection, cancellationTokenSource, httpsHostName); + var args = new BeforeSslAuthenticateEventArgs(this, clientConnection, cancellationTokenSource, httpsHostName); await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); @@ -74,7 +74,7 @@ private async Task handleClient(TransparentBaseProxyEndPoint endPoint, TcpClient await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls12, false); // HTTPS server created - we can now decrypt the client's traffic - clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool, cancellationToken); + clientStream = new HttpClientStream(this, clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference isHttps = true; } From 285e023db3442d2b21e387876510443a5345c00c Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Fri, 23 Apr 2021 06:55:48 -0600 Subject: [PATCH 04/14] #823 Pass SessionEventArgs to HttpStream --- .../EventArguments/SessionEventArgs.cs | 6 ++--- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 24 +++++++++++-------- src/Titanium.Web.Proxy/ResponseHandler.cs | 2 +- .../Network/IHttpStreamReader.cs | 3 ++- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 5339c9694..f13ba0453 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -228,7 +228,7 @@ internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancell var reader = isRequest ? (HttpStream)ClientStream : HttpClient.Connection.Stream; - await reader.CopyBodyAsync(requestResponse, true, NullWriter.Instance, TransformationMode.None, null, cancellationToken); + await reader.CopyBodyAsync(requestResponse, true, NullWriter.Instance, TransformationMode.None, isRequest, this, cancellationToken); } /// @@ -270,13 +270,13 @@ internal async Task CopyRequestBodyAsync(IHttpStreamWriter writer, Transformatio } else { - await reader.CopyBodyAsync(request, false, writer, transformation, OnDataSent, cancellationToken); + await reader.CopyBodyAsync(request, false, writer, transformation, true, this, cancellationToken); } } private async Task copyResponseBodyAsync(IHttpStreamWriter writer, TransformationMode transformation, CancellationToken cancellationToken) { - await HttpClient.Connection.Stream.CopyBodyAsync(HttpClient.Response, false, writer, transformation, OnDataReceived, cancellationToken); + await HttpClient.Connection.Stream.CopyBodyAsync(HttpClient.Response, false, writer, transformation, false, this, cancellationToken); } /// diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 44ea1dd0a..11dfca0fc 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -1003,14 +1003,14 @@ internal ValueTask WriteBodyAsync(byte[] data, bool isChunked, CancellationToken return WriteAsync(data, cancellationToken: cancellationToken); } - public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOriginalHeaderValues, IHttpStreamWriter writer, TransformationMode transformation, Action? onCopy, CancellationToken cancellationToken) + public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOriginalHeaderValues, IHttpStreamWriter writer, TransformationMode transformation, bool isRequest, SessionEventArgs args, CancellationToken cancellationToken) { bool isChunked = useOriginalHeaderValues ? requestResponse.OriginalIsChunked : requestResponse.IsChunked; long contentLength = useOriginalHeaderValues ? requestResponse.OriginalContentLength : requestResponse.ContentLength; if (transformation == TransformationMode.None) { - await CopyBodyAsync(writer, isChunked, contentLength, onCopy, cancellationToken); + await CopyBodyAsync(writer, isChunked, contentLength, isRequest, args, cancellationToken); return; } @@ -1029,7 +1029,7 @@ public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOri try { var http = new HttpStream(server, s, bufferPool, cancellationToken, true); - await http.CopyBodyAsync(writer, false, -1, onCopy, cancellationToken); + await http.CopyBodyAsync(writer, false, -1, isRequest, args, cancellationToken); } finally { @@ -1051,12 +1051,13 @@ public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOri /// /// public Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, - Action? onCopy, CancellationToken cancellationToken) + bool isRequest, + SessionEventArgs args, CancellationToken cancellationToken) { // For chunked request we need to read data as they arrive, until we reach a chunk end symbol if (isChunked) { - return copyBodyChunkedAsync(writer, onCopy, cancellationToken); + return copyBodyChunkedAsync(writer, isRequest, args, cancellationToken); } // http 1.0 or the stream reader limits the stream @@ -1066,7 +1067,7 @@ public Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long content } // If not chunked then its easy just read the amount of bytes mentioned in content length header - return copyBytesToStream(writer, contentLength, onCopy, cancellationToken); + return copyBytesToStream(writer, contentLength, isRequest, args, cancellationToken); } /// @@ -1095,7 +1096,7 @@ private async ValueTask writeBodyChunkedAsync(byte[] data, CancellationToken can /// /// /// - private async Task copyBodyChunkedAsync(IHttpStreamWriter writer, Action? onCopy, CancellationToken cancellationToken) + private async Task copyBodyChunkedAsync(IHttpStreamWriter writer, bool isRequest, SessionEventArgs args, CancellationToken cancellationToken) { while (true) { @@ -1120,7 +1121,7 @@ private async Task copyBodyChunkedAsync(IHttpStreamWriter writer, Action /// /// - private async Task copyBytesToStream(IHttpStreamWriter writer, long count, Action? onCopy, + private async Task copyBytesToStream(IHttpStreamWriter writer, long count, bool isRequest, SessionEventArgs args, CancellationToken cancellationToken) { var buffer = bufferPool.GetBuffer(); @@ -1170,7 +1171,10 @@ private async Task copyBytesToStream(IHttpStreamWriter writer, long count, Actio await writer.WriteAsync(buffer, 0, bytesRead, cancellationToken); - onCopy?.Invoke(buffer, 0, bytesRead); + if (isRequest) + args.OnDataSent(buffer, 0, bytesRead); + else + args.OnDataReceived(buffer, 0, bytesRead); } } finally diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs index 95a782f71..dc536b360 100644 --- a/src/Titanium.Web.Proxy/ResponseHandler.cs +++ b/src/Titanium.Web.Proxy/ResponseHandler.cs @@ -118,7 +118,7 @@ await handleHttpSessionRequest(args, null, args.ClientConnection.NegotiatedAppli // Copy body if exists var serverStream = args.HttpClient.Connection.Stream; await serverStream.CopyBodyAsync(response, false, clientStream, TransformationMode.None, - args.OnDataReceived, cancellationToken); + false, args, cancellationToken); } } diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamReader.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamReader.cs index 3bb6eed21..bcee2686b 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamReader.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamReader.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Titanium.Web.Proxy.EventArguments; namespace Titanium.Web.Proxy.StreamExtended.Network { @@ -11,6 +12,6 @@ public interface IHttpStreamReader : ILineStream Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, - Action? onCopy, CancellationToken cancellationToken); + bool isRequest, SessionEventArgs args, CancellationToken cancellationToken); } } From a745dd3df755bd2c7ea8f34252a24d6e2f601948 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 26 Apr 2021 09:06:06 -0600 Subject: [PATCH 05/14] #823 prep work with TODO comments --- ...entArgs.cs => BeforeBodyWriteEventArgs.cs} | 6 ++--- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 22 +++++++++++++++++++ src/Titanium.Web.Proxy/RequestHandler.cs | 18 +++++++++++++++ src/Titanium.Web.Proxy/ResponseHandler.cs | 18 +++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) rename src/Titanium.Web.Proxy/EventArguments/{BeforeBodySendEventArgs.cs => BeforeBodyWriteEventArgs.cs} (87%) diff --git a/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/BeforeBodyWriteEventArgs.cs similarity index 87% rename from src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs rename to src/Titanium.Web.Proxy/EventArguments/BeforeBodyWriteEventArgs.cs index cf77ec68f..e0788e934 100644 --- a/src/Titanium.Web.Proxy/EventArguments/BeforeBodySendEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/BeforeBodyWriteEventArgs.cs @@ -10,12 +10,12 @@ namespace Titanium.Web.Proxy.EventArguments public class BeforeBodyWriteEventArgs : ProxyEventArgsBase { - internal BeforeBodyWriteEventArgs(SessionEventArgs session, byte[] bodyBytes, bool isChunked, bool isFinalChunk) : base(session.Server, session.ClientConnection) + internal BeforeBodyWriteEventArgs(SessionEventArgs session, byte[] bodyBytes, bool isChunked, bool isLastChunk) : base(session.Server, session.ClientConnection) { Session = session; BodyBytes = bodyBytes; IsChunked = isChunked; - IsFinalChunk = isFinalChunk; + IsLastChunk = isLastChunk; } @@ -34,7 +34,7 @@ internal BeforeBodyWriteEventArgs(SessionEventArgs session, byte[] bodyBytes, bo /// Indicates if this is the last chunk from client or server stream, when request is chunked. /// Override this property to true if there are more bytes to write. /// - public bool IsFinalChunk { get; set; } + public bool IsLastChunk { get; set; } /// /// The bytes about to be written. If IsChunked is true, this will be a chunk of the bytes to be written. diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 11dfca0fc..46f73c7e2 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -1054,6 +1054,14 @@ public Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long content bool isRequest, SessionEventArgs args, CancellationToken cancellationToken) { + +#if DEBUG + if ((isRequest && args.HttpClient.Request.OriginalHasBody && !args.HttpClient.Request.IsBodyRead && server.ShouldCallBeforeRequestBodyWrite()) + || (!isRequest && args.HttpClient.Response.OriginalHasBody && !args.HttpClient.Response.IsBodyRead && server.ShouldCallBeforeResponseBodyWrite())) + { + return handleBodyWrite(writer, isChunked, contentLength, isRequest, args, cancellationToken); + } +#endif // For chunked request we need to read data as they arrive, until we reach a chunk end symbol if (isChunked) { @@ -1070,6 +1078,20 @@ public Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long content return copyBytesToStream(writer, contentLength, isRequest, args, cancellationToken); } + private Task handleBodyWrite(IHttpStreamWriter writer, bool isChunked, long contentLength, + bool isRequest, SessionEventArgs args, CancellationToken cancellationToken) + { + var originalContentLength = isRequest ? args.HttpClient.Request.OriginalContentLength : args.HttpClient.Response.OriginalContentLength; + var originalIsChunked = isRequest ? args.HttpClient.Request.OriginalIsChunked : args.HttpClient.Response.OriginalIsChunked; + + //1. Read bytes from original stream (max length of bytes will be equal to bufferPool.BufferSize). + //2. Call BeforeBodyWrite event handler with BeforeBodyWriteEventArgs.BodyBytes set to the bytes read from original stream. + //3. Write BeforeBodyWriteEventArgs.BodyBytes to the target stream when BeforeBodyWriteEventArgs.BodyBytes is not null or empty. + //4. Exit when 'long contentLength' parameter number of bytes are written to target stream (when not chunked) or + //when BeforeBodyWriteEventArgs.IsLastChunk is true after callback (when chunked). + throw new NotImplementedException(); + } + /// /// Copies the given input bytes to output stream chunked /// diff --git a/src/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs index 1565e0121..fe74694fb 100644 --- a/src/Titanium.Web.Proxy/RequestHandler.cs +++ b/src/Titanium.Web.Proxy/RequestHandler.cs @@ -400,5 +400,23 @@ private async Task onBeforeRequest(SessionEventArgs args) await BeforeRequest.InvokeAsync(this, args, ExceptionFunc); } } + + internal bool ShouldCallBeforeRequestBodyWrite() + { + if (OnRequestBodyWrite != null) + { + return true; + } + + return false; + } + + internal async Task OnBeforeRequestBodyWrite(BeforeBodyWriteEventArgs args) + { + if (OnRequestBodyWrite != null) + { + await OnRequestBodyWrite.InvokeAsync(this, args, ExceptionFunc); + } + } } } diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs index dc536b360..5898cf458 100644 --- a/src/Titanium.Web.Proxy/ResponseHandler.cs +++ b/src/Titanium.Web.Proxy/ResponseHandler.cs @@ -150,5 +150,23 @@ private async Task onAfterResponse(SessionEventArgs args) await AfterResponse.InvokeAsync(this, args, ExceptionFunc); } } + + internal bool ShouldCallBeforeResponseBodyWrite() + { + if (OnResponseBodyWrite != null) + { + return true; + } + + return false; + } + + internal async Task OnBeforeResponseBodyWrite(BeforeBodyWriteEventArgs args) + { + if (OnResponseBodyWrite != null) + { + await OnResponseBodyWrite.InvokeAsync(this, args, ExceptionFunc); + } + } } } From e3bd45082406704301c4c6f97d68c084d7df2c53 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 26 Apr 2021 09:09:41 -0600 Subject: [PATCH 06/14] Fix release build --- src/Titanium.Web.Proxy/RequestHandler.cs | 2 ++ src/Titanium.Web.Proxy/ResponseHandler.cs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs index fe74694fb..103f309f9 100644 --- a/src/Titanium.Web.Proxy/RequestHandler.cs +++ b/src/Titanium.Web.Proxy/RequestHandler.cs @@ -401,6 +401,7 @@ private async Task onBeforeRequest(SessionEventArgs args) } } +#if DEBUG internal bool ShouldCallBeforeRequestBodyWrite() { if (OnRequestBodyWrite != null) @@ -418,5 +419,6 @@ internal async Task OnBeforeRequestBodyWrite(BeforeBodyWriteEventArgs args) await OnRequestBodyWrite.InvokeAsync(this, args, ExceptionFunc); } } +#endif } } diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs index 5898cf458..0d07c9d3b 100644 --- a/src/Titanium.Web.Proxy/ResponseHandler.cs +++ b/src/Titanium.Web.Proxy/ResponseHandler.cs @@ -150,7 +150,7 @@ private async Task onAfterResponse(SessionEventArgs args) await AfterResponse.InvokeAsync(this, args, ExceptionFunc); } } - +#if DEBUG internal bool ShouldCallBeforeResponseBodyWrite() { if (OnResponseBodyWrite != null) @@ -168,5 +168,6 @@ internal async Task OnBeforeResponseBodyWrite(BeforeBodyWriteEventArgs args) await OnResponseBodyWrite.InvokeAsync(this, args, ExceptionFunc); } } +#endif } } From 1519ca535b857abb4bd428a19b080648c3ef0a99 Mon Sep 17 00:00:00 2001 From: buildbot171 Date: Mon, 26 Apr 2021 15:11:16 +0000 Subject: [PATCH 07/14] API documentation update by build server --- ...eamExtended.Network.IHttpStreamReader.html | 23 +++++++++++-------- docs/index.json | 2 +- docs/xrefmap.yml | 15 +++++------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html b/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html index 4e2a4d0c7..8fd1727f1 100644 --- a/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html +++ b/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html @@ -110,18 +110,18 @@

Methods

| - Improve this Doc + Improve this Doc - View Source + View Source -

CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Action<Byte[], Int32, Int32>, CancellationToken)

+

CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Boolean, SessionEventArgs, CancellationToken)

Declaration
-
Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
+
Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, bool isRequest, SessionEventArgs args, CancellationToken cancellationToken)
Parameters
@@ -149,8 +149,13 @@
Parameters
- - + + + + + + + @@ -180,7 +185,7 @@
Returns
Improve this Doc - View Source + View Source

Read(Byte[], Int32, Int32)

@@ -237,7 +242,7 @@
Returns
Improve this Doc - View Source + View Source

ReadAsync(Byte[], Int32, Int32, CancellationToken)

@@ -305,7 +310,7 @@
Returns
Improve this Doc
  • - View Source + View Source
  • diff --git a/docs/index.json b/docs/index.json index 5b9581638..ffbaded0e 100644 --- a/docs/index.json +++ b/docs/index.json @@ -362,7 +362,7 @@ "api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html": { "href": "api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html", "title": "Interface IHttpStreamReader | Titanium Web Proxy", - "keywords": "Interface IHttpStreamReader Inherited Members ILineStream.DataAvailable ILineStream.FillBufferAsync(CancellationToken) ILineStream.ReadByteFromBuffer() ILineStream.ReadLineAsync(CancellationToken) Namespace : Titanium.Web.Proxy.StreamExtended.Network Assembly : Titanium.Web.Proxy.dll Syntax public interface IHttpStreamReader : ILineStream Methods | Improve this Doc View Source CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Action, CancellationToken) Declaration Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, Action onCopy, CancellationToken cancellationToken) Parameters Type Name Description IHttpStreamWriter writer Boolean isChunked Int64 contentLength Action < Byte [], Int32 , Int32 > onCopy CancellationToken cancellationToken Returns Type Description Task | Improve this Doc View Source Read(Byte[], Int32, Int32) Declaration int Read(byte[] buffer, int offset, int count) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count Returns Type Description Int32 | Improve this Doc View Source ReadAsync(Byte[], Int32, Int32, CancellationToken) Declaration Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count CancellationToken cancellationToken Returns Type Description Task < Int32 >" + "keywords": "Interface IHttpStreamReader Inherited Members ILineStream.DataAvailable ILineStream.FillBufferAsync(CancellationToken) ILineStream.ReadByteFromBuffer() ILineStream.ReadLineAsync(CancellationToken) Namespace : Titanium.Web.Proxy.StreamExtended.Network Assembly : Titanium.Web.Proxy.dll Syntax public interface IHttpStreamReader : ILineStream Methods | Improve this Doc View Source CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Boolean, SessionEventArgs, CancellationToken) Declaration Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long contentLength, bool isRequest, SessionEventArgs args, CancellationToken cancellationToken) Parameters Type Name Description IHttpStreamWriter writer Boolean isChunked Int64 contentLength Boolean isRequest SessionEventArgs args CancellationToken cancellationToken Returns Type Description Task | Improve this Doc View Source Read(Byte[], Int32, Int32) Declaration int Read(byte[] buffer, int offset, int count) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count Returns Type Description Int32 | Improve this Doc View Source ReadAsync(Byte[], Int32, Int32, CancellationToken) Declaration Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count CancellationToken cancellationToken Returns Type Description Task < Int32 >" }, "api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html": { "href": "api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html", diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml index 0d05fd084..064150f93 100644 --- a/docs/xrefmap.yml +++ b/docs/xrefmap.yml @@ -5054,15 +5054,12 @@ references: commentId: T:Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader fullName: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader nameWithType: IHttpStreamReader -- uid: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter,System.Boolean,System.Int64,System.Action{System.Byte[],System.Int32,System.Int32},System.Threading.CancellationToken) - name: CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Action, CancellationToken) - href: api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html#Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamReader_CopyBodyAsync_Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamWriter_System_Boolean_System_Int64_System_Action_System_Byte___System_Int32_System_Int32__System_Threading_CancellationToken_ - commentId: M:Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter,System.Boolean,System.Int64,System.Action{System.Byte[],System.Int32,System.Int32},System.Threading.CancellationToken) - name.vb: CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Action(Of Byte(), Int32, Int32), CancellationToken) - fullName: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter, System.Boolean, System.Int64, System.Action, System.Threading.CancellationToken) - fullName.vb: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter, System.Boolean, System.Int64, System.Action(Of System.Byte(), System.Int32, System.Int32), System.Threading.CancellationToken) - nameWithType: IHttpStreamReader.CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Action, CancellationToken) - nameWithType.vb: IHttpStreamReader.CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Action(Of Byte(), Int32, Int32), CancellationToken) +- uid: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter,System.Boolean,System.Int64,System.Boolean,Titanium.Web.Proxy.EventArguments.SessionEventArgs,System.Threading.CancellationToken) + name: CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Boolean, SessionEventArgs, CancellationToken) + href: api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html#Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamReader_CopyBodyAsync_Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamWriter_System_Boolean_System_Int64_System_Boolean_Titanium_Web_Proxy_EventArguments_SessionEventArgs_System_Threading_CancellationToken_ + commentId: M:Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter,System.Boolean,System.Int64,System.Boolean,Titanium.Web.Proxy.EventArguments.SessionEventArgs,System.Threading.CancellationToken) + fullName: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync(Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter, System.Boolean, System.Int64, System.Boolean, Titanium.Web.Proxy.EventArguments.SessionEventArgs, System.Threading.CancellationToken) + nameWithType: IHttpStreamReader.CopyBodyAsync(IHttpStreamWriter, Boolean, Int64, Boolean, SessionEventArgs, CancellationToken) - uid: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.CopyBodyAsync* name: CopyBodyAsync href: api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html#Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamReader_CopyBodyAsync_ From 9dcdb8d24d66fd51977d0772e37611cee5f92937 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 26 Apr 2021 09:16:51 -0600 Subject: [PATCH 08/14] #823 update TODO comments --- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 46f73c7e2..beffbec6f 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -1084,11 +1084,13 @@ private Task handleBodyWrite(IHttpStreamWriter writer, bool isChunked, long cont var originalContentLength = isRequest ? args.HttpClient.Request.OriginalContentLength : args.HttpClient.Response.OriginalContentLength; var originalIsChunked = isRequest ? args.HttpClient.Request.OriginalIsChunked : args.HttpClient.Response.OriginalIsChunked; - //1. Read bytes from original stream (max length of bytes will be equal to bufferPool.BufferSize). - //2. Call BeforeBodyWrite event handler with BeforeBodyWriteEventArgs.BodyBytes set to the bytes read from original stream. - //3. Write BeforeBodyWriteEventArgs.BodyBytes to the target stream when BeforeBodyWriteEventArgs.BodyBytes is not null or empty. - //4. Exit when 'long contentLength' parameter number of bytes are written to target stream (when not chunked) or + //1. Begin while(true) loop + //2. Read bytes from original stream (max length of bytes will be equal to bufferPool.BufferSize). + //3. Call BeforeBodyWrite event handler with BeforeBodyWriteEventArgs.BodyBytes set to the bytes read from original stream. + //4. Write BeforeBodyWriteEventArgs.BodyBytes to the target stream when BeforeBodyWriteEventArgs.BodyBytes is not null or empty. + //5. Stop writing to target stream when 'long contentLength' parameter number of bytes are written (when not chunked) or //when BeforeBodyWriteEventArgs.IsLastChunk is true after callback (when chunked). + //6. Exit loop when original stream is completely siphoned out. throw new NotImplementedException(); } From afcca99af3cc95fd37d718373c369ee6f88f8a61 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 26 Apr 2021 09:17:38 -0600 Subject: [PATCH 09/14] #823 Update TODO comments --- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index beffbec6f..c6d1e132a 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -1090,7 +1090,7 @@ private Task handleBodyWrite(IHttpStreamWriter writer, bool isChunked, long cont //4. Write BeforeBodyWriteEventArgs.BodyBytes to the target stream when BeforeBodyWriteEventArgs.BodyBytes is not null or empty. //5. Stop writing to target stream when 'long contentLength' parameter number of bytes are written (when not chunked) or //when BeforeBodyWriteEventArgs.IsLastChunk is true after callback (when chunked). - //6. Exit loop when original stream is completely siphoned out. + //6. Exit loop when original stream is completely siphoned out and when writing in step 5 has stopped. throw new NotImplementedException(); } From 476f87736ab474aa08b09b63156632674d970cde Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 26 Apr 2021 09:24:53 -0600 Subject: [PATCH 10/14] #823 Update TODO comments --- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index c6d1e132a..29a7ae4fd 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -1085,12 +1085,12 @@ private Task handleBodyWrite(IHttpStreamWriter writer, bool isChunked, long cont var originalIsChunked = isRequest ? args.HttpClient.Request.OriginalIsChunked : args.HttpClient.Response.OriginalIsChunked; //1. Begin while(true) loop - //2. Read bytes from original stream (max length of bytes will be equal to bufferPool.BufferSize). - //3. Call BeforeBodyWrite event handler with BeforeBodyWriteEventArgs.BodyBytes set to the bytes read from original stream. + //2. Parse chunk if chunked, and read bytes from original stream. Max length of bytes read will be equal to bufferPool.BufferSize. + //3. Call BeforeBodyWrite event handler with BeforeBodyWriteEventArgs.BodyBytes set to the bytes read from original stream (pass null if original stream reached its end). //4. Write BeforeBodyWriteEventArgs.BodyBytes to the target stream when BeforeBodyWriteEventArgs.BodyBytes is not null or empty. //5. Stop writing to target stream when 'long contentLength' parameter number of bytes are written (when not chunked) or //when BeforeBodyWriteEventArgs.IsLastChunk is true after callback (when chunked). - //6. Exit loop when original stream is completely siphoned out and when writing in step 5 has stopped. + //6. Exit loop when original stream reaches its end AND when writing in step 5 has stopped. throw new NotImplementedException(); } From 8f9fed1ec4b6f44b27b4775f0cb75d5420b14adc Mon Sep 17 00:00:00 2001 From: Sebastian Solnica Date: Mon, 26 Apr 2021 17:42:10 +0200 Subject: [PATCH 11/14] Fix for #840: handling exceptions thrown when server is stopping --- src/Titanium.Web.Proxy/ProxyServer.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Titanium.Web.Proxy/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs index 719256e66..f4a8a3c5d 100644 --- a/src/Titanium.Web.Proxy/ProxyServer.cs +++ b/src/Titanium.Web.Proxy/ProxyServer.cs @@ -777,8 +777,19 @@ private void onAcceptConnection(IAsyncResult asyn) }); } - // Get the listener that handles the client request. - endPoint.Listener!.BeginAcceptSocket(onAcceptConnection, endPoint); + try + { + // based on end point type call appropriate request handlers + // Get the listener that handles the client request. + endPoint.Listener!.BeginAcceptSocket(onAcceptConnection, endPoint); + } + catch (Exception ex) when (ex is ObjectDisposedException || ex is InvalidOperationException) + { + // The listener was Stop()'d, disposing the underlying socket and + // triggering the completion of the callback. We're already exiting, + // so just return. + return; + } } From 158e728fd125ff6afa255ca669837a9e85152c99 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 26 Apr 2021 13:41:22 -0600 Subject: [PATCH 12/14] #823 Update TODO comments --- src/Titanium.Web.Proxy/Helpers/HttpStream.cs | 13 +++++++++++-- src/Titanium.Web.Proxy/Helpers/NullWriter.cs | 2 ++ .../StreamExtended/Network/IHttpStreamWriter.cs | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs index 29a7ae4fd..3f4e2f75b 100644 --- a/src/Titanium.Web.Proxy/Helpers/HttpStream.cs +++ b/src/Titanium.Web.Proxy/Helpers/HttpStream.cs @@ -41,6 +41,8 @@ internal class HttpStream : Stream, IHttpStreamWriter, IHttpStreamReader, IPeekS private readonly IBufferPool bufferPool; private readonly CancellationToken cancellationToken; + public bool IsNetworkStream => isNetworkStream; + public event EventHandler? DataRead; public event EventHandler? DataWrite; @@ -1056,8 +1058,11 @@ public Task CopyBodyAsync(IHttpStreamWriter writer, bool isChunked, long content { #if DEBUG - if ((isRequest && args.HttpClient.Request.OriginalHasBody && !args.HttpClient.Request.IsBodyRead && server.ShouldCallBeforeRequestBodyWrite()) - || (!isRequest && args.HttpClient.Response.OriginalHasBody && !args.HttpClient.Response.IsBodyRead && server.ShouldCallBeforeResponseBodyWrite())) + var isResponse = !isRequest; + + if (isNetworkStream && writer.IsNetworkStream && + (isRequest && args.HttpClient.Request.OriginalHasBody && !args.HttpClient.Request.IsBodyRead && server.ShouldCallBeforeRequestBodyWrite()) || + (isResponse && args.HttpClient.Response.OriginalHasBody && !args.HttpClient.Response.IsBodyRead && server.ShouldCallBeforeResponseBodyWrite())) { return handleBodyWrite(writer, isChunked, contentLength, isRequest, args, cancellationToken); } @@ -1084,6 +1089,10 @@ private Task handleBodyWrite(IHttpStreamWriter writer, bool isChunked, long cont var originalContentLength = isRequest ? args.HttpClient.Request.OriginalContentLength : args.HttpClient.Response.OriginalContentLength; var originalIsChunked = isRequest ? args.HttpClient.Request.OriginalIsChunked : args.HttpClient.Response.OriginalIsChunked; + //TODO + //create a new decompression stream to wrap this source HttpStream based on original content encoding if needed. + //create a new compression stream to wrap target writer stream based on content encoding if needed. + //1. Begin while(true) loop //2. Parse chunk if chunked, and read bytes from original stream. Max length of bytes read will be equal to bufferPool.BufferSize. //3. Call BeforeBodyWrite event handler with BeforeBodyWriteEventArgs.BodyBytes set to the bytes read from original stream (pass null if original stream reached its end). diff --git a/src/Titanium.Web.Proxy/Helpers/NullWriter.cs b/src/Titanium.Web.Proxy/Helpers/NullWriter.cs index b71892846..c3ef9dc82 100644 --- a/src/Titanium.Web.Proxy/Helpers/NullWriter.cs +++ b/src/Titanium.Web.Proxy/Helpers/NullWriter.cs @@ -8,6 +8,8 @@ internal class NullWriter : IHttpStreamWriter { public static NullWriter Instance { get; } = new NullWriter(); + public bool IsNetworkStream => false; + private NullWriter() { } diff --git a/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamWriter.cs b/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamWriter.cs index 6cfd89c40..1457c8dee 100644 --- a/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamWriter.cs +++ b/src/Titanium.Web.Proxy/StreamExtended/Network/IHttpStreamWriter.cs @@ -8,6 +8,8 @@ namespace Titanium.Web.Proxy.StreamExtended.Network /// public interface IHttpStreamWriter { + bool IsNetworkStream { get; } + void Write(byte[] buffer, int offset, int count); Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); From f022921b967689c8b0b9eb08855e5b0dc1ee0b1d Mon Sep 17 00:00:00 2001 From: buildbot171 Date: Mon, 26 Apr 2021 19:42:55 +0000 Subject: [PATCH 13/14] API documentation update by build server --- ...eamExtended.Network.IHttpStreamWriter.html | 40 +++++++++++++++++-- docs/index.json | 2 +- docs/xrefmap.yml | 13 ++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html b/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html index fa38d2dfa..2b9a6371b 100644 --- a/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html +++ b/docs/api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html @@ -92,6 +92,38 @@
    Synt
    public interface IHttpStreamWriter
    +

    Properties +

    + + | + Improve this Doc + + + View Source + + +

    IsNetworkStream

    +
    +
    +
    Declaration
    +
    +
    bool IsNetworkStream { get; }
    +
    +
    Property Value
    +
    Action<Byte[], Int32, Int32>onCopyBooleanisRequest
    SessionEventArgsargs
    + + + + + + + + + + + + +
    TypeDescription
    Boolean

    Methods

    @@ -99,7 +131,7 @@

    Methods Improve this Doc - View Source + View Source

    Write(Byte[], Int32, Int32)

    @@ -141,7 +173,7 @@
    Parameters
    Improve this Doc
    - View Source + View Source

    WriteAsync(Byte[], Int32, Int32, CancellationToken)

    @@ -203,7 +235,7 @@
    Returns
    Improve this Doc - View Source + View Source

    WriteLineAsync(String, CancellationToken)

    @@ -255,7 +287,7 @@
    Returns
    Improve this Doc - View Source + View Source

    WriteLineAsync(CancellationToken)

    diff --git a/docs/index.json b/docs/index.json index ffbaded0e..fc49c5949 100644 --- a/docs/index.json +++ b/docs/index.json @@ -367,7 +367,7 @@ "api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html": { "href": "api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html", "title": "Interface IHttpStreamWriter | Titanium Web Proxy", - "keywords": "Interface IHttpStreamWriter A concrete implementation of this interface is required when calling CopyStream. Namespace : Titanium.Web.Proxy.StreamExtended.Network Assembly : Titanium.Web.Proxy.dll Syntax public interface IHttpStreamWriter Methods | Improve this Doc View Source Write(Byte[], Int32, Int32) Declaration void Write(byte[] buffer, int offset, int count) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count | Improve this Doc View Source WriteAsync(Byte[], Int32, Int32, CancellationToken) Declaration Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count CancellationToken cancellationToken Returns Type Description Task | Improve this Doc View Source WriteLineAsync(String, CancellationToken) Declaration ValueTask WriteLineAsync(string value, CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description String value CancellationToken cancellationToken Returns Type Description ValueTask | Improve this Doc View Source WriteLineAsync(CancellationToken) Declaration ValueTask WriteLineAsync(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Returns Type Description ValueTask" + "keywords": "Interface IHttpStreamWriter A concrete implementation of this interface is required when calling CopyStream. Namespace : Titanium.Web.Proxy.StreamExtended.Network Assembly : Titanium.Web.Proxy.dll Syntax public interface IHttpStreamWriter Properties | Improve this Doc View Source IsNetworkStream Declaration bool IsNetworkStream { get; } Property Value Type Description Boolean Methods | Improve this Doc View Source Write(Byte[], Int32, Int32) Declaration void Write(byte[] buffer, int offset, int count) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count | Improve this Doc View Source WriteAsync(Byte[], Int32, Int32, CancellationToken) Declaration Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) Parameters Type Name Description Byte [] buffer Int32 offset Int32 count CancellationToken cancellationToken Returns Type Description Task | Improve this Doc View Source WriteLineAsync(String, CancellationToken) Declaration ValueTask WriteLineAsync(string value, CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description String value CancellationToken cancellationToken Returns Type Description ValueTask | Improve this Doc View Source WriteLineAsync(CancellationToken) Declaration ValueTask WriteLineAsync(CancellationToken cancellationToken = default(CancellationToken)) Parameters Type Name Description CancellationToken cancellationToken Returns Type Description ValueTask" }, "api/Titanium.Web.Proxy.StreamExtended.Network.ILineStream.html": { "href": "api/Titanium.Web.Proxy.StreamExtended.Network.ILineStream.html", diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml index 064150f93..2ce3ccc1e 100644 --- a/docs/xrefmap.yml +++ b/docs/xrefmap.yml @@ -5105,6 +5105,19 @@ references: commentId: T:Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter fullName: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter nameWithType: IHttpStreamWriter +- uid: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.IsNetworkStream + name: IsNetworkStream + href: api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html#Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamWriter_IsNetworkStream + commentId: P:Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.IsNetworkStream + fullName: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.IsNetworkStream + nameWithType: IHttpStreamWriter.IsNetworkStream +- uid: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.IsNetworkStream* + name: IsNetworkStream + href: api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html#Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamWriter_IsNetworkStream_ + commentId: Overload:Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.IsNetworkStream + isSpec: "True" + fullName: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.IsNetworkStream + nameWithType: IHttpStreamWriter.IsNetworkStream - uid: Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.Write(System.Byte[],System.Int32,System.Int32) name: Write(Byte[], Int32, Int32) href: api/Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html#Titanium_Web_Proxy_StreamExtended_Network_IHttpStreamWriter_Write_System_Byte___System_Int32_System_Int32_ From 1236dceabd8aff639e56eea2de7fbe678729a339 Mon Sep 17 00:00:00 2001 From: buildbot171 Date: Mon, 10 May 2021 15:57:50 +0000 Subject: [PATCH 14/14] API documentation update by build server --- docs/api/Titanium.Web.Proxy.ProxyServer.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/Titanium.Web.Proxy.ProxyServer.html b/docs/api/Titanium.Web.Proxy.ProxyServer.html index c315e0665..986680694 100644 --- a/docs/api/Titanium.Web.Proxy.ProxyServer.html +++ b/docs/api/Titanium.Web.Proxy.ProxyServer.html @@ -1363,7 +1363,7 @@
    Parameters
    Improve this Doc - View Source + View Source

    Dispose()

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

    Dispose(Boolean)

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

    Finalize()