Commit 5d2bf635 authored by Honfika's avatar Honfika

Do not dispose the WebSession object when the session is finished (but set the...

Do not dispose the WebSession object when the session is finished (but set the bodies to null unless the KeepXxxBody property is set tu true, which is false by default)
parent 785fadb5
......@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup>
......
......@@ -107,7 +107,6 @@ namespace Titanium.Web.Proxy.Examples.Wpf
SessionListItem item;
if (sessionDictionary.TryGetValue(e, out item))
{
item.Response = e.WebSession.Response;
item.Update();
}
});
......@@ -123,7 +122,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
if (e.WebSession.Request.HasBody)
{
item.RequestBody = await e.GetRequestBody();
e.WebSession.Request.KeepRequestBody = true;
await e.GetRequestBody();
}
}
......@@ -135,7 +135,6 @@ namespace Titanium.Web.Proxy.Examples.Wpf
SessionListItem item2;
if (sessionDictionary.TryGetValue(e, out item2))
{
item2.Response = e.WebSession.Response;
item2.Update();
item = item2;
}
......@@ -145,7 +144,8 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{
if (e.WebSession.Response.HasBody)
{
item.ResponseBody = await e.GetResponseBody();
e.WebSession.Response.KeepResponseBody = true;
await e.GetResponseBody();
}
}
}
......@@ -165,11 +165,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{
Number = lastSessionNumber,
SessionArgs = e,
// save the headers because TWP will set it to null in Dispose
RequestHeaders = e.WebSession.Request.RequestHeaders,
ResponseHeaders = e.WebSession.Response.ResponseHeaders,
Request = e.WebSession.Request,
Response = e.WebSession.Response,
WebSession = e.WebSession,
};
if (e is TunnelConnectSessionEventArgs || e.WebSession.Request.UpgradeToWebSocket)
......@@ -221,24 +217,22 @@ namespace Titanium.Web.Proxy.Examples.Wpf
const int truncateLimit = 1024;
var session = SelectedSession;
var data = session.RequestBody ?? new byte[0];
var session = SelectedSession.WebSession;
var request = session.Request;
var data = (request.RequestBodyRead ? request.RequestBody : null) ?? new byte[0];
bool truncated = data.Length > truncateLimit;
if (truncated)
{
data = data.Take(truncateLimit).ToArray();
}
//restore the headers
typeof(Request).GetProperty(nameof(Request.RequestHeaders)).SetValue(session.Request, session.RequestHeaders);
typeof(Response).GetProperty(nameof(Response.ResponseHeaders)).SetValue(session.Response, session.ResponseHeaders);
//string hexStr = string.Join(" ", data.Select(x => x.ToString("X2")));
TextBoxRequest.Text = session.Request.HeaderText + session.Request.Encoding.GetString(data) +
TextBoxRequest.Text = request.HeaderText + request.Encoding.GetString(data) +
(truncated ? Environment.NewLine + $"Data is truncated after {truncateLimit} bytes" : null) +
(session.Request as ConnectRequest)?.ClientHelloInfo;
(request as ConnectRequest)?.ClientHelloInfo;
data = session.ResponseBody ?? new byte[0];
var response = session.Response;
data = (response.ResponseBodyRead ? response.ResponseBody : null) ?? new byte[0];
truncated = data.Length > truncateLimit;
if (truncated)
{
......
......@@ -70,17 +70,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
set { SetField(ref sentDataCount, value); }
}
public byte[] RequestBody { get; set; }
public byte[] ResponseBody { get; set; }
public Request Request { get; set; }
public Response Response { get; set; }
public HeaderCollection RequestHeaders { get; set; }
public HeaderCollection ResponseHeaders { get; set; }
public HttpWebClient WebSession { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
......
......@@ -140,8 +140,13 @@ namespace Titanium.Web.Proxy.EventArguments
"content length is greater than zero before accessing the body.");
}
if (WebSession.Request.RequestLocked)
{
throw new Exception("You cannot get the request body after request is made to server.");
}
//Caching check
if (WebSession.Request.RequestBody == null)
if (!WebSession.Request.RequestBodyRead)
{
//If chunked then its easy just read the whole body with the content length mentioned in the request header
using (var requestBodyStream = new MemoryStream())
......@@ -171,7 +176,8 @@ namespace Titanium.Web.Proxy.EventArguments
//Now set the flag to true
//So that next time we can deliver body from cache
WebSession.Request.RequestBodyRead = true;
OnDataSent(WebSession.Request.RequestBody, 0, WebSession.Request.RequestBody.Length);
var body = WebSession.Request.RequestBody;
OnDataSent(body, 0, body.Length);
}
}
......@@ -182,7 +188,6 @@ namespace Titanium.Web.Proxy.EventArguments
{
//siphon out the body
await ReadResponseBody();
WebSession.Response.Dispose();
WebSession.Response = new Response();
}
......@@ -201,8 +206,13 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary>
private async Task ReadResponseBody()
{
if (!WebSession.Request.RequestLocked)
{
throw new Exception("You cannot read the response body before request is made to server.");
}
//If not already read (not cached yet)
if (WebSession.Response.ResponseBody == null)
if (!WebSession.Response.ResponseBodyRead)
{
if (WebSession.Response.HasBody)
{
......@@ -237,7 +247,8 @@ namespace Titanium.Web.Proxy.EventArguments
//set this to true for caching
WebSession.Response.ResponseBodyRead = true;
OnDataReceived(WebSession.Response.ResponseBody, 0, WebSession.Response.ResponseBody.Length);
var body = WebSession.Response.ResponseBody;
OnDataReceived(body, 0, body.Length);
}
}
......@@ -249,11 +260,6 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (!WebSession.Request.RequestBodyRead)
{
if (WebSession.Request.RequestLocked)
{
throw new Exception("You cannot call this function after request is made to server.");
}
await ReadRequestBody();
}
......@@ -268,17 +274,10 @@ namespace Titanium.Web.Proxy.EventArguments
{
if (!WebSession.Request.RequestBodyRead)
{
if (WebSession.Request.RequestLocked)
{
throw new Exception("You cannot call this function after request is made to server.");
}
await ReadRequestBody();
}
//Use the encoding specified in request to decode the byte[] data to string
return WebSession.Request.RequestBodyString ?? (WebSession.Request.RequestBodyString =
WebSession.Request.Encoding.GetString(WebSession.Request.RequestBody));
return WebSession.Request.RequestBodyString;
}
/// <summary>
......@@ -328,12 +327,11 @@ namespace Titanium.Web.Proxy.EventArguments
/// <returns></returns>
public async Task<byte[]> GetResponseBody()
{
if (!WebSession.Request.RequestLocked)
if (!WebSession.Response.ResponseBodyRead)
{
throw new Exception("You cannot call this function before request is made to server.");
await ReadResponseBody();
}
await ReadResponseBody();
return WebSession.Response.ResponseBody;
}
......@@ -343,15 +341,12 @@ namespace Titanium.Web.Proxy.EventArguments
/// <returns></returns>
public async Task<string> GetResponseBodyAsString()
{
if (!WebSession.Request.RequestLocked)
if (!WebSession.Response.ResponseBodyRead)
{
throw new Exception("You cannot call this function before request is made to server.");
await ReadResponseBody();
}
await GetResponseBody();
return WebSession.Response.ResponseBodyString ?? (WebSession.Response.ResponseBodyString =
WebSession.Response.Encoding.GetString(WebSession.Response.ResponseBody));
return WebSession.Response.ResponseBodyString;
}
/// <summary>
......@@ -396,7 +391,7 @@ namespace Titanium.Web.Proxy.EventArguments
}
//syphon out the response body from server before setting the new body
if (WebSession.Response.ResponseBody == null)
if (!WebSession.Response.ResponseBodyRead)
{
await GetResponseBody();
}
......@@ -534,7 +529,7 @@ namespace Titanium.Web.Proxy.EventArguments
CustomUpStreamHttpProxyUsed = null;
CustomUpStreamHttpsProxyUsed = null;
WebSession.Dispose();
WebSession.FinishSession();
}
}
}
......@@ -11,9 +11,9 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Used to communicate with the server over HTTP(S)
/// </summary>
public class HttpWebClient : IDisposable
public class HttpWebClient
{
private int bufferSize;
private readonly int bufferSize;
/// <summary>
/// Connection to server
......@@ -222,12 +222,13 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
internal void FinishSession()
{
ConnectRequest = null;
ServerConnection = null;
Request.Dispose();
Response.Dispose();
ConnectRequest?.FinishSession();
Request?.FinishSession();
Response?.FinishSession();
}
}
}
......@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// A HTTP(S) request object
/// </summary>
public class Request : IDisposable
public class Request
{
/// <summary>
/// Request Method
......@@ -36,6 +36,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public Version HttpVersion { get; set; }
/// <summary>
/// Keeps the response body data after the session is finished
/// </summary>
public bool KeepRequestBody { get; set; }
/// <summary>
/// Has request body?
/// </summary>
......@@ -166,20 +171,54 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
internal bool CancelRequest { get; set; }
/// <summary>
/// Cached request body as byte array
/// </summary>
private byte[] requestBody;
/// <summary>
/// Cached request body as string
/// </summary>
private string requestBodyString;
/// <summary>
/// Request body as byte array
/// </summary>
internal byte[] RequestBody { get; set; }
public byte[] RequestBody
{
get
{
if (!RequestBodyRead)
{
if (RequestLocked)
{
throw new Exception("You cannot get the request body after request is made to server.");
}
throw new Exception("Request body is not read yet. " +
"Use SessionEventArgs.GetRequestBody() or SessionEventArgs.GetRequestBodyAsString() " +
"method to read the request body.");
}
return requestBody;
}
internal set
{
requestBody = value;
requestBodyString = null;
}
}
/// <summary>
/// Request body as string
/// Use the encoding specified in request to decode the byte[] data to string
/// </summary>
internal string RequestBodyString { get; set; }
internal string RequestBodyString => requestBodyString ?? (requestBodyString = Encoding.GetString(RequestBody));
/// <summary>
/// Request body was read by user?
/// </summary>
internal bool RequestBodyRead { get; set; }
public bool RequestBodyRead { get; internal set; }
/// <summary>
/// Request is ready to be sent (user callbacks are complete?)
......@@ -207,7 +246,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Request header collection
/// </summary>
public HeaderCollection RequestHeaders { get; private set; } = new HeaderCollection();
public HeaderCollection RequestHeaders { get; } = new HeaderCollection();
/// <summary>
/// Does server responsed positively for 100 continue request
......@@ -297,17 +336,15 @@ namespace Titanium.Web.Proxy.Http
}
/// <summary>
/// Dispose off
/// Finish the session
/// </summary>
public void Dispose()
public void FinishSession()
{
//not really needed since GC will collect it
//but just to be on safe side
RequestHeaders = null;
RequestBody = null;
RequestBodyString = null;
if (!KeepRequestBody)
{
requestBody = null;
requestBodyString = null;
}
}
}
}
......@@ -9,7 +9,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Http(s) response object
/// </summary>
public class Response : IDisposable
public class Response
{
/// <summary>
/// Response Status Code.
......@@ -36,6 +36,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public Version HttpVersion { get; set; }
/// <summary>
/// Keeps the response body data after the session is finished
/// </summary>
public bool KeepResponseBody { get; set; }
/// <summary>
/// Has response body?
/// </summary>
......@@ -151,22 +156,51 @@ namespace Titanium.Web.Proxy.Http
/// <summary>
/// Collection of all response headers
/// </summary>
public HeaderCollection ResponseHeaders { get; private set; } = new HeaderCollection();
public HeaderCollection ResponseHeaders { get; } = new HeaderCollection();
/// <summary>
/// Cached response body content as byte array
/// </summary>
private byte[] responseBody;
/// <summary>
/// Response body content as byte array
/// Cached response body as string
/// </summary>
internal byte[] ResponseBody { get; set; }
private string responseBodyString;
/// <summary>
/// Response body as byte array
/// </summary>
public byte[] ResponseBody
{
get
{
if (!ResponseBodyRead)
{
throw new Exception("Response body is not read yet. " +
"Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() " +
"method to read the response body.");
}
return responseBody;
}
internal set
{
responseBody = value;
responseBodyString = null;
}
}
/// <summary>
/// Response body as string
/// Use the encoding specified in response to decode the byte[] data to string
/// </summary>
internal string ResponseBodyString { get; set; }
internal string ResponseBodyString => responseBodyString ?? (responseBodyString = Encoding.GetString(ResponseBody));
/// <summary>
/// Was response body read by user
/// </summary>
internal bool ResponseBodyRead { get; set; }
public bool ResponseBodyRead { get; internal set; }
/// <summary>
/// Is response is no more modifyable by user (user callbacks complete?)
......@@ -235,17 +269,15 @@ namespace Titanium.Web.Proxy.Http
}
/// <summary>
/// Dispose off
/// Finish the session
/// </summary>
public void Dispose()
internal void FinishSession()
{
//not really needed since GC will collect it
//but just to be on safe side
ResponseHeaders = null;
ResponseBody = null;
ResponseBodyString = null;
if (!KeepResponseBody)
{
responseBody = null;
responseBodyString = null;
}
}
}
}
......@@ -512,11 +512,13 @@ namespace Titanium.Web.Proxy
await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.RequestBody);
}
var body = args.WebSession.Request.RequestBody;
//chunked send is not supported as of now
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length;
args.WebSession.Request.ContentLength = body.Length;
var newStream = args.WebSession.ServerConnection.Stream;
await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length);
await newStream.WriteAsync(body, 0, body.Length);
}
else
{
......
......@@ -8,6 +8,7 @@
<AssemblyOriginatorKeyFile>StrongNameKey.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>6</LangVersion>
</PropertyGroup>
<ItemGroup>
......
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