Unverified Commit af1038c8 authored by justcoding121's avatar justcoding121 Committed by GitHub

Merge pull request #441 from justcoding121/master

Issue 432 Fix
parents e52d0aff 93a65722
......@@ -169,6 +169,13 @@ namespace Titanium.Web.Proxy.EventArguments
}
}
/// <summary>
/// Syphon out any left over data in given request/response from backing tcp connection.
/// When user modifies the response/request we need to do this to reuse tcp connections.
/// </summary>
/// <param name="isRequest"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken)
{
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
......@@ -180,7 +187,7 @@ namespace Titanium.Web.Proxy.EventArguments
using (var bodyStream = new MemoryStream())
{
var writer = new HttpWriter(bodyStream, bufferPool, bufferSize);
await copyBodyAsync(isRequest, writer, TransformationMode.None, null, cancellationToken);
await copyBodyAsync(isRequest, true, writer, TransformationMode.None, null, cancellationToken);
}
}
......@@ -223,23 +230,24 @@ namespace Titanium.Web.Proxy.EventArguments
}
else
{
await copyBodyAsync(true, writer, transformation, OnDataSent, cancellationToken);
await copyBodyAsync(true, false, writer, transformation, OnDataSent, cancellationToken);
}
}
internal async Task CopyResponseBodyAsync(HttpWriter writer, TransformationMode transformation, CancellationToken cancellationToken)
{
await copyBodyAsync(false, writer, transformation, OnDataReceived, cancellationToken);
await copyBodyAsync(false, false, writer, transformation, OnDataReceived, cancellationToken);
}
private async Task copyBodyAsync(bool isRequest, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
private async Task copyBodyAsync(bool isRequest, bool useOriginalHeaderValues, HttpWriter writer, TransformationMode transformation, Action<byte[], int, int> onCopy, CancellationToken cancellationToken)
{
var stream = getStreamReader(isRequest);
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
bool isChunked = requestResponse.IsChunked;
long contentLength = requestResponse.ContentLength;
bool isChunked = useOriginalHeaderValues? requestResponse.OriginalIsChunked : requestResponse.IsChunked;
long contentLength = useOriginalHeaderValues ? requestResponse.OriginalContentLength : requestResponse.ContentLength;
if (transformation == TransformationMode.None)
{
await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken);
......@@ -249,7 +257,7 @@ namespace Titanium.Web.Proxy.EventArguments
LimitedStream limitedStream;
Stream decompressStream = null;
string contentEncoding = requestResponse.ContentEncoding;
string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength);
......@@ -463,7 +471,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// <param name="html">HTML content to sent.</param>
/// <param name="headers">HTTP response headers.</param>
/// <param name="closeServerConnection">Close the server connection?</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Ok(string html, Dictionary<string, HttpHeader> headers = null,
bool closeServerConnection = false)
{
......@@ -485,7 +493,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
/// <param name="result">The html content bytes.</param>
/// <param name="headers">The HTTP headers.</param>
/// <param name="closeServerConnection">Close the server connection?</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null,
bool closeServerConnection = false)
{
......@@ -505,8 +513,8 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="html">The html content.</param>
/// <param name="status">The HTTP status code.</param>
/// <param name="headers">The HTTP headers.</param>
/// <param name="closeServerConnection">Close the server connection?</param>
public void GenericResponse(string html, HttpStatusCode status,
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void GenericResponse(string html, HttpStatusCode status,
Dictionary<string, HttpHeader> headers = null, bool closeServerConnection = false)
{
var response = new GenericResponse(status);
......@@ -524,7 +532,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="result">The bytes to sent.</param>
/// <param name="status">The HTTP status code.</param>
/// <param name="headers">The HTTP headers.</param>
/// <param name="closeServerConnection">Close the server connection?</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void GenericResponse(byte[] result, HttpStatusCode status,
Dictionary<string, HttpHeader> headers, bool closeServerConnection = false)
{
......@@ -540,7 +548,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Redirect to provided URL.
/// </summary>
/// <param name="url">The URL to redirect.</param>
/// <param name="closeServerConnection">Close the server connection?</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Redirect(string url, bool closeServerConnection = false)
{
var response = new RedirectResponse();
......@@ -552,13 +560,13 @@ namespace Titanium.Web.Proxy.EventArguments
}
/// <summary>
/// Respond with given response object to client.
/// </summary>
/// <param name="response">The response object.</param>
/// <param name="closeServerConnection">Close the server connection?</param>
/// Respond with given response object to client.
/// </summary>
/// <param name="response">The response object.</param>
/// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Respond(Response response, bool closeServerConnection = false)
{
//request already send.
//request already send/ready to be sent.
if (WebSession.Request.Locked)
{
//response already received from server and ready to be sent to client.
......@@ -567,34 +575,42 @@ namespace Titanium.Web.Proxy.EventArguments
throw new Exception("You cannot call this function after response is sent to the client.");
}
//response already received from server but not yet ready to sent to client.
response.Locked = true;
response.TerminateResponse = WebSession.Response.TerminateResponse;
//cleanup original response.
if (closeServerConnection)
{
//no need to cleanup original connection.
//it will be closed any way.
TerminateServerConnection();
}
response.OriginalHasBody = WebSession.Response.OriginalHasBody;
response.OriginalIsChunked = WebSession.Response.OriginalIsChunked;
response.OriginalContentLength = WebSession.Response.OriginalContentLength;
response.OriginalContentEncoding = WebSession.Response.OriginalContentEncoding;
//response already received from server but not yet ready to sent to client.
WebSession.Response = response;
WebSession.Response.Locked = true;
}
//request not yet sent/not yet ready to be sent.
else
{
//request not yet sent.
WebSession.Request.Locked = true;
response.Locked = true;
WebSession.Response = response;
WebSession.Request.CancelRequest = true;
//set new response.
WebSession.Response = response;
WebSession.Response.Locked = true;
}
if(closeServerConnection)
{
TerminateServerConnection();
}
}
/// <summary>
/// Terminate the connection to server.
/// Terminate the connection to server at the end of this HTTP request/response session.
/// </summary>
public void TerminateServerConnection()
{
WebSession.Response.TerminateResponse = true;
WebSession.CloseServerConnection = true;
}
/// <summary>
......
......@@ -28,6 +28,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
internal TcpServerConnection ServerConnection { get; set; }
/// <summary>
/// Should we close the server connection at the end of this HTTP request/response session.
/// </summary>
internal bool CloseServerConnection { get; set; }
/// <summary>
/// Stores internal data for the session.
/// </summary>
......
......@@ -99,7 +99,8 @@ namespace Titanium.Web.Proxy.Http
public string Url => RequestUri.OriginalString;
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request.
/// Cancels the client HTTP request without sending to server.
/// This should be set when API user responds with custom response.
/// </summary>
internal bool CancelRequest { get; set; }
......
......@@ -23,10 +23,29 @@ namespace Titanium.Web.Proxy.Http
private string bodyString;
/// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters
/// Store whether the original request/response has body or not, since the user may change the parameters.
/// We need this detail to tcp syphon out attached connection for reuse.
/// </summary>
internal bool OriginalHasBody { get; set; }
/// <summary>
/// Store original content-length, since the user setting the body may change the parameters.
/// We need this detail to tcp syphon out attached connection for reuse.
/// </summary>
internal long OriginalContentLength { get; set; }
/// <summary>
/// Store whether the original request/response was a chunked body, since the user may change the parameters.
/// We need this detail to tcp syphon out attached connection for reuse.
/// </summary>
internal bool OriginalIsChunked { get; set; }
/// <summary>
/// Store whether the original request/response content-encoding, since the user may change the parameters.
/// We need this detail to tcp syphon out attached connection for reuse.
/// </summary>
internal string OriginalContentEncoding { get; set; }
/// <summary>
/// Keeps the body data after the session is finished.
/// </summary>
......@@ -168,6 +187,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// Also if user set this as a custom response then this should be true.
/// </summary>
internal bool Locked { get; set; }
......
......@@ -92,8 +92,6 @@ namespace Titanium.Web.Proxy.Http
}
}
internal bool TerminateResponse { get; set; }
/// <summary>
/// Is response 100-continue
/// </summary>
......
......@@ -162,7 +162,11 @@ namespace Titanium.Web.Proxy
await args.GetRequestBody(cancellationToken);
}
//we need this to syphon out data from connection if API user changes them.
request.OriginalHasBody = request.HasBody;
request.OriginalContentLength = request.ContentLength;
request.OriginalIsChunked = request.IsChunked;
request.OriginalContentEncoding = request.ContentEncoding;
// If user requested interception do it
await invokeBeforeRequest(args);
......@@ -251,7 +255,7 @@ namespace Titanium.Web.Proxy
}
//user requested
if (args.WebSession.Response.TerminateResponse)
if (args.WebSession.CloseServerConnection)
{
closeServerConnection = true;
return;
......
......@@ -18,7 +18,6 @@ namespace Titanium.Web.Proxy
/// <returns> The task.</returns>
private async Task handleHttpSessionResponse(SessionEventArgs args)
{
var cancellationToken = args.CancellationTokenSource.Token;
// read response & headers from server
......@@ -40,7 +39,12 @@ namespace Titanium.Web.Proxy
}
}
//save original values so that if user changes them
//we can still use original values when syphoning out data from attached tcp connection.
response.OriginalHasBody = response.HasBody;
response.OriginalContentLength = response.ContentLength;
response.OriginalIsChunked = response.IsChunked;
response.OriginalContentEncoding = response.ContentEncoding;
// if user requested call back then do it
if (!response.Locked)
......@@ -53,13 +57,17 @@ namespace Titanium.Web.Proxy
var clientStreamWriter = args.ProxyClient.ClientStreamWriter;
if (response.TerminateResponse || response.Locked)
//user set custom response by ignoring original response from server.
if (response.Locked)
{
//write custom user response with body and return.
await clientStreamWriter.WriteResponseAsync(response, cancellationToken: cancellationToken);
if (!response.TerminateResponse)
if(args.WebSession.ServerConnection != null
&& !args.WebSession.CloseServerConnection)
{
// syphon out the response body from server before setting the new body
// syphon out the original response body from server connection
// so that connection will be good to be reused.
await args.SyphonOutBodyAsync(false, cancellationToken);
}
......
......@@ -305,7 +305,7 @@ the specified status to client. And then ignore the request.</p>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection?</p>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -354,7 +354,7 @@ And then ignore the request. </p>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection?</p>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -576,7 +576,7 @@ and ignore the request. </p>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection?</p>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -618,7 +618,7 @@ and ignore the request. </p>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection?</p>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -653,7 +653,7 @@ and ignore the request. </p>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection?</p>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -688,7 +688,7 @@ and ignore the request. </p>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.boolean">Boolean</a></td>
<td><span class="parametername">closeServerConnection</span></td>
<td><p>Close the server connection?</p>
<td><p>Close the server connection used by request if any?</p>
</td>
</tr>
</tbody>
......@@ -813,7 +813,7 @@ and ignore the request. </p>
<a id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_TerminateServerConnection_" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.TerminateServerConnection*"></a>
<h4 id="Titanium_Web_Proxy_EventArguments_SessionEventArgs_TerminateServerConnection" data-uid="Titanium.Web.Proxy.EventArguments.SessionEventArgs.TerminateServerConnection">TerminateServerConnection()</h4>
<div class="markdown level1 summary"><p>Terminate the connection to server.</p>
<div class="markdown level1 summary"><p>Terminate the connection to server at the end of this HTTP request/response session.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment