Commit 606fe644 authored by titanium007's avatar titanium007

Use Async for each session

Make this fully asynchronous. Fix request modification
parent c479518b
...@@ -33,8 +33,9 @@ namespace Titanium.Web.Proxy.Models ...@@ -33,8 +33,9 @@ namespace Titanium.Web.Proxy.Models
internal Stream ClientStream { get; set; } internal Stream ClientStream { get; set; }
internal Stream ServerResponseStream { get; set; } internal Stream ServerResponseStream { get; set; }
internal Encoding Encoding { get; set; } internal Encoding Encoding { get; set; }
internal bool WasModified { get; set; } internal bool RequestWasModified { get; set; }
internal System.Threading.ManualResetEvent FinishedRequestEvent { get; set; } internal bool ResponseWasModified { get; set; }
internal string UpgradeProtocol { get; set; } internal string UpgradeProtocol { get; set; }
...@@ -64,11 +65,13 @@ namespace Titanium.Web.Proxy.Models ...@@ -64,11 +65,13 @@ namespace Titanium.Web.Proxy.Models
mw.Close(); mw.Close();
RequestHtmlBody = Encoding.Default.GetString(mw.ToArray()); RequestHtmlBody = Encoding.Default.GetString(mw.ToArray());
} }
RequestWasModified = true;
return RequestHtmlBody; return RequestHtmlBody;
} }
public void SetRequestHtmlBody(string Body) public void SetRequestHtmlBody(string Body)
{ {
this.RequestHtmlBody = Body; this.RequestHtmlBody = Body;
RequestWasModified = true;
} }
public string GetResponseHtmlBody() public string GetResponseHtmlBody()
{ {
...@@ -97,7 +100,7 @@ namespace Titanium.Web.Proxy.Models ...@@ -97,7 +100,7 @@ namespace Titanium.Web.Proxy.Models
break; break;
} }
ResponseHtmlBody = ResponseData; ResponseHtmlBody = ResponseData;
WasModified = true; ResponseWasModified = true;
} }
return ResponseHtmlBody; return ResponseHtmlBody;
...@@ -153,7 +156,13 @@ namespace Titanium.Web.Proxy.Models ...@@ -153,7 +156,13 @@ namespace Titanium.Web.Proxy.Models
public System.Net.Sockets.TcpClient Client { get; set; }
public string tunnelHostName { get; set; }
public string securehost { get; set; }
} }
} }
\ No newline at end of file
...@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy ...@@ -33,7 +33,7 @@ namespace Titanium.Web.Proxy
private static object certificateAccessLock = new object(); private static object certificateAccessLock = new object();
private static List<string> pinnedCertificateClients = new List<string>(); private static List<string> pinnedCertificateClients = new List<string>();
private static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
private static TcpListener listener; private static TcpListener listener;
private static Thread listenerThread; private static Thread listenerThread;
...@@ -46,6 +46,8 @@ namespace Titanium.Web.Proxy ...@@ -46,6 +46,8 @@ namespace Titanium.Web.Proxy
public static IPAddress ListeningIPInterface { get; set; } public static IPAddress ListeningIPInterface { get; set; }
public static string RootCertificateName { get; set; } public static string RootCertificateName { get; set; }
public static bool EnableSSL { get; set; }
public static bool SetAsSystemProxy { get; set; }
public static Int32 ListeningPort public static Int32 ListeningPort
{ {
...@@ -141,65 +143,24 @@ namespace Titanium.Web.Proxy ...@@ -141,65 +143,24 @@ namespace Titanium.Web.Proxy
{ {
while (ShouldListen) while (ShouldListen)
{ {
// Set the event to nonsignaled state.
tcpClientConnected.Reset(); var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() => HandleClient(client));
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptTcpClientCallback), listener);
// Wait until a connection is made and processed before
// continuing.
tcpClientConnected.WaitOne();
} }
} }
catch (ThreadInterruptedException) { } catch (ThreadInterruptedException) { }
catch (SocketException ex) catch (SocketException)
{ {
Debug.WriteLine(ex.Message);
}
}
public static void AcceptTcpClientCallback(IAsyncResult ar)
{
try
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = null;
// End the operation and display the received data on
// the console.
client = listener.EndAcceptTcpClient(ar);
Task.Factory.StartNew(() => ProcessClient(client));
// Signal the calling thread to continue.
tcpClientConnected.Set();
} }
catch(ObjectDisposedException) { }
}
private static void ProcessClient(Object param)
{
try
{
TcpClient client = param as TcpClient;
HandleClientRequest(client);
client.Close();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
} }
public static bool EnableSSL { get; set; }
public static bool SetAsSystemProxy { get; set; }
} }
} }
\ No newline at end of file
...@@ -13,6 +13,7 @@ using System.Security.Cryptography.X509Certificates; ...@@ -13,6 +13,7 @@ using System.Security.Cryptography.X509Certificates;
using System.Reflection; using System.Reflection;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
...@@ -21,7 +22,7 @@ namespace Titanium.Web.Proxy ...@@ -21,7 +22,7 @@ namespace Titanium.Web.Proxy
partial class ProxyServer partial class ProxyServer
{ {
private static void HandleClientRequest(TcpClient Client) private static void HandleClient(TcpClient Client)
{ {
string connectionGroup = null; string connectionGroup = null;
...@@ -120,7 +121,7 @@ namespace Titanium.Web.Proxy ...@@ -120,7 +121,7 @@ namespace Titanium.Web.Proxy
return; return;
} }
Monitor.Enter(certificateAccessLock); Monitor.Enter(certificateAccessLock);
var _certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName); //CertificateHelper.GetCertificate(RootCertificateName, tunnelHostName); var _certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName);
Monitor.Exit(certificateAccessLock); Monitor.Exit(certificateAccessLock);
SslStream sslStream = null; SslStream sslStream = null;
...@@ -173,223 +174,202 @@ namespace Titanium.Web.Proxy ...@@ -173,223 +174,202 @@ namespace Titanium.Web.Proxy
securehost = remoteUri; securehost = remoteUri;
} }
int count = 0; HandleHttpSessionRequest(Client, httpCmd, connectionGroup, clientStream, tunnelHostName, requestLines, clientStreamReader, securehost);
SessionEventArgs args = new SessionEventArgs(BUFFER_SIZE);
while (!String.IsNullOrEmpty(httpCmd)) }
{ catch (AuthenticationException)
{
count++; return;
}
catch (EndOfStreamException)
{
return;
}
catch (IOException)
{
return;
}
catch (UriFormatException)
{
return;
}
catch (WebException)
{
return;
}
finally
{
MemoryStream mw = null;
StreamWriter sw = null;
args = new SessionEventArgs(BUFFER_SIZE);
try }
{
splitBuffer = httpCmd.Split(spaceSplit, 3);
if (splitBuffer.Length != 3)
{
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
if (clientStream != null) }
clientStream.Close(); private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, string connectionGroup, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, string securehost)
{
return;
}
method = splitBuffer[0];
remoteUri = splitBuffer[1];
if (splitBuffer[2] == "HTTP/1.1") if (httpCmd == null) return;
{
version = new Version(1, 1);
}
else
{
version = new Version(1, 0);
}
if (securehost != null)
{
remoteUri = securehost + remoteUri;
args.IsSSLRequest = true;
}
//construct the web request that we are going to issue on behalf of the client. var args = new SessionEventArgs(BUFFER_SIZE);
args.ProxyRequest = (HttpWebRequest)HttpWebRequest.Create(remoteUri.Trim()); args.Client = Client;
args.ProxyRequest.Proxy = null; args.tunnelHostName = tunnelHostName;
args.ProxyRequest.UseDefaultCredentials = true; args.securehost = securehost;
args.ProxyRequest.Method = method; try
args.ProxyRequest.ProtocolVersion = version; {
args.ClientStream = clientStream; var splitBuffer = httpCmd.Split(spaceSplit, 3);
args.ClientStreamReader = clientStreamReader;
for (int i = 1; i < requestLines.Count; i++) if (splitBuffer.Length != 3)
{ {
var rawHeader = requestLines[i]; TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
if ((header[0] == "upgrade") && (header[1] == "websocket")) if (clientStream != null)
{ clientStream.Close();
return;
}
var method = splitBuffer[0];
var remoteUri = splitBuffer[1];
Version version;
if (splitBuffer[2] == "HTTP/1.1")
{
version = new Version(1, 1);
}
else
{
version = new Version(1, 0);
}
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); if (securehost != null)
{
remoteUri = securehost + remoteUri;
args.IsSSLRequest = true;
}
if (clientStream != null) //construct the web request that we are going to issue on behalf of the client.
clientStream.Close(); args.ProxyRequest = (HttpWebRequest)HttpWebRequest.Create(remoteUri.Trim());
args.ProxyRequest.Proxy = null;
args.ProxyRequest.UseDefaultCredentials = true;
args.ProxyRequest.Method = method;
args.ProxyRequest.ProtocolVersion = version;
args.ClientStream = clientStream;
args.ClientStreamReader = clientStreamReader;
return; for (int i = 1; i < requestLines.Count; i++)
} {
} var rawHeader = requestLines[i];
String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None);
ReadRequestHeaders(ref requestLines, args.ProxyRequest); if ((header[0] == "upgrade") && (header[1] == "websocket"))
{
int contentLen = (int)args.ProxyRequest.ContentLength; TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
args.ProxyRequest.AllowAutoRedirect = false; if (clientStream != null)
args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None; clientStream.Close();
if (BeforeRequest != null) return;
{ }
args.RequestHostname = args.ProxyRequest.RequestUri.Host; }
args.RequestURL = args.ProxyRequest.RequestUri.OriginalString;
args.RequestLength = contentLen; ReadRequestHeaders(ref requestLines, args.ProxyRequest);
args.RequestHttpVersion = version;
args.ClientPort = ((IPEndPoint)Client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)Client.Client.RemoteEndPoint).Address;
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
BeforeRequest(null, args); int contentLen = (int)args.ProxyRequest.ContentLength;
}
if (args.CancelRequest)
{
if (args.RequestIsAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count > 0 ? requestLines[0] : null; args.ProxyRequest.AllowAutoRedirect = false;
continue; args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None;
}
else
break;
}
args.ProxyRequest.ConnectionGroupName = connectionGroup; if (BeforeRequest != null)
args.ProxyRequest.AllowWriteStreamBuffering = true; {
args.RequestHostname = args.ProxyRequest.RequestUri.Host;
args.RequestURL = args.ProxyRequest.RequestUri.OriginalString;
args.FinishedRequestEvent = new ManualResetEvent(false); args.RequestLength = contentLen;
args.RequestHttpVersion = version;
args.ClientPort = ((IPEndPoint)Client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)Client.Client.RemoteEndPoint).Address;
args.RequestIsAlive = args.ProxyRequest.KeepAlive;
if (method.ToUpper() == "POST" || method.ToUpper() == "PUT") BeforeRequest(null, args);
{ }
args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args); string tmpLine;
} if (args.CancelRequest)
else {
if (args.RequestIsAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{ {
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleServerResponse), args); requestLines.Add(tmpLine);
} }
httpCmd = requestLines.Count > 0 ? requestLines[0] : null;
return;
}
else
return;
}
if (args.IsSSLRequest) args.ProxyRequest.ConnectionGroupName = connectionGroup;
{ args.ProxyRequest.AllowWriteStreamBuffering = true;
if (args.ProxyRequest.Method == "POST" || args.ProxyRequest.Method == "PUT")
args.FinishedRequestEvent.WaitOne();
else
args.FinishedRequestEvent.Set();
}
else
args.FinishedRequestEvent.WaitOne();
httpCmd = null;
if (args.ProxyRequest.KeepAlive)
{
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
}
if (args.RequestWasModified)
{
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] requestBytes = encoding.GetBytes(args.RequestHtmlBody);
args.ProxyRequest.ContentLength = requestBytes.Length;
Stream newStream = args.ProxyRequest.GetRequestStream();
newStream.Write(requestBytes, 0, requestBytes.Length);
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
if (args.ServerResponse != null) }
args.ServerResponse.Close(); else
} {
catch (IOException ex) if (method.ToUpper() == "POST" || method.ToUpper() == "PUT")
{
throw ex;
}
catch (UriFormatException ex)
{ {
throw ex; args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args);
} }
catch (WebException ex) else
{ {
throw ex; args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
} }
finally
{
if (sw != null) sw.Close();
if (mw != null) mw.Close();
if (args.ProxyRequest != null) args.ProxyRequest.Abort();
if (args.ServerResponseStream != null) args.ServerResponseStream.Close();
}
} }
}
catch (AuthenticationException ex)
{
Debug.WriteLine(ex.Message);
}
catch (EndOfStreamException ex)
{
Debug.WriteLine(ex.Message);
} }
catch (IOException ex) catch (IOException ex)
{ {
Debug.WriteLine(ex.Message); return;
} }
catch (UriFormatException ex) catch (UriFormatException ex)
{ {
Debug.WriteLine(ex.Message); return;
} }
catch (WebException ex) catch (WebException ex)
{ {
Debug.WriteLine(ex.Message); return;
} }
finally finally
{ {
if (connectStreamWriter != null)
connectStreamWriter.Close();
if (clientStreamReader != null)
clientStreamReader.Close();
if (clientStream != null)
clientStream.Close();
} }
} }
private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebRequest WebRequest) private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebRequest WebRequest)
{ {
...@@ -467,7 +447,7 @@ namespace Titanium.Web.Proxy ...@@ -467,7 +447,7 @@ namespace Titanium.Web.Proxy
break; break;
default: default:
if (header.Length > 0) if (header.Length >= 2)
WebRequest.Headers.Add(header[0], header[1]); WebRequest.Headers.Add(header[0], header[1]);
else else
WebRequest.Headers.Add(header[0], ""); WebRequest.Headers.Add(header[0], "");
...@@ -527,7 +507,6 @@ namespace Titanium.Web.Proxy ...@@ -527,7 +507,6 @@ namespace Titanium.Web.Proxy
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message); Debug.WriteLine(ex.Message);
return; return;
} }
...@@ -536,7 +515,6 @@ namespace Titanium.Web.Proxy ...@@ -536,7 +515,6 @@ namespace Titanium.Web.Proxy
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message); Debug.WriteLine(ex.Message);
return; return;
...@@ -609,7 +587,6 @@ namespace Titanium.Web.Proxy ...@@ -609,7 +587,6 @@ namespace Titanium.Web.Proxy
postStream.Close(); postStream.Close();
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message); Debug.WriteLine(ex.Message);
return; return;
} }
...@@ -619,14 +596,13 @@ namespace Titanium.Web.Proxy ...@@ -619,14 +596,13 @@ namespace Titanium.Web.Proxy
postStream.Close(); postStream.Close();
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
args.FinishedRequestEvent.Set();
Debug.WriteLine(ex.Message); Debug.WriteLine(ex.Message);
return; return;
} }
} }
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleServerResponse), args); args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
} }
......
...@@ -11,12 +11,13 @@ using System.Security.Authentication; ...@@ -11,12 +11,13 @@ using System.Security.Authentication;
using System.Diagnostics; using System.Diagnostics;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
partial class ProxyServer partial class ProxyServer
{ {
private static void HandleServerResponse(IAsyncResult AsynchronousResult) private static void HandleHttpSessionResponse(IAsyncResult AsynchronousResult)
{ {
SessionEventArgs args = (SessionEventArgs)AsynchronousResult.AsyncState; SessionEventArgs args = (SessionEventArgs)AsynchronousResult.AsyncState;
...@@ -55,7 +56,7 @@ namespace Titanium.Web.Proxy ...@@ -55,7 +56,7 @@ namespace Titanium.Web.Proxy
if (BeforeResponse != null) if (BeforeResponse != null)
BeforeResponse(null, args); BeforeResponse(null, args);
if (args.WasModified) if (args.ResponseWasModified)
{ {
byte[] data; byte[] data;
...@@ -137,21 +138,36 @@ namespace Titanium.Web.Proxy ...@@ -137,21 +138,36 @@ namespace Titanium.Web.Proxy
finally finally
{ {
if (args.ProxyRequest.KeepAlive == false) if (args.ProxyRequest != null) args.ProxyRequest.Abort();
{ if (args.ServerResponseStream != null) args.ServerResponseStream.Close();
if (responseWriter != null)
responseWriter.Close();
if (clientWriteStream != null)
clientWriteStream.Close();
}
if (args.ServerResponse != null) if (args.ServerResponse != null)
args.ServerResponse.Close(); args.ServerResponse.Close();
args.FinishedRequestEvent.Set(); }
if (args.ProxyRequest.KeepAlive == false)
{
if (responseWriter != null)
responseWriter.Close();
if (clientWriteStream != null)
clientWriteStream.Close();
args.Client.Close();
}
else
{
string httpCmd, tmpLine;
List<string> requestLines = new List<string>();
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = args.ClientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
TcpClient Client = args.Client;
HandleHttpSessionRequest(Client, httpCmd, args.ProxyRequest.ConnectionGroupName, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.securehost);
} }
} }
......
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