Commit 9bac69a9 authored by justcoding121's avatar justcoding121

add more comments

parent 4bcd22fc
......@@ -12,10 +12,24 @@ namespace Titanium.Web.Proxy.Http
/// </summary>
public class Request
{
/// <summary>
/// Request Method
/// </summary>
public string Method { get; set; }
/// <summary>
/// Request HTTP Uri
/// </summary>
public Uri RequestUri { get; set; }
/// <summary>
/// Request Http Version
/// </summary>
public Version HttpVersion { get; set; }
/// <summary>
/// Request Http hostanem
/// </summary>
internal string Host
{
get
......@@ -35,6 +49,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Request content encoding
/// </summary>
internal string ContentEncoding
{
get
......@@ -50,6 +67,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Request content-length
/// </summary>
public long ContentLength
{
get
......@@ -68,7 +88,6 @@ namespace Titanium.Web.Proxy.Http
}
set
{
var header = RequestHeaders.FirstOrDefault(x => x.Name.ToLower() == "content-length");
if (value >= 0)
......@@ -88,6 +107,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Request content-type
/// </summary>
public string ContentType
{
get
......@@ -109,6 +131,9 @@ namespace Titanium.Web.Proxy.Http
}
/// <summary>
/// Is request body send as chunked bytes
/// </summary>
public bool IsChunked
{
get
......@@ -140,6 +165,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Does this request has a 100-continue header?
/// </summary>
public bool ExpectContinue
{
get
......@@ -150,19 +178,37 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Request Url
/// </summary>
public string Url { get { return RequestUri.OriginalString; } }
/// <summary>
/// Encoding for this request
/// </summary>
internal Encoding Encoding { get { return this.GetEncoding(); } }
/// <summary>
/// Terminates the underlying Tcp Connection to client after current request
/// </summary>
internal bool CancelRequest { get; set; }
/// <summary>
/// Request body as byte array
/// </summary>
internal byte[] RequestBody { get; set; }
/// <summary>
/// request body as string
/// </summary>
internal string RequestBodyString { get; set; }
internal bool RequestBodyRead { get; set; }
internal bool RequestLocked { get; set; }
/// <summary>
/// Does this request has an upgrade to websocket header?
/// </summary>
internal bool UpgradeToWebSocket
{
get
......@@ -179,8 +225,19 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Request heade collection
/// </summary>
public List<HttpHeader> RequestHeaders { get; set; }
/// <summary>
/// Does server responsed positively for 100 continue request
/// </summary>
public bool Is100Continue { get; internal set; }
/// <summary>
/// Server responsed negatively for the request for 100 continue
/// </summary>
public bool ExpectationFailed { get; internal set; }
public Request()
......
......@@ -18,7 +18,9 @@ namespace Titanium.Web.Proxy.Http
internal Encoding Encoding { get { return this.GetResponseCharacterEncoding(); } }
/// <summary>
/// Content encoding for this response
/// </summary>
internal string ContentEncoding
{
get
......@@ -35,6 +37,10 @@ namespace Titanium.Web.Proxy.Http
}
internal Version HttpVersion { get; set; }
/// <summary>
/// Keep the connection alive?
/// </summary>
internal bool ResponseKeepAlive
{
get
......@@ -51,6 +57,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Content type of this response
/// </summary>
public string ContentType
{
get
......@@ -67,6 +76,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Length of response body
/// </summary>
internal long ContentLength
{
get
......@@ -105,6 +117,9 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Response transfer-encoding is chunked?
/// </summary>
internal bool IsChunked
{
get
......@@ -143,14 +158,37 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Collection of all response headers
/// </summary>
public List<HttpHeader> ResponseHeaders { get; set; }
/// <summary>
/// Response network stream
/// </summary>
internal Stream ResponseStream { get; set; }
/// <summary>
/// response body contenst as byte array
/// </summary>
internal byte[] ResponseBody { get; set; }
/// <summary>
/// response body as string
/// </summary>
internal string ResponseBodyString { get; set; }
internal bool ResponseBodyRead { get; set; }
internal bool ResponseLocked { get; set; }
/// <summary>
/// Is response 100-continue
/// </summary>
public bool Is100Continue { get; internal set; }
/// <summary>
/// expectation failed returned by server?
/// </summary>
public bool ExpectationFailed { get; internal set; }
public Response()
......
......@@ -44,7 +44,6 @@ namespace Titanium.Web.Proxy.Network
//Get a unique string to identify this connection
var key = GetConnectionKey(hostname, port, isHttps, version);
while (true)
{
await connectionAccessLock.WaitAsync();
......@@ -76,6 +75,7 @@ namespace Titanium.Web.Proxy.Network
}
if (cached == null)
cached = await CreateClient(hostname, port, isHttps, version);
......
......@@ -351,7 +351,7 @@ namespace Titanium.Web.Proxy
}
catch
{
//Other errors are discarded to keep the proxy running
//Other errors are discarded to keep proxy running
}
}
......
......@@ -18,7 +18,9 @@ using System.Threading.Tasks;
namespace Titanium.Web.Proxy
{
/// <summary>
/// Handle the requesr
/// </summary>
partial class ProxyServer
{
//This is called when client is aware of proxy
......@@ -43,6 +45,7 @@ namespace Titanium.Web.Proxy
//break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
//Find the request Verb
var httpVerb = httpCmdSplit[0];
if (httpVerb.ToUpper() == "CONNECT")
......@@ -50,6 +53,7 @@ namespace Titanium.Web.Proxy
else
httpRemoteUri = new Uri(httpCmdSplit[1]);
//parse the HTTP version
Version version = new Version(1, 1);
if (httpCmdSplit.Length == 3)
{
......@@ -76,7 +80,8 @@ namespace Titanium.Web.Proxy
try
{
//create the Tcp Connection to server and then release it to connection cache
//Just doing what CONNECT request is asking as to do
var tunnelClient = await TcpConnectionManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version);
await TcpConnectionManager.ReleaseClient(tunnelClient);
......@@ -88,7 +93,6 @@ namespace Titanium.Web.Proxy
//HTTPS server created - we can now decrypt the client's traffic
clientStream = sslStream;
clientStreamReader = new CustomBinaryReader(sslStream);
clientStreamWriter = new StreamWriter(sslStream);
......@@ -102,14 +106,19 @@ namespace Titanium.Web.Proxy
return;
}
//Now read the actual HTTPS request line
httpCmd = await clientStreamReader.ReadLineAsync();
}
//Sorry cannot do a HTTPS request decrypt to port 80 at this time
else if (httpVerb.ToUpper() == "CONNECT")
{
//Cyphen out CONNECT request headers
await clientStreamReader.ReadAllLinesAsync();
//write back successfull CONNECT response
await WriteConnectResponse(clientStreamWriter, version);
//Just relay the request/response without decrypting it
await TcpHelper.SendRaw(clientStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port,
false);
......@@ -179,12 +188,23 @@ namespace Titanium.Web.Proxy
await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter,
true);
}
/// <summary>
/// This is the core request handler method for a particular connection from client
/// </summary>
/// <param name="client"></param>
/// <param name="httpCmd"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
private static async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, bool isHttps)
{
TcpConnection connection = null;
//Loop through each subsequest request on this particular client connection
//(assuming HTTP connection is kept alive by client)
while (true)
{
if (string.IsNullOrEmpty(httpCmd))
......@@ -203,6 +223,7 @@ namespace Titanium.Web.Proxy
var httpMethod = httpCmdSplit[0];
//find the request HTTP version
Version version = new Version(1, 1);
if (httpCmdSplit.Length == 3)
{
......@@ -216,6 +237,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.RequestHeaders = new List<HttpHeader>();
//Read the request headers
string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync()))
{
......@@ -225,6 +247,8 @@ namespace Titanium.Web.Proxy
var httpRemoteUri = new Uri(!isHttps ? httpCmdSplit[1] : (string.Concat("https://", args.WebSession.Request.Host, httpCmdSplit[1])));
#if DEBUG
//Just ignore local requests while Debugging
//Its annoying
if (httpRemoteUri.Host.Contains("localhost"))
{
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null);
......@@ -242,7 +266,7 @@ namespace Titanium.Web.Proxy
PrepareRequestHeaders(args.WebSession.Request.RequestHeaders, args.WebSession);
args.WebSession.Request.Host = args.WebSession.Request.RequestUri.Authority;
//If requested interception
//If user requested interception do it
if (BeforeRequest != null)
{
Delegate[] invocationList = BeforeRequest.GetInvocationList();
......@@ -256,6 +280,7 @@ namespace Titanium.Web.Proxy
await Task.WhenAll(handlerTasks);
}
//if upgrading to websocket then relay the requet without reading the contents
if (args.WebSession.Request.UpgradeToWebSocket)
{
await TcpHelper.SendRaw(clientStream, httpCmd, args.WebSession.Request.RequestHeaders,
......@@ -267,21 +292,24 @@ namespace Titanium.Web.Proxy
//construct the web request that we are going to issue on behalf of the client.
connection = await TcpConnectionManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version);
args.WebSession.Request.RequestLocked = true;
//If request was cancelled by user then dispose the client
if (args.WebSession.Request.CancelRequest)
{
Dispose(client, clientStream, clientStreamReader, clientStreamWriter, args);
break;
}
//if expect continue is enabled then send the headers first
//and see if server would return 100 conitinue
if (args.WebSession.Request.ExpectContinue)
{
args.WebSession.SetConnection(connection);
await args.WebSession.SendRequest();
}
//If 100 continue was the response inform that to the client
if (Enable100ContinueBehaviour)
if (args.WebSession.Request.Is100Continue)
{
......@@ -296,6 +324,7 @@ namespace Titanium.Web.Proxy
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
//If expect continue is not enabled then set the connectio and send request headers
if (!args.WebSession.Request.ExpectContinue)
{
args.WebSession.SetConnection(connection);
......@@ -327,6 +356,7 @@ namespace Titanium.Web.Proxy
}
}
//If not expectation failed response was returned by server then parse response
if (!args.WebSession.Request.ExpectationFailed)
{
await HandleHttpSessionResponse(args);
......@@ -339,9 +369,10 @@ namespace Titanium.Web.Proxy
return;
}
//send the tcp connection to server back to connection cache for reuse
await TcpConnectionManager.ReleaseClient(connection);
// read the next request
// read the next request
httpCmd = await clientStreamReader.ReadLineAsync();
}
......@@ -355,6 +386,12 @@ namespace Titanium.Web.Proxy
}
/// <summary>
/// Write successfull CONNECT response to client
/// </summary>
/// <param name="clientStreamWriter"></param>
/// <param name="httpVersion"></param>
/// <returns></returns>
private static async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion)
{
await clientStreamWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2}", httpVersion.Major, httpVersion.Minor, "200 Connection established"));
......@@ -363,6 +400,11 @@ namespace Titanium.Web.Proxy
await clientStreamWriter.FlushAsync();
}
/// <summary>
/// prepare the request headers so that we can avoid encodings not parsable by this proxy
/// </summary>
/// <param name="requestHeaders"></param>
/// <param name="webRequest"></param>
private static void PrepareRequestHeaders(List<HttpHeader> requestHeaders, HttpWebClient webRequest)
{
for (var i = 0; i < requestHeaders.Count; i++)
......@@ -381,6 +423,11 @@ namespace Titanium.Web.Proxy
FixRequestProxyHeaders(requestHeaders);
webRequest.Request.RequestHeaders = requestHeaders;
}
/// <summary>
/// Fix proxy specific headers
/// </summary>
/// <param name="headers"></param>
private static void FixRequestProxyHeaders(List<HttpHeader> headers)
{
//If proxy-connection close was returned inform to close the connection
......@@ -400,7 +447,11 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
}
//This is called when the request is PUT/POST to read the body
/// <summary>
/// This is called when the request is PUT/POST to read the body
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private static async Task SendClientRequestBody(SessionEventArgs args)
{
// End the operation
......@@ -445,6 +496,7 @@ namespace Titanium.Web.Proxy
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
//if user callback is registered then do it
if (ServerCertificateValidationCallback != null)
{
var args = new CertificateValidationEventArgs();
......@@ -511,7 +563,7 @@ namespace Titanium.Web.Proxy
localCertificates.Count > 0)
clientCertificate = localCertificates[0];
//If user call back is registered
if (ClientCertificateSelectionCallback != null)
{
var args = new CertificateSelectionEventArgs();
......
......@@ -11,11 +11,15 @@ using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy
{
/// <summary>
/// Handle the response from server
/// </summary>
partial class ProxyServer
{
//Called asynchronously when a request was successfully and we received the response
public static async Task HandleHttpSessionResponse(SessionEventArgs args)
{
//read response & headers from server
await args.WebSession.ReceiveResponse();
try
......@@ -23,7 +27,7 @@ namespace Titanium.Web.Proxy
if (!args.WebSession.Response.ResponseBodyRead)
args.WebSession.Response.ResponseStream = args.WebSession.ServerConnection.Stream;
//If client request call back then do it
if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked)
{
Delegate[] invocationList = BeforeResponse.GetInvocationList();
......@@ -39,6 +43,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Response.ResponseLocked = true;
//Write back to client 100-conitinue response if that's what server returned
if (args.WebSession.Response.Is100Continue)
{
await WriteResponseStatus(args.WebSession.Response.HttpVersion, "100",
......@@ -52,6 +57,7 @@ namespace Titanium.Web.Proxy
await args.ProxyClient.ClientStreamWriter.WriteLineAsync();
}
//Write back response status
await WriteResponseStatus(args.WebSession.Response.HttpVersion, args.WebSession.Response.ResponseStatusCode,
args.WebSession.Response.ResponseStatusDescription, args.ProxyClient.ClientStreamWriter);
......@@ -95,6 +101,12 @@ namespace Titanium.Web.Proxy
}
}
/// <summary>
/// get the compressed response body from give response bytes
/// </summary>
/// <param name="encodingType"></param>
/// <param name="responseBodyStream"></param>
/// <returns></returns>
private static async Task<byte[]> GetCompressedResponseBody(string encodingType, byte[] responseBodyStream)
{
var compressionFactory = new CompressionFactory();
......@@ -102,13 +114,26 @@ namespace Titanium.Web.Proxy
return await compressor.Compress(responseBodyStream);
}
/// <summary>
/// Write response status
/// </summary>
/// <param name="version"></param>
/// <param name="code"></param>
/// <param name="description"></param>
/// <param name="responseWriter"></param>
/// <returns></returns>
private static async Task WriteResponseStatus(Version version, string code, string description,
StreamWriter responseWriter)
{
await responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description));
}
/// <summary>
/// Write response headers to client
/// </summary>
/// <param name="responseWriter"></param>
/// <param name="headers"></param>
/// <returns></returns>
private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)
{
if (headers != null)
......@@ -124,6 +149,11 @@ namespace Titanium.Web.Proxy
await responseWriter.WriteLineAsync();
await responseWriter.FlushAsync();
}
/// <summary>
/// Fix the proxy specific headers before sending response headers to client
/// </summary>
/// <param name="headers"></param>
private static void FixResponseProxyHeaders(List<HttpHeader> headers)
{
//If proxy-connection close was returned inform to close the connection
......@@ -143,7 +173,14 @@ namespace Titanium.Web.Proxy
headers.RemoveAll(x => x.Name.ToLower() == "proxy-connection");
}
/// <summary>
/// Handle dispose of a client/server session
/// </summary>
/// <param name="client"></param>
/// <param name="clientStream"></param>
/// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param>
/// <param name="args"></param>
private static void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader,
IDisposable clientStreamWriter, IDisposable args)
{
......
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