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