Customize TcpClient used for client connection upon create.
Customize TcpClient used for server connection upon create.
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
|
- Action<Byte[], Int32, Int32> |
- onCopy |
+ Boolean |
+ isRequest |
+ |
+
+
+ SessionEventArgs |
+ args |
|
@@ -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/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
+
+
+
+ Type |
+ Description |
+
+
+
+
+ Boolean |
+ |
+
+
+
Methods
@@ -99,7 +131,7 @@
- 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 5b9581638..fc49c5949 100644
--- a/docs/index.json
+++ b/docs/index.json
@@ -362,12 +362,12 @@
"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",
"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 0d05fd084..2ce3ccc1e 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_
@@ -5108,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_
diff --git a/src/Titanium.Web.Proxy/EventArguments/BeforeBodyWriteEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/BeforeBodyWriteEventArgs.cs
new file mode 100644
index 000000000..e0788e934
--- /dev/null
+++ b/src/Titanium.Web.Proxy/EventArguments/BeforeBodyWriteEventArgs.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 isLastChunk) : base(session.Server, session.ClientConnection)
+ {
+ Session = session;
+ BodyBytes = bodyBytes;
+ IsChunked = isChunked;
+ IsLastChunk = isLastChunk;
+ }
+
+
+ ///
+ /// 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 IsLastChunk { 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/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..f13ba0453 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)
{
@@ -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/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..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;
@@ -68,7 +70,7 @@ static HttpStream()
}
private static readonly byte[] newLine = ProxyConstants.NewLineBytes;
-
+ private readonly ProxyServer server;
///
/// Initializes a new instance of the class.
///
@@ -76,8 +78,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;
@@ -1001,14 +1005,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;
}
@@ -1026,8 +1030,8 @@ public async Task CopyBodyAsync(RequestResponseBase requestResponse, bool useOri
try
{
- var http = new HttpStream(s, bufferPool, cancellationToken, true);
- await http.CopyBodyAsync(writer, false, -1, onCopy, cancellationToken);
+ var http = new HttpStream(server, s, bufferPool, cancellationToken, true);
+ await http.CopyBodyAsync(writer, false, -1, isRequest, args, cancellationToken);
}
finally
{
@@ -1049,12 +1053,24 @@ 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)
{
+
+#if DEBUG
+ 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);
+ }
+#endif
// 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
@@ -1064,7 +1080,27 @@ 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);
+ }
+
+ 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;
+
+ //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).
+ //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 reaches its end AND when writing in step 5 has stopped.
+ throw new NotImplementedException();
}
///
@@ -1093,7 +1129,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)
{
@@ -1118,7 +1154,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();
@@ -1168,7 +1204,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/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/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/ProxyServer.cs b/src/Titanium.Web.Proxy/ProxyServer.cs
index d7ee15b85..f4a8a3c5d 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.
///
@@ -765,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;
+ }
}
diff --git a/src/Titanium.Web.Proxy/RequestHandler.cs b/src/Titanium.Web.Proxy/RequestHandler.cs
index 1565e0121..103f309f9 100644
--- a/src/Titanium.Web.Proxy/RequestHandler.cs
+++ b/src/Titanium.Web.Proxy/RequestHandler.cs
@@ -400,5 +400,25 @@ private async Task onBeforeRequest(SessionEventArgs args)
await BeforeRequest.InvokeAsync(this, args, ExceptionFunc);
}
}
+
+#if DEBUG
+ 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);
+ }
+ }
+#endif
}
}
diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs
index 95a782f71..0d07c9d3b 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);
}
}
@@ -150,5 +150,24 @@ private async Task onAfterResponse(SessionEventArgs args)
await AfterResponse.InvokeAsync(this, args, ExceptionFunc);
}
}
+#if DEBUG
+ 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);
+ }
+ }
+#endif
}
}
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);
}
}
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);
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;
}