Commit e4d47081 authored by justcoding121's avatar justcoding121

#432 Fix issue & refactor

parent 0be354b4
...@@ -169,6 +169,13 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -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) internal async Task SyphonOutBodyAsync(bool isRequest, CancellationToken cancellationToken)
{ {
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
...@@ -180,7 +187,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -180,7 +187,7 @@ namespace Titanium.Web.Proxy.EventArguments
using (var bodyStream = new MemoryStream()) using (var bodyStream = new MemoryStream())
{ {
var writer = new HttpWriter(bodyStream, bufferPool, bufferSize); 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 ...@@ -223,23 +230,24 @@ namespace Titanium.Web.Proxy.EventArguments
} }
else 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) 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 stream = getStreamReader(isRequest);
var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response; var requestResponse = isRequest ? (RequestResponseBase)WebSession.Request : WebSession.Response;
bool isChunked = requestResponse.IsChunked; bool isChunked = useOriginalHeaderValues? requestResponse.OriginalIsChunked : requestResponse.IsChunked;
long contentLength = requestResponse.ContentLength; long contentLength = useOriginalHeaderValues ? requestResponse.OriginalContentLength : requestResponse.ContentLength;
if (transformation == TransformationMode.None) if (transformation == TransformationMode.None)
{ {
await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken); await writer.CopyBodyAsync(stream, isChunked, contentLength, onCopy, cancellationToken);
...@@ -249,7 +257,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -249,7 +257,7 @@ namespace Titanium.Web.Proxy.EventArguments
LimitedStream limitedStream; LimitedStream limitedStream;
Stream decompressStream = null; Stream decompressStream = null;
string contentEncoding = requestResponse.ContentEncoding; string contentEncoding = useOriginalHeaderValues ? requestResponse.OriginalContentEncoding : requestResponse.ContentEncoding;
Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength); Stream s = limitedStream = new LimitedStream(stream, bufferPool, isChunked, contentLength);
...@@ -463,7 +471,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -463,7 +471,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
/// <param name="html">HTML content to sent.</param> /// <param name="html">HTML content to sent.</param>
/// <param name="headers">HTTP response headers.</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, public void Ok(string html, Dictionary<string, HttpHeader> headers = null,
bool closeServerConnection = false) bool closeServerConnection = false)
{ {
...@@ -485,7 +493,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -485,7 +493,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
/// <param name="result">The html content bytes.</param> /// <param name="result">The html content bytes.</param>
/// <param name="headers">The HTTP headers.</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, public void Ok(byte[] result, Dictionary<string, HttpHeader> headers = null,
bool closeServerConnection = false) bool closeServerConnection = false)
{ {
...@@ -505,7 +513,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -505,7 +513,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="html">The html content.</param> /// <param name="html">The html content.</param>
/// <param name="status">The HTTP status code.</param> /// <param name="status">The HTTP status code.</param>
/// <param name="headers">The HTTP headers.</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(string html, HttpStatusCode status, public void GenericResponse(string html, HttpStatusCode status,
Dictionary<string, HttpHeader> headers = null, bool closeServerConnection = false) Dictionary<string, HttpHeader> headers = null, bool closeServerConnection = false)
{ {
...@@ -524,7 +532,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -524,7 +532,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <param name="result">The bytes to sent.</param> /// <param name="result">The bytes to sent.</param>
/// <param name="status">The HTTP status code.</param> /// <param name="status">The HTTP status code.</param>
/// <param name="headers">The HTTP headers.</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, public void GenericResponse(byte[] result, HttpStatusCode status,
Dictionary<string, HttpHeader> headers, bool closeServerConnection = false) Dictionary<string, HttpHeader> headers, bool closeServerConnection = false)
{ {
...@@ -540,7 +548,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -540,7 +548,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// Redirect to provided URL. /// Redirect to provided URL.
/// </summary> /// </summary>
/// <param name="url">The URL to redirect.</param> /// <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) public void Redirect(string url, bool closeServerConnection = false)
{ {
var response = new RedirectResponse(); var response = new RedirectResponse();
...@@ -555,10 +563,10 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -555,10 +563,10 @@ namespace Titanium.Web.Proxy.EventArguments
/// Respond with given response object to client. /// Respond with given response object to client.
/// </summary> /// </summary>
/// <param name="response">The response object.</param> /// <param name="response">The response object.</param>
/// <param name="closeServerConnection">Close the server connection?</param> /// <param name="closeServerConnection">Close the server connection used by request if any?</param>
public void Respond(Response response, bool closeServerConnection = false) public void Respond(Response response, bool closeServerConnection = false)
{ {
//request already send. //request already send/ready to be sent.
if (WebSession.Request.Locked) if (WebSession.Request.Locked)
{ {
//response already received from server and ready to be sent to client. //response already received from server and ready to be sent to client.
...@@ -567,34 +575,42 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -567,34 +575,42 @@ namespace Titanium.Web.Proxy.EventArguments
throw new Exception("You cannot call this function after response is sent to the client."); throw new Exception("You cannot call this function after response is sent to the client.");
} }
//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. //response already received from server but not yet ready to sent to client.
response.Locked = true;
response.TerminateResponse = WebSession.Response.TerminateResponse;
WebSession.Response = response; WebSession.Response = response;
WebSession.Response.Locked = true;
} }
//request not yet sent/not yet ready to be sent.
else else
{ {
//request not yet sent.
WebSession.Request.Locked = true; WebSession.Request.Locked = true;
WebSession.Request.CancelRequest = true;
response.Locked = true; //set new response.
WebSession.Response = response; WebSession.Response = response;
WebSession.Response.Locked = true;
WebSession.Request.CancelRequest = true;
} }
if(closeServerConnection)
{
TerminateServerConnection();
}
} }
/// <summary> /// <summary>
/// Terminate the connection to server. /// Terminate the connection to server at the end of this HTTP request/response session.
/// </summary> /// </summary>
public void TerminateServerConnection() public void TerminateServerConnection()
{ {
WebSession.Response.TerminateResponse = true; WebSession.CloseServerConnection = true;
} }
/// <summary> /// <summary>
......
...@@ -28,6 +28,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -28,6 +28,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
internal TcpServerConnection ServerConnection { get; set; } 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> /// <summary>
/// Stores internal data for the session. /// Stores internal data for the session.
/// </summary> /// </summary>
......
...@@ -99,7 +99,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -99,7 +99,8 @@ namespace Titanium.Web.Proxy.Http
public string Url => RequestUri.OriginalString; public string Url => RequestUri.OriginalString;
/// <summary> /// <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> /// </summary>
internal bool CancelRequest { get; set; } internal bool CancelRequest { get; set; }
......
...@@ -23,10 +23,29 @@ namespace Titanium.Web.Proxy.Http ...@@ -23,10 +23,29 @@ namespace Titanium.Web.Proxy.Http
private string bodyString; private string bodyString;
/// <summary> /// <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> /// </summary>
internal bool OriginalHasBody { get; set; } 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> /// <summary>
/// Keeps the body data after the session is finished. /// Keeps the body data after the session is finished.
/// </summary> /// </summary>
...@@ -168,6 +187,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -168,6 +187,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?) /// 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> /// </summary>
internal bool Locked { get; set; } internal bool Locked { get; set; }
......
...@@ -92,8 +92,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -92,8 +92,6 @@ namespace Titanium.Web.Proxy.Http
} }
} }
internal bool TerminateResponse { get; set; }
/// <summary> /// <summary>
/// Is response 100-continue /// Is response 100-continue
/// </summary> /// </summary>
......
...@@ -162,7 +162,11 @@ namespace Titanium.Web.Proxy ...@@ -162,7 +162,11 @@ namespace Titanium.Web.Proxy
await args.GetRequestBody(cancellationToken); await args.GetRequestBody(cancellationToken);
} }
//we need this to syphon out data from connection if API user changes them.
request.OriginalHasBody = request.HasBody; request.OriginalHasBody = request.HasBody;
request.OriginalContentLength = request.ContentLength;
request.OriginalIsChunked = request.IsChunked;
request.OriginalContentEncoding = request.ContentEncoding;
// If user requested interception do it // If user requested interception do it
await invokeBeforeRequest(args); await invokeBeforeRequest(args);
...@@ -251,7 +255,7 @@ namespace Titanium.Web.Proxy ...@@ -251,7 +255,7 @@ namespace Titanium.Web.Proxy
} }
//user requested //user requested
if (args.WebSession.Response.TerminateResponse) if (args.WebSession.CloseServerConnection)
{ {
closeServerConnection = true; closeServerConnection = true;
return; return;
......
...@@ -18,7 +18,6 @@ namespace Titanium.Web.Proxy ...@@ -18,7 +18,6 @@ namespace Titanium.Web.Proxy
/// <returns> The task.</returns> /// <returns> The task.</returns>
private async Task handleHttpSessionResponse(SessionEventArgs args) private async Task handleHttpSessionResponse(SessionEventArgs args)
{ {
var cancellationToken = args.CancellationTokenSource.Token; var cancellationToken = args.CancellationTokenSource.Token;
// read response & headers from server // read response & headers from server
...@@ -40,7 +39,12 @@ namespace Titanium.Web.Proxy ...@@ -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.OriginalHasBody = response.HasBody;
response.OriginalContentLength = response.ContentLength;
response.OriginalIsChunked = response.IsChunked;
response.OriginalContentEncoding = response.ContentEncoding;
// if user requested call back then do it // if user requested call back then do it
if (!response.Locked) if (!response.Locked)
...@@ -53,13 +57,17 @@ namespace Titanium.Web.Proxy ...@@ -53,13 +57,17 @@ namespace Titanium.Web.Proxy
var clientStreamWriter = args.ProxyClient.ClientStreamWriter; 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); 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); await args.SyphonOutBodyAsync(false, cancellationToken);
} }
......
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