diff --git a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 4e6630b10..a36a36503 100644 --- a/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/src/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -85,6 +85,11 @@ private async Task readRequestBodyAsync(CancellationToken cancellationToken) // If not already read (not cached yet) if (!request.IsBodyRead) { + if (request.IsBodyReceived) + { + throw new Exception("Request body was already received."); + } + if (request.HttpVersion == HttpHeader.Version20) { // do not send to the remote endpoint @@ -103,6 +108,7 @@ private async Task readRequestBodyAsync(CancellationToken cancellationToken) // Now set the flag to true // So that next time we can deliver body from cache request.IsBodyRead = true; + request.IsBodyReceived = true; } else { @@ -115,6 +121,7 @@ private async Task readRequestBodyAsync(CancellationToken cancellationToken) // Now set the flag to true // So that next time we can deliver body from cache request.IsBodyRead = true; + request.IsBodyReceived = true; } } } @@ -160,6 +167,11 @@ private async Task readResponseBodyAsync(CancellationToken cancellationToken) // If not already read (not cached yet) if (!response.IsBodyRead) { + if (response.IsBodyReceived) + { + throw new Exception("Response body was already received."); + } + if (response.HttpVersion == HttpHeader.Version20) { // do not send to the remote endpoint @@ -178,6 +190,7 @@ private async Task readResponseBodyAsync(CancellationToken cancellationToken) // Now set the flag to true // So that next time we can deliver body from cache response.IsBodyRead = true; + response.IsBodyReceived = true; } else { @@ -190,6 +203,7 @@ private async Task readResponseBodyAsync(CancellationToken cancellationToken) // Now set the flag to true // So that next time we can deliver body from cache response.IsBodyRead = true; + response.IsBodyReceived = true; } } } @@ -221,7 +235,7 @@ private async Task readBodyAsync(bool isRequest, CancellationToken cance internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken) { var requestResponse = isRequest ? (RequestResponseBase)HttpClient.Request : HttpClient.Response; - if (requestResponse.IsBodyRead || !requestResponse.OriginalHasBody) + if (requestResponse.IsBodyReceived || !requestResponse.OriginalHasBody) { return; } @@ -229,6 +243,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, isRequest, this, cancellationToken); + requestResponse.IsBodyReceived = true; } /// @@ -272,11 +287,15 @@ internal async Task CopyRequestBodyAsync(IHttpStreamWriter writer, Transformatio { await reader.CopyBodyAsync(request, false, writer, transformation, true, this, cancellationToken); } + + request.IsBodyReceived = true; } private async Task copyResponseBodyAsync(IHttpStreamWriter writer, TransformationMode transformation, CancellationToken cancellationToken) { - await HttpClient.Connection.Stream.CopyBodyAsync(HttpClient.Response, false, writer, transformation, false, this, cancellationToken); + var response = HttpClient.Response; + await HttpClient.Connection.Stream.CopyBodyAsync(response, false, writer, transformation, false, this, cancellationToken); + response.IsBodyReceived = true; } /// diff --git a/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs b/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs index 825cc8db8..1948c0417 100644 --- a/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs +++ b/src/Titanium.Web.Proxy/Http/RequestResponseBase.cs @@ -211,6 +211,21 @@ internal set internal bool BodyAvailable => BodyInternal != null; + private bool isBodyReceived; + + internal bool IsBodyReceived + { + get => isBodyReceived; + set + { + if (isBodyReceived) + { + ; + } + isBodyReceived = value; + } + } + internal bool IsBodySent { get; set; } internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true); diff --git a/src/Titanium.Web.Proxy/Http2/Http2Helper.cs b/src/Titanium.Web.Proxy/Http2/Http2Helper.cs index d84341874..125e5185a 100644 --- a/src/Titanium.Web.Proxy/Http2/Http2Helper.cs +++ b/src/Titanium.Web.Proxy/Http2/Http2Helper.cs @@ -394,6 +394,7 @@ private static async Task copyHttp2FrameAsync(Stream input, Stream output, } rr.IsBodyRead = true; + rr.IsBodyReceived = true; var tcs = rr.ReadHttp2BodyTaskCompletionSource; rr.ReadHttp2BodyTaskCompletionSource = null; diff --git a/src/Titanium.Web.Proxy/ResponseHandler.cs b/src/Titanium.Web.Proxy/ResponseHandler.cs index 0d07c9d3b..b294244ba 100644 --- a/src/Titanium.Web.Proxy/ResponseHandler.cs +++ b/src/Titanium.Web.Proxy/ResponseHandler.cs @@ -120,6 +120,8 @@ await handleHttpSessionRequest(args, null, args.ClientConnection.NegotiatedAppli await serverStream.CopyBodyAsync(response, false, clientStream, TransformationMode.None, false, args, cancellationToken); } + + response.IsBodyReceived = true; } args.TimeLine["Response Sent"] = DateTime.UtcNow;