Skip to content

Commit

Permalink
add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
justcoding121 committed Mar 2, 2016
1 parent c244b2b commit de51679
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 35 deletions.
139 changes: 106 additions & 33 deletions Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,48 @@

namespace Titanium.Web.Proxy.EventArguments
{
public class Client
{
internal TcpClient TcpClient { get; set; }
internal Stream ClientStream { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }

public int ClientPort { get; internal set; }
public IPAddress ClientIpAddress { get; internal set; }

}
/// <summary>
/// Holds info related to a single proxy session (single request/response sequence)
/// A proxy session is bounded to a single connection from client
/// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy
/// </summary>
public class SessionEventArgs : EventArgs, IDisposable
{
readonly int _bufferSize;

/// <summary>
/// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgs(int bufferSize)
{
_bufferSize = bufferSize;
Client = new Client();
Client = new ProxyClient();
ProxySession = new HttpWebSession();
}

internal Client Client { get; set; }
/// <summary>
/// Holds a reference to server connection
/// </summary>
internal ProxyClient Client { get; set; }


/// <summary>
/// Does this session uses SSL
/// </summary>
public bool IsHttps { get; internal set; }

/// <summary>
/// A web session corresponding to a single request/response sequence
/// within a proxy connection
/// </summary>
public HttpWebSession ProxySession { get; set; }


/// <summary>
/// A shortcut to get the request content length
/// </summary>
public int RequestContentLength
{
get
Expand All @@ -50,17 +63,25 @@ public int RequestContentLength
}
}

/// <summary>
/// A shortcut to get the request Method (GET/POST/PUT etc)
/// </summary>
public string RequestMethod
{
get { return ProxySession.Request.Method; }
}


/// <summary>
/// A shortcut to get the response status code (200 OK, 404 etc)
/// </summary>
public string ResponseStatusCode
{
get { return ProxySession.Response.ResponseStatusCode; }
}

/// <summary>
/// A shortcut to get the response content type
/// </summary>
public string ResponseContentType
{
get
Expand All @@ -69,30 +90,39 @@ public string ResponseContentType
}
}

/// <summary>
/// implement any cleanup here
/// </summary>
public void Dispose()
{

}

/// <summary>
/// Read request body content as bytes[] for current session
/// </summary>
private void ReadRequestBody()
{
//GET request don't have a request body to read
if ((ProxySession.Request.Method.ToUpper() != "POST" && ProxySession.Request.Method.ToUpper() != "PUT"))
{
throw new BodyNotFoundException("Request don't have a body." +
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body.");
}

//Caching check
if (ProxySession.Request.RequestBody == null)
{
var isChunked = false;
string requestContentEncoding = null;


//get compression method (gzip, zlib etc)
if (ProxySession.Request.RequestHeaders.Any(x => x.Name.ToLower() == "content-encoding"))
{
requestContentEncoding = ProxySession.Request.RequestHeaders.First(x => x.Name.ToLower() == "content-encoding").Value;
}

//check if the request have chunked body (body send chunck by chunck without a fixed length)
if (ProxySession.Request.RequestHeaders.Any(x => x.Name.ToLower() == "transfer-encoding"))
{
var transferEncoding =
Expand All @@ -103,13 +133,14 @@ private void ReadRequestBody()
}
}


//If not chunked then its easy just read the whole body with the content length mentioned in the request header
if (requestContentEncoding == null && !isChunked)
ProxySession.Request.RequestBody = this.Client.ClientStreamReader.ReadBytes(RequestContentLength);
else
{
using (var requestBodyStream = new MemoryStream())
{
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (isChunked)
{
while (true)
Expand All @@ -126,6 +157,7 @@ private void ReadRequestBody()
}
else
{
//chunk end
this.Client.ClientStreamReader.ReadLine();
break;
}
Expand All @@ -134,6 +166,7 @@ private void ReadRequestBody()

try
{
//decompress
switch (requestContentEncoding)
{
case "gzip":
Expand All @@ -152,20 +185,29 @@ private void ReadRequestBody()
}
catch
{
//if decompression fails, just assign the body stream as it it
//Not a safe option
ProxySession.Request.RequestBody = requestBodyStream.ToArray();
}
}
}
}
//Now set the flag to true
//So that next time we can deliver body from cache
ProxySession.Request.RequestBodyRead = true;
}

/// <summary>
/// Read response body as byte[] for current response
/// </summary>
private void ReadResponseBody()
{
//If not already read (not cached yet)
if (ProxySession.Response.ResponseBody == null)
{
using (var responseBodyStream = new MemoryStream())
{
//If chuncked the read chunk by chunk until we hit chunk end symbol
if (ProxySession.Response.IsChunked)
{
while (true)
Expand All @@ -182,17 +224,19 @@ private void ReadResponseBody()
}
else
{
//chuck end
ProxySession.ProxyClient.ServerStreamReader.ReadLine();
break;
}
}
}
else
{
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response
var buffer = ProxySession.ProxyClient.ServerStreamReader.ReadBytes(ProxySession.Response.ContentLength);
responseBodyStream.Write(buffer, 0, buffer.Length);
}

//decompress
switch (ProxySession.Response.ContentEncoding)
{
case "gzip":
Expand All @@ -209,41 +253,46 @@ private void ReadResponseBody()
break;
}
}

//set this to true for caching
ProxySession.Response.ResponseBodyRead = true;
}
}


public Encoding GetRequestBodyEncoding()
{
if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");

return ProxySession.Request.Encoding;
}

/// <summary>
/// Gets the request body as bytes
/// </summary>
/// <returns></returns>
public byte[] GetRequestBody()
{
if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");

ReadRequestBody();
return ProxySession.Request.RequestBody;
}

/// <summary>
/// Gets the request body as string
/// </summary>
/// <returns></returns>
public string GetRequestBodyAsString()
{
if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");


ReadRequestBody();

//Use the encoding specified in request to decode the byte[] data to string
return ProxySession.Request.RequestBodyString ?? (ProxySession.Request.RequestBodyString = ProxySession.Request.Encoding.GetString(ProxySession.Request.RequestBody));
}

/// <summary>
/// Sets the request body
/// </summary>
/// <param name="body"></param>
public void SetRequestBody(byte[] body)
{
if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");

//syphon out the request body from client before setting the new body
if (!ProxySession.Request.RequestBodyRead)
{
ReadRequestBody();
Expand All @@ -253,10 +302,15 @@ public void SetRequestBody(byte[] body)
ProxySession.Request.RequestBodyRead = true;
}

/// <summary>
/// Sets the body with the specified string
/// </summary>
/// <param name="body"></param>
public void SetRequestBodyString(string body)
{
if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");

//syphon out the request body from client before setting the new body
if (!ProxySession.Request.RequestBodyRead)
{
ReadRequestBody();
Expand All @@ -266,13 +320,10 @@ public void SetRequestBodyString(string body)
ProxySession.Request.RequestBodyRead = true;
}

public Encoding GetResponseBodyEncoding()
{
if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");

return ProxySession.Response.Encoding;
}

/// <summary>
/// Gets the response body as byte array
/// </summary>
/// <returns></returns>
public byte[] GetResponseBody()
{
if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
Expand All @@ -281,6 +332,10 @@ public byte[] GetResponseBody()
return ProxySession.Response.ResponseBody;
}

/// <summary>
/// Gets the response body as string
/// </summary>
/// <returns></returns>
public string GetResponseBodyAsString()
{
if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");
Expand All @@ -290,10 +345,15 @@ public string GetResponseBodyAsString()
return ProxySession.Response.ResponseBodyString ?? (ProxySession.Response.ResponseBodyString = ProxySession.Response.Encoding.GetString(ProxySession.Response.ResponseBody));
}

/// <summary>
/// Set the response body bytes
/// </summary>
/// <param name="body"></param>
public void SetResponseBody(byte[] body)
{
if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");

//syphon out the response body from server before setting the new body
if (ProxySession.Response.ResponseBody == null)
{
GetResponseBody();
Expand All @@ -302,10 +362,15 @@ public void SetResponseBody(byte[] body)
ProxySession.Response.ResponseBody = body;
}

/// <summary>
/// Replace the response body with the specified string
/// </summary>
/// <param name="body"></param>
public void SetResponseBodyString(string body)
{
if (!ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function before request is made to server.");

//syphon out the response body from server before setting the new body
if (ProxySession.Response.ResponseBody == null)
{
GetResponseBody();
Expand All @@ -316,6 +381,14 @@ public void SetResponseBodyString(string body)
}


/// <summary>
/// Before request is made to server
/// Respond with the specified HTML string to client
/// and ignore the request
/// Marking as obsolete, need to comeup with a generic responder method in future
/// </summary>
/// <param name="html"></param>
[Obsolete]
public void Ok(string html)
{
if (ProxySession.Request.RequestLocked) throw new Exception("You cannot call this function after request is made to server.");
Expand Down
2 changes: 0 additions & 2 deletions Titanium.Web.Proxy/RequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,6 @@ private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, S
args.Client.ClientStreamWriter = clientStreamWriter;
args.ProxySession.Request.Hostname = args.ProxySession.Request.RequestUri.Host;
args.ProxySession.Request.Url = args.ProxySession.Request.RequestUri.OriginalString;
args.Client.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
args.Client.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;


//If requested interception
Expand Down

0 comments on commit de51679

Please sign in to comment.