Commit 9115e03f authored by justcoding121's avatar justcoding121 Committed by justcoding121

Fix stack overflow

Fixed stack overflow by avoiding recursive calls using threadpool
parent affaacf2
...@@ -16,17 +16,17 @@ namespace Titanium.Web.Proxy.Test ...@@ -16,17 +16,17 @@ namespace Titanium.Web.Proxy.Test
public static void Main(string[] args) public static void Main(string[] args)
{ {
//On Console exit make sure we also exit the proxy //On Console exit make sure we also exit the proxy
handler = new ConsoleEventDelegate(ConsoleEventCallback); NativeMethods.handler = new NativeMethods.ConsoleEventDelegate(ConsoleEventCallback);
SetConsoleCtrlHandler(handler, true); NativeMethods.SetConsoleCtrlHandler(NativeMethods.handler, true);
Console.Write("Do you want to monitor HTTPS? (Y/N):"); Console.Write("Do you want to monitor HTTPS? (Y/N):");
if(Console.ReadLine().Trim().ToLower()=="y" ) if (Console.ReadLine().Trim().ToLower() == "y")
{ {
controller.EnableSSL = true; controller.EnableSSL = true;
} }
Console.Write("Do you want to set this as a System Proxy? (Y/N):"); Console.Write("Do you want to set this as a System Proxy? (Y/N):");
...@@ -36,18 +36,18 @@ namespace Titanium.Web.Proxy.Test ...@@ -36,18 +36,18 @@ namespace Titanium.Web.Proxy.Test
controller.SetAsSystemProxy = true; controller.SetAsSystemProxy = true;
} }
//Start proxy controller //Start proxy controller
controller.StartProxy(); controller.StartProxy();
Console.WriteLine("Hit any key to exit.."); Console.WriteLine("Hit any key to exit..");
Console.WriteLine(); Console.WriteLine();
Console.Read(); Console.Read();
controller.Stop(); controller.Stop();
} }
static bool ConsoleEventCallback(int eventType) static bool ConsoleEventCallback(int eventType)
{ {
if (eventType == 2) if (eventType == 2)
...@@ -55,21 +55,25 @@ namespace Titanium.Web.Proxy.Test ...@@ -55,21 +55,25 @@ namespace Titanium.Web.Proxy.Test
try try
{ {
controller.Stop(); controller.Stop();
} }
catch { } catch { }
} }
return false; return false;
} }
// Keeps it from getting garbage collected
private static ConsoleEventDelegate handler; }
// Pinvoke internal static class NativeMethods
private delegate bool ConsoleEventDelegate(int eventType); {
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add); internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
// Pinvoke
internal delegate bool ConsoleEventDelegate(int eventType);
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate handler;
} }
} }
...@@ -59,14 +59,34 @@ namespace Titanium.Web.Proxy.Test ...@@ -59,14 +59,34 @@ namespace Titanium.Web.Proxy.Test
Console.WriteLine(e.RequestURL); Console.WriteLine(e.RequestURL);
//To cancel a request with a custom HTML content
//Filter URL
//if (e.RequestURL.Contains("somewebsite.com"))
//{
// e.Ok("<!DOCTYPE html><html><body><h1>Blocked</h1><p>website blocked.</p></body></html>");
//}
} }
//Test script injection //Test script injection
//Insert script to read the Browser URL and send it back to proxy //Insert script to read the Browser URL and send it back to proxy
public void OnResponse(object sender, SessionEventArgs e) public void OnResponse(object sender, SessionEventArgs e)
{ {
//To modify a response
//if (e.ServerResponse.StatusCode == HttpStatusCode.OK)
//{
// if (e.ServerResponse.ContentType.Trim().ToLower().Contains("text/html"))
// {
// //Get response body
// string responseHtmlBody = e.GetResponseHtmlBody();
// //Modify e.ServerResponse
// responseHtmlBody = "<html><head></head><body>Response is modified!</body></html>";
// //Set modifed response Html Body
// e.SetResponseHtmlBody(responseHtmlBody);
// }
//}
} }
......
...@@ -56,4 +56,7 @@ Global ...@@ -56,4 +56,7 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
EndGlobalSection EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal EndGlobal
...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Helpers
private const string CERT_CREATE_FORMAT = private const string CERT_CREATE_FORMAT =
"-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 -b {5:MM/dd/yyyy} {6}"; "-ss {0} -n \"CN={1}, O={2}\" -sky {3} -cy {4} -m 120 -a sha256 -eku 1.3.6.1.5.5.7.3.1 -b {5:MM/dd/yyyy} {6}";
private readonly IDictionary<string, X509Certificate2> _certificateCache; private readonly IDictionary<string, X509Certificate2> certificateCache;
public string Issuer { get; private set; } public string Issuer { get; private set; }
public string RootCertificateName { get; private set; } public string RootCertificateName { get; private set; }
...@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
MyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); MyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
RootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser); RootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
_certificateCache = new Dictionary<string, X509Certificate2>(); certificateCache = new Dictionary<string, X509Certificate2>();
} }
/// <summary> /// <summary>
...@@ -69,8 +69,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -69,8 +69,8 @@ namespace Titanium.Web.Proxy.Helpers
} }
protected virtual X509Certificate2 CreateCertificate(X509Store store, string certificateName) protected virtual X509Certificate2 CreateCertificate(X509Store store, string certificateName)
{ {
if (_certificateCache.ContainsKey(certificateName)) if (certificateCache.ContainsKey(certificateName))
return _certificateCache[certificateName]; return certificateCache[certificateName];
lock (store) lock (store)
{ {
...@@ -102,8 +102,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -102,8 +102,8 @@ namespace Titanium.Web.Proxy.Helpers
finally finally
{ {
store.Close(); store.Close();
if (certificate != null && !_certificateCache.ContainsKey(certificateName)) if (certificate != null && !certificateCache.ContainsKey(certificateName))
_certificateCache.Add(certificateName, certificate); certificateCache.Add(certificateName, certificate);
} }
} }
} }
...@@ -151,9 +151,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -151,9 +151,9 @@ namespace Titanium.Web.Proxy.Helpers
{ {
store.Close(); store.Close();
if (certificates == null && if (certificates == null &&
_certificateCache.ContainsKey(certificateName)) certificateCache.ContainsKey(certificateName))
{ {
_certificateCache.Remove(certificateName); certificateCache.Remove(certificateName);
} }
} }
} }
......
...@@ -3,6 +3,7 @@ using System.Collections.Generic; ...@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.IO; using System.IO;
using System.Diagnostics.CodeAnalysis;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
...@@ -32,10 +33,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -32,10 +33,11 @@ namespace Titanium.Web.Proxy.Helpers
} }
public static byte[] CompressZlib(string ResponseData, Encoding e) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressZlib(string responseData, Encoding e)
{ {
Byte[] bytes = e.GetBytes(ResponseData); Byte[] bytes = e.GetBytes(responseData);
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
{ {
...@@ -45,17 +47,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -45,17 +47,16 @@ namespace Titanium.Web.Proxy.Helpers
zip.Write(bytes, 0, bytes.Length); zip.Write(bytes, 0, bytes.Length);
} }
return ms.ToArray(); return ms.ToArray();
} }
} }
public static byte[] CompressDeflate(string ResponseData, Encoding e) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressDeflate(string responseData, Encoding e)
{ {
Byte[] bytes = e.GetBytes(ResponseData); Byte[] bytes = e.GetBytes(responseData);
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
{ {
...@@ -70,9 +71,10 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -70,9 +71,10 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
public static byte[] CompressGzip(string ResponseData, Encoding e) [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
public static byte[] CompressGzip(string responseData, Encoding e)
{ {
Byte[] bytes = e.GetBytes(ResponseData); Byte[] bytes = e.GetBytes(responseData);
using (MemoryStream ms = new MemoryStream()) using (MemoryStream ms = new MemoryStream())
{ {
......
...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Helpers
public string ReadLine() public string ReadLine()
{ {
char[] buf = new char[1]; char[] buf = new char[1];
StringBuilder _readBuffer = new StringBuilder(); StringBuilder readBuffer = new StringBuilder();
try try
{ {
var charsRead = 0; var charsRead = 0;
...@@ -29,24 +29,24 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -29,24 +29,24 @@ namespace Titanium.Web.Proxy.Helpers
{ {
if (lastChar == '\r' && buf[0] == '\n') if (lastChar == '\r' && buf[0] == '\n')
{ {
return _readBuffer.Remove(_readBuffer.Length - 1, 1).ToString(); return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
} }
else else
if (buf[0] == '\0') if (buf[0] == '\0')
{ {
return _readBuffer.ToString(); return readBuffer.ToString();
} }
else else
_readBuffer.Append(buf[0]); readBuffer.Append(buf[0]);
lastChar = buf[0]; lastChar = buf[0];
} }
return _readBuffer.ToString(); return readBuffer.ToString();
} }
catch (IOException) catch (IOException)
{ return _readBuffer.ToString(); } { return readBuffer.ToString(); }
catch (Exception e) catch (Exception)
{ throw e; } { throw; }
} }
......
...@@ -8,6 +8,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -8,6 +8,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
public class NetFrameworkHelper public class NetFrameworkHelper
{ {
//Fix bug in .Net 4.0 HttpWebRequest (don't use this for 4.5 and above)
//http://stackoverflow.com/questions/856885/httpwebrequest-to-url-with-dot-at-the-end //http://stackoverflow.com/questions/856885/httpwebrequest-to-url-with-dot-at-the-end
public static void URLPeriodFix() public static void URLPeriodFix()
{ {
......
...@@ -7,12 +7,16 @@ using System.Runtime.InteropServices; ...@@ -7,12 +7,16 @@ using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
public static class SystemProxyHelper internal static class NativeMethods
{ {
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
public const int INTERNET_OPTION_SETTINGS_CHANGED = 39; }
public const int INTERNET_OPTION_REFRESH = 37; public static class SystemProxyHelper
{
public const int INTERNET_OPTION_SETTINGS_CHANGED = 39;
public const int INTERNET_OPTION_REFRESH = 37;
static bool settingsReturn, refreshReturn; static bool settingsReturn, refreshReturn;
static object prevProxyServer; static object prevProxyServer;
static object prevProxyEnable; static object prevProxyEnable;
...@@ -23,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -23,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
prevProxyEnable = reg.GetValue("ProxyEnable"); prevProxyEnable = reg.GetValue("ProxyEnable");
prevProxyServer = reg.GetValue("ProxyServer"); prevProxyServer = reg.GetValue("ProxyServer");
reg.SetValue("ProxyEnable", 1); reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", "http="+hostname+":" + port + ";"); reg.SetValue("ProxyServer", "http=" + hostname + ":" + port + ";");
refresh(); refresh();
} }
public static void EnableProxyHTTPS(string hostname, int port) public static void EnableProxyHTTPS(string hostname, int port)
...@@ -43,8 +47,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -43,8 +47,8 @@ namespace Titanium.Web.Proxy.Helpers
} }
private static void refresh() private static void refresh()
{ {
settingsReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); settingsReturn = NativeMethods.InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); refreshReturn = NativeMethods.InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
} }
} }
} }
...@@ -13,16 +13,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -13,16 +13,16 @@ namespace Titanium.Web.Proxy.Helpers
{ {
private static readonly int BUFFER_SIZE = 8192; private static readonly int BUFFER_SIZE = 8192;
private static readonly String[] colonSpaceSplit = new string[] { ": " }; private static readonly String[] colonSpaceSplit = new string[] { ": " };
public static void SendRaw(string Hostname, int TunnelPort, System.IO.Stream ClientStream) public static void SendRaw(string hostname, int tunnelPort, System.IO.Stream clientStream)
{ {
System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(Hostname, TunnelPort); System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(hostname, tunnelPort);
var tunnelStream = tunnelClient.GetStream(); var tunnelStream = tunnelClient.GetStream();
var tunnelReadBuffer = new byte[BUFFER_SIZE]; var tunnelReadBuffer = new byte[BUFFER_SIZE];
Task sendRelay = new Task(() => StreamHelper.CopyTo(ClientStream, tunnelStream, BUFFER_SIZE)); Task sendRelay = new Task(() => StreamHelper.CopyTo(clientStream, tunnelStream, BUFFER_SIZE));
Task receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, ClientStream, BUFFER_SIZE)); Task receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start(); sendRelay.Start();
receiveRelay.Start(); receiveRelay.Start();
...@@ -35,21 +35,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -35,21 +35,21 @@ namespace Titanium.Web.Proxy.Helpers
if (tunnelClient != null) if (tunnelClient != null)
tunnelClient.Close(); tunnelClient.Close();
} }
public static void SendRaw(string HttpCmd, string SecureHostName, ref List<string> RequestLines, bool IsHttps, Stream ClientStream) public static void SendRaw(string httpCmd, string secureHostName, List<string> requestLines, bool isHttps, Stream clientStream)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append(HttpCmd); sb.Append(httpCmd);
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
string hostname = SecureHostName; string hostname = secureHostName;
for (int i = 1; i < RequestLines.Count; i++) for (int i = 1; i < requestLines.Count; i++)
{ {
var header = RequestLines[i]; var header = requestLines[i];
if (SecureHostName == null) if (secureHostName == null)
{ {
String[] headerParsed = HttpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None); String[] headerParsed = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None);
switch (headerParsed[0].ToLower()) switch (headerParsed[0].ToLower())
{ {
case "host": case "host":
...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.Helpers
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
int tunnelPort = 80; int tunnelPort = 80;
if (IsHttps) if (isHttps)
{ {
tunnelPort = 443; tunnelPort = 443;
...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Helpers
System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(hostname, tunnelPort); System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(hostname, tunnelPort);
var tunnelStream = tunnelClient.GetStream() as System.IO.Stream; var tunnelStream = tunnelClient.GetStream() as System.IO.Stream;
if (IsHttps) if (isHttps)
{ {
var sslStream = new SslStream(tunnelStream); var sslStream = new SslStream(tunnelStream);
sslStream.AuthenticateAsClient(hostname); sslStream.AuthenticateAsClient(hostname);
...@@ -87,8 +87,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -87,8 +87,8 @@ namespace Titanium.Web.Proxy.Helpers
} }
var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), ClientStream, tunnelStream, BUFFER_SIZE)); var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), clientStream, tunnelStream, BUFFER_SIZE));
var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, ClientStream, BUFFER_SIZE)); var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start(); sendRelay.Start();
receiveRelay.Start(); receiveRelay.Start();
......
...@@ -3,48 +3,73 @@ using System.Text; ...@@ -3,48 +3,73 @@ using System.Text;
using System.IO; using System.IO;
using System.Net; using System.Net;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using System.Net.Sockets;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
public class SessionEventArgs : EventArgs public class SessionEventArgs : EventArgs, IDisposable
{ {
public string RequestURL { get; set; }
public string RequestHostname { get; set; }
public bool IsSSLRequest { get; set; }
public int ClientPort { get; set; }
public IPAddress ClientIpAddress { get; set; }
public HttpWebRequest ProxyRequest { get; set; }
public HttpWebResponse ServerResponse { get; set; }
internal int BUFFER_SIZE; internal int BUFFER_SIZE;
internal Stream ClientStream { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal StreamWriter ClientStreamWriter { get; set; }
internal string UpgradeProtocol { get; set; }
internal Encoding Encoding { get; set; }
internal int RequestLength { get; set; } internal int RequestLength { get; set; }
internal Version RequestHttpVersion { get; set; } internal Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; } internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; } internal bool CancelRequest { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; } internal string RequestHtmlBody { get; set; }
internal Stream ClientStream { get; set; }
internal Stream ServerResponseStream { get; set; }
internal Encoding Encoding { get; set; }
internal bool RequestWasModified { get; set; } internal bool RequestWasModified { get; set; }
internal Stream ServerResponseStream { get; set; }
internal string ResponseHtmlBody { get; set; }
internal bool ResponseWasModified { get; set; } internal bool ResponseWasModified { get; set; }
internal string UpgradeProtocol { get; set; }
public TcpClient Client { get; set; }
public int ClientPort { get; set; }
public IPAddress ClientIpAddress { get; set; }
public string tunnelHostName { get; set; }
public string securehost { get; set; }
public bool IsSSLRequest { get; set; }
public string RequestURL { get; set; }
public string RequestHostname { get; set; }
public HttpWebRequest ProxyRequest { get; set; }
public HttpWebResponse ServerResponse { get; set; }
public void Dispose()
{
if (this.ProxyRequest != null)
this.ProxyRequest.Abort();
internal string RequestHtmlBody { get; set; } if (this.ServerResponseStream != null)
internal string ResponseHtmlBody { get; set; } this.ServerResponseStream.Dispose();
if (this.ServerResponse != null)
this.ServerResponse.Close();
if (this.ClientStreamReader != null)
this.ClientStreamReader.Dispose();
if (this.ClientStreamWriter != null)
this.ClientStreamWriter.Dispose();
public SessionEventArgs(int BufferSize) if (this.ClientStream != null)
this.ClientStream.Dispose();
if (this.Client != null)
this.Client.Close();
}
public SessionEventArgs(int bufferSize)
{ {
BUFFER_SIZE = BufferSize; BUFFER_SIZE = bufferSize;
} }
public string GetRequestHtmlBody() public string GetRequestHtmlBody()
{ {
...@@ -68,9 +93,9 @@ namespace Titanium.Web.Proxy.Models ...@@ -68,9 +93,9 @@ namespace Titanium.Web.Proxy.Models
RequestWasModified = true; RequestWasModified = true;
return RequestHtmlBody; return RequestHtmlBody;
} }
public void SetRequestHtmlBody(string Body) public void SetRequestHtmlBody(string body)
{ {
this.RequestHtmlBody = Body; this.RequestHtmlBody = body;
RequestWasModified = true; RequestWasModified = true;
} }
public string GetResponseHtmlBody() public string GetResponseHtmlBody()
...@@ -101,30 +126,30 @@ namespace Titanium.Web.Proxy.Models ...@@ -101,30 +126,30 @@ namespace Titanium.Web.Proxy.Models
} }
ResponseHtmlBody = ResponseData; ResponseHtmlBody = ResponseData;
ResponseWasModified = true; ResponseWasModified = true;
} }
return ResponseHtmlBody; return ResponseHtmlBody;
} }
public void SetResponseHtmlBody(string Body) public void SetResponseHtmlBody(string body)
{ {
this.ResponseHtmlBody = Body; this.ResponseHtmlBody = body;
} }
//stream reader not recomended for images //stream reader not recomended for images
private string DecodeData(Stream ResponseStream, Encoding e) private string DecodeData(Stream responseStream, Encoding e)
{ {
StreamReader reader = new StreamReader(ResponseStream, e); StreamReader reader = new StreamReader(responseStream, e);
return reader.ReadToEnd(); return reader.ReadToEnd();
} }
public void Ok(string Html) public void Ok(string html)
{ {
if (Html == null) if (html == null)
Html = string.Empty; html = string.Empty;
var result = Encoding.Default.GetBytes(Html); var result = Encoding.Default.GetBytes(html);
StreamWriter connectStreamWriter = new StreamWriter(ClientStream); StreamWriter connectStreamWriter = new StreamWriter(ClientStream);
var s = String.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok"); var s = String.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok");
...@@ -153,16 +178,6 @@ namespace Titanium.Web.Proxy.Models ...@@ -153,16 +178,6 @@ 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
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Titanium.Web.Proxy.Properties")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Proxy.Properties")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5036e0b7-a0d0-4070-8eb0-72c129dee9b3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
...@@ -38,6 +38,8 @@ namespace Titanium.Web.Proxy ...@@ -38,6 +38,8 @@ namespace Titanium.Web.Proxy
private static TcpListener listener; private static TcpListener listener;
private static Thread listenerThread; private static Thread listenerThread;
private static bool ShouldListen { get; set; }
public static event EventHandler<SessionEventArgs> BeforeRequest; public static event EventHandler<SessionEventArgs> BeforeRequest;
public static event EventHandler<SessionEventArgs> BeforeResponse; public static event EventHandler<SessionEventArgs> BeforeResponse;
...@@ -64,6 +66,7 @@ namespace Titanium.Web.Proxy ...@@ -64,6 +66,7 @@ namespace Titanium.Web.Proxy
CertManager = new CertificateManager("Titanium", CertManager = new CertificateManager("Titanium",
"Titanium Root Certificate Authority"); "Titanium Root Certificate Authority");
} }
public ProxyServer() public ProxyServer()
{ {
...@@ -87,7 +90,26 @@ namespace Titanium.Web.Proxy ...@@ -87,7 +90,26 @@ namespace Titanium.Web.Proxy
} }
private static bool ShouldListen { get; set; } private static void Listen(Object obj)
{
TcpListener listener = (TcpListener)obj;
try
{
while (ShouldListen)
{
var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() => HandleClient(client));
}
}
catch (ThreadInterruptedException) { }
catch (SocketException) { }
}
public static bool Start() public static bool Start()
{ {
...@@ -138,25 +160,7 @@ namespace Titanium.Web.Proxy ...@@ -138,25 +160,7 @@ namespace Titanium.Web.Proxy
} }
private static void Listen(Object obj)
{
TcpListener listener = (TcpListener)obj;
try
{
while (ShouldListen)
{
var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() => HandleClient(client));
}
}
catch (ThreadInterruptedException) { }
catch (SocketException) { }
}
......
...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy ...@@ -22,7 +22,7 @@ namespace Titanium.Web.Proxy
partial class ProxyServer partial class ProxyServer
{ {
private static void HandleClient(TcpClient Client) private static void HandleClient(TcpClient client)
{ {
...@@ -36,7 +36,7 @@ namespace Titanium.Web.Proxy ...@@ -36,7 +36,7 @@ namespace Titanium.Web.Proxy
{ {
clientStream = Client.GetStream(); clientStream = client.GetStream();
clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII); clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII);
string securehost = null; string securehost = null;
...@@ -138,7 +138,7 @@ namespace Titanium.Web.Proxy ...@@ -138,7 +138,7 @@ namespace Titanium.Web.Proxy
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false); sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
} }
catch (AuthenticationException ex) catch (AuthenticationException)
{ {
//if authentication failed it could be because client uses pinned certificates //if authentication failed it could be because client uses pinned certificates
//So add the hostname to this list so that next time we can relay without touching it (tunnel the request) //So add the hostname to this list so that next time we can relay without touching it (tunnel the request)
...@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy ...@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy
{ {
pinnedCertificateClients.Add(tunnelHostName); pinnedCertificateClients.Add(tunnelHostName);
} }
throw ex; throw;
} }
} }
...@@ -180,7 +180,7 @@ namespace Titanium.Web.Proxy ...@@ -180,7 +180,7 @@ namespace Titanium.Web.Proxy
} }
//Now create the request //Now create the request
HandleHttpSessionRequest(Client, httpCmd, clientStream, tunnelHostName, requestLines, clientStreamReader, securehost); Task.Factory.StartNew(()=>HandleHttpSessionRequest(client, httpCmd, clientStream, tunnelHostName, requestLines, clientStreamReader, securehost));
...@@ -211,7 +211,7 @@ namespace Titanium.Web.Proxy ...@@ -211,7 +211,7 @@ namespace Titanium.Web.Proxy
} }
} }
private static void HandleHttpSessionRequest(TcpClient Client, string httpCmd, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, string securehost) private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, string securehost)
{ {
...@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy ...@@ -219,7 +219,7 @@ namespace Titanium.Web.Proxy
var args = new SessionEventArgs(BUFFER_SIZE); var args = new SessionEventArgs(BUFFER_SIZE);
args.Client = Client; args.Client = client;
args.tunnelHostName = tunnelHostName; args.tunnelHostName = tunnelHostName;
args.securehost = securehost; args.securehost = securehost;
try try
...@@ -229,7 +229,7 @@ namespace Titanium.Web.Proxy ...@@ -229,7 +229,7 @@ namespace Titanium.Web.Proxy
if (splitBuffer.Length != 3) if (splitBuffer.Length != 3)
{ {
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); TcpHelper.SendRaw(httpCmd, tunnelHostName, requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
if (clientStream != null) if (clientStream != null)
clientStream.Close(); clientStream.Close();
...@@ -272,7 +272,7 @@ namespace Titanium.Web.Proxy ...@@ -272,7 +272,7 @@ namespace Titanium.Web.Proxy
if ((header[0] == "upgrade") && (header[1] == "websocket")) if ((header[0] == "upgrade") && (header[1] == "websocket"))
{ {
TcpHelper.SendRaw(httpCmd, tunnelHostName, ref requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); TcpHelper.SendRaw(httpCmd, tunnelHostName, requestLines, args.IsSSLRequest, clientStreamReader.BaseStream);
if (clientStream != null) if (clientStream != null)
clientStream.Close(); clientStream.Close();
...@@ -281,7 +281,7 @@ namespace Titanium.Web.Proxy ...@@ -281,7 +281,7 @@ namespace Titanium.Web.Proxy
} }
} }
ReadRequestHeaders(ref requestLines, args.ProxyRequest); SetClientRequestHeaders(requestLines, args.ProxyRequest);
int contentLen = (int)args.ProxyRequest.ContentLength; int contentLen = (int)args.ProxyRequest.ContentLength;
...@@ -298,8 +298,8 @@ namespace Titanium.Web.Proxy ...@@ -298,8 +298,8 @@ namespace Titanium.Web.Proxy
args.RequestLength = contentLen; args.RequestLength = contentLen;
args.RequestHttpVersion = version; args.RequestHttpVersion = version;
args.ClientPort = ((IPEndPoint)Client.Client.RemoteEndPoint).Port; args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port;
args.ClientIpAddress = ((IPEndPoint)Client.Client.RemoteEndPoint).Address; args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
args.RequestIsAlive = args.ProxyRequest.KeepAlive; args.RequestIsAlive = args.ProxyRequest.KeepAlive;
BeforeRequest(null, args); BeforeRequest(null, args);
...@@ -342,29 +342,35 @@ namespace Titanium.Web.Proxy ...@@ -342,29 +342,35 @@ namespace Titanium.Web.Proxy
//If its a post/put request, then read the client html body and send it to server //If its a post/put request, then read the client html body and send it to server
if (method.ToUpper() == "POST" || method.ToUpper() == "PUT") if (method.ToUpper() == "POST" || method.ToUpper() == "PUT")
{ {
args.ProxyRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), args); SendClientRequestBody(args);
//Http request body sent, now wait asynchronously for response
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
} }
else else
{ {
//otherwise wait for response asynchronously //otherwise wait for response asynchronously
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
}
//Now read the next request (if keep-Alive is enabled, otherwise exit thus thread) //Now read the next request (if keep-Alive is enabled, otherwise exit this thread)
//If client is pipeling the request, this will be immediately hit before response for previous request was made //If client is pipeling the request, this will be immediately hit before response for previous request was made
if (args.ProxyRequest.KeepAlive) if (args.ProxyRequest.KeepAlive)
{
tmpLine = null;
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = args.ClientStreamReader.ReadLine()))
{ {
requestLines = new List<string>(); requestLines.Add(tmpLine);
requestLines.Clear();
while (!String.IsNullOrEmpty(tmpLine = args.ClientStreamReader.ReadLine()))
{
requestLines.Add(tmpLine);
}
httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
HandleHttpSessionRequest(Client, httpCmd, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.securehost);
} }
} httpCmd = requestLines.Count() > 0 ? requestLines[0] : null;
TcpClient Client = args.Client;
//Http request body sent, now wait for next request
Task.Factory.StartNew(() => HandleHttpSessionRequest(Client, httpCmd, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.securehost));
}
} }
} }
...@@ -387,13 +393,13 @@ namespace Titanium.Web.Proxy ...@@ -387,13 +393,13 @@ namespace Titanium.Web.Proxy
} }
private static void ReadRequestHeaders(ref List<string> RequestLines, HttpWebRequest WebRequest) private static void SetClientRequestHeaders(List<string> requestLines, HttpWebRequest webRequest)
{ {
for (int i = 1; i < RequestLines.Count; i++) for (int i = 1; i < requestLines.Count; i++)
{ {
String httpCmd = RequestLines[i]; String httpCmd = requestLines[i];
String[] header = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None); String[] header = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None);
...@@ -401,75 +407,75 @@ namespace Titanium.Web.Proxy ...@@ -401,75 +407,75 @@ namespace Titanium.Web.Proxy
switch (header[0].ToLower()) switch (header[0].ToLower())
{ {
case "accept": case "accept":
WebRequest.Accept = header[1]; webRequest.Accept = header[1];
break; break;
case "accept-encoding": case "accept-encoding":
WebRequest.Headers.Add(header[0], "gzip,deflate,zlib"); webRequest.Headers.Add(header[0], "gzip,deflate,zlib");
break; break;
case "cookie": case "cookie":
WebRequest.Headers["Cookie"] = header[1]; webRequest.Headers["Cookie"] = header[1];
break; break;
case "connection": case "connection":
if (header[1].ToLower() == "keep-alive") if (header[1].ToLower() == "keep-alive")
WebRequest.KeepAlive = true; webRequest.KeepAlive = true;
break; break;
case "content-length": case "content-length":
int contentLen; int contentLen;
int.TryParse(header[1], out contentLen); int.TryParse(header[1], out contentLen);
if (contentLen != 0) if (contentLen != 0)
WebRequest.ContentLength = contentLen; webRequest.ContentLength = contentLen;
break; break;
case "content-type": case "content-type":
WebRequest.ContentType = header[1]; webRequest.ContentType = header[1];
break; break;
case "expect": case "expect":
if (header[1].ToLower() == "100-continue") if (header[1].ToLower() == "100-continue")
WebRequest.ServicePoint.Expect100Continue = true; webRequest.ServicePoint.Expect100Continue = true;
else else
WebRequest.Expect = header[1]; webRequest.Expect = header[1];
break; break;
case "host": case "host":
WebRequest.Host = header[1]; webRequest.Host = header[1];
break; break;
case "if-modified-since": case "if-modified-since":
String[] sb = header[1].Trim().Split(semiSplit); String[] sb = header[1].Trim().Split(semiSplit);
DateTime d; DateTime d;
if (DateTime.TryParse(sb[0], out d)) if (DateTime.TryParse(sb[0], out d))
WebRequest.IfModifiedSince = d; webRequest.IfModifiedSince = d;
break; break;
case "proxy-connection": case "proxy-connection":
if (header[1].ToLower() == "keep-alive") if (header[1].ToLower() == "keep-alive")
WebRequest.KeepAlive = true; webRequest.KeepAlive = true;
break; break;
case "range": case "range":
var startEnd = header[1].Replace(Environment.NewLine, "").Remove(0, 6).Split('-'); var startEnd = header[1].Replace(Environment.NewLine, "").Remove(0, 6).Split('-');
if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) WebRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else WebRequest.AddRange(int.Parse(startEnd[0])); } if (startEnd.Length > 1) { if (!String.IsNullOrEmpty(startEnd[1])) webRequest.AddRange(int.Parse(startEnd[0]), int.Parse(startEnd[1])); else webRequest.AddRange(int.Parse(startEnd[0])); }
else else
WebRequest.AddRange(int.Parse(startEnd[0])); webRequest.AddRange(int.Parse(startEnd[0]));
break; break;
case "referer": case "referer":
WebRequest.Referer = header[1]; webRequest.Referer = header[1];
break; break;
case "user-agent": case "user-agent":
WebRequest.UserAgent = header[1]; webRequest.UserAgent = header[1];
break; break;
//revisit this, transfer-encoding is not a request header according to spec //revisit this, transfer-encoding is not a request header according to spec
//But how to identify if client is sending chunked body for PUT/POST? //But how to identify if client is sending chunked body for PUT/POST?
case "transfer-encoding": case "transfer-encoding":
if (header[1].ToLower() == "chunked") if (header[1].ToLower() == "chunked")
WebRequest.SendChunked = true; webRequest.SendChunked = true;
else else
WebRequest.SendChunked = false; webRequest.SendChunked = false;
break; break;
case "upgrade": case "upgrade":
if (header[1].ToLower() == "http/1.1") if (header[1].ToLower() == "http/1.1")
WebRequest.Headers.Add(header[0], header[1]); webRequest.Headers.Add(header[0], header[1]);
break; break;
default: default:
if (header.Length >= 2) if (header.Length >= 2)
WebRequest.Headers.Add(header[0], header[1]); webRequest.Headers.Add(header[0], header[1]);
break; break;
} }
...@@ -480,12 +486,12 @@ namespace Titanium.Web.Proxy ...@@ -480,12 +486,12 @@ namespace Titanium.Web.Proxy
} }
//This is called when the request is PUT/POST to read the body //This is called when the request is PUT/POST to read the body
private static void GetRequestStreamCallback(IAsyncResult AsynchronousResult) private static void SendClientRequestBody(SessionEventArgs args)
{ {
var args = (SessionEventArgs)AsynchronousResult.AsyncState;
// End the operation // End the operation
Stream postStream = args.ProxyRequest.EndGetRequestStream(AsynchronousResult); Stream postStream = args.ProxyRequest.GetRequestStream();
if (args.ProxyRequest.ContentLength > 0) if (args.ProxyRequest.ContentLength > 0)
...@@ -525,13 +531,13 @@ namespace Titanium.Web.Proxy ...@@ -525,13 +531,13 @@ namespace Titanium.Web.Proxy
{ {
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
return; throw;
} }
catch (WebException) catch (WebException)
{ {
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
return; throw;
} }
...@@ -603,7 +609,7 @@ namespace Titanium.Web.Proxy ...@@ -603,7 +609,7 @@ namespace Titanium.Web.Proxy
postStream.Close(); postStream.Close();
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
return; throw;
} }
catch (WebException) catch (WebException)
{ {
...@@ -611,30 +617,13 @@ namespace Titanium.Web.Proxy ...@@ -611,30 +617,13 @@ namespace Titanium.Web.Proxy
postStream.Close(); postStream.Close();
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
return; throw;
} }
} }
//Http request body sent, now wait asynchronously for response
args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args);
//Now read the next request (if keep-Alive is enabled, otherwise exit thus thread)
//If client is pipeling the request, this will be immediately hit before response for previous request was made
if (args.ProxyRequest.KeepAlive)
{
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;
//Http request body sent, now wait for next request
HandleHttpSessionRequest(Client, httpCmd, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.securehost);
}
} }
......
...@@ -18,13 +18,13 @@ namespace Titanium.Web.Proxy ...@@ -18,13 +18,13 @@ namespace Titanium.Web.Proxy
partial class ProxyServer partial class ProxyServer
{ {
//Called asynchronously when a request was successfully and we received the response //Called asynchronously when a request was successfully and we received the response
private static void HandleHttpSessionResponse(IAsyncResult AsynchronousResult) private static void HandleHttpSessionResponse(IAsyncResult asynchronousResult)
{ {
SessionEventArgs args = (SessionEventArgs)AsynchronousResult.AsyncState; SessionEventArgs args = (SessionEventArgs)asynchronousResult.AsyncState;
try try
{ {
args.ServerResponse = (HttpWebResponse)args.ProxyRequest.EndGetResponse(AsynchronousResult); args.ServerResponse = (HttpWebResponse)args.ProxyRequest.EndGetResponse(asynchronousResult);
} }
catch (WebException webEx) catch (WebException webEx)
{ {
...@@ -32,21 +32,18 @@ namespace Titanium.Web.Proxy ...@@ -32,21 +32,18 @@ namespace Titanium.Web.Proxy
//args.ProxyRequest.KeepAlive = false; //args.ProxyRequest.KeepAlive = false;
args.ServerResponse = webEx.Response as HttpWebResponse; args.ServerResponse = webEx.Response as HttpWebResponse;
} }
Stream serverResponseStream = null;
Stream clientWriteStream = args.ClientStream;
StreamWriter responseWriter = null;
try try
{ {
if (args.ClientStreamWriter == null)
{
args.ClientStreamWriter = new StreamWriter(args.ClientStream);
}
responseWriter = new StreamWriter(clientWriteStream);
if (args.ServerResponse != null) if (args.ServerResponse != null)
{ {
List<Tuple<String, String>> responseHeaders = ProcessResponse(args.ServerResponse); List<Tuple<String, String>> responseHeaders = ProcessResponse(args.ServerResponse);
args.ServerResponseStream = args.ServerResponse.GetResponseStream();
serverResponseStream = args.ServerResponse.GetResponseStream();
args.ServerResponseStream = serverResponseStream;
if (args.ServerResponse.Headers.Count == 0 && args.ServerResponse.ContentLength == -1) if (args.ServerResponse.Headers.Count == 0 && args.ServerResponse.ContentLength == -1)
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
...@@ -66,44 +63,44 @@ namespace Titanium.Web.Proxy ...@@ -66,44 +63,44 @@ namespace Titanium.Web.Proxy
{ {
case "gzip": case "gzip":
data = CompressionHelper.CompressGzip(args.ResponseHtmlBody, args.Encoding); data = CompressionHelper.CompressGzip(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
case "deflate": case "deflate":
data = CompressionHelper.CompressDeflate(args.ResponseHtmlBody, args.Encoding); data = CompressionHelper.CompressDeflate(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
case "zlib": case "zlib":
data = CompressionHelper.CompressZlib(args.ResponseHtmlBody, args.Encoding); data = CompressionHelper.CompressZlib(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
default: default:
data = EncodeData(args.ResponseHtmlBody, args.Encoding); data = EncodeData(args.ResponseHtmlBody, args.Encoding);
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(responseWriter, responseHeaders, data.Length); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders, data.Length);
SendData(clientWriteStream, data, isChunked); SendData(args.ClientStream, data, isChunked);
break; break;
} }
} }
else else
{ {
WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, responseWriter); WriteResponseStatus(args.ServerResponse.ProtocolVersion, args.ServerResponse.StatusCode, args.ServerResponse.StatusDescription, args.ClientStreamWriter);
WriteResponseHeaders(responseWriter, responseHeaders); WriteResponseHeaders(args.ClientStreamWriter, responseHeaders);
if (isChunked) if (isChunked)
SendChunked(serverResponseStream, clientWriteStream); SendChunked(args.ServerResponseStream, args.ClientStream);
else else
SendNormal(serverResponseStream, clientWriteStream); SendNormal(args.ServerResponseStream, args.ClientStream);
} }
clientWriteStream.Flush(); args.ClientStream.Flush();
} }
else else
...@@ -115,7 +112,7 @@ namespace Titanium.Web.Proxy ...@@ -115,7 +112,7 @@ namespace Titanium.Web.Proxy
{ {
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
} }
catch (SocketException ex) catch (SocketException)
{ {
args.ProxyRequest.KeepAlive = false; args.ProxyRequest.KeepAlive = false;
} }
...@@ -129,48 +126,48 @@ namespace Titanium.Web.Proxy ...@@ -129,48 +126,48 @@ namespace Titanium.Web.Proxy
} }
finally finally
{ {
//Close this HttpWebRequest session //If this is false then terminate the tcp client
if (args.ProxyRequest != null) args.ProxyRequest.Abort(); if (args.ProxyRequest.KeepAlive == false)
if (args.ServerResponseStream != null) args.ServerResponseStream.Close(); {
args.Dispose();
}
else
{
if (args.ServerResponse != null) //Close this HttpWebRequest session
args.ServerResponse.Close(); if (args.ProxyRequest != null)
args.ProxyRequest.Abort();
} if (args.ServerResponse != null)
args.ServerResponse.Close();
//If this is false then terminate the tcp client if (args.ServerResponseStream != null)
if (args.ProxyRequest.KeepAlive == false) args.ServerResponseStream.Close();
{
if (responseWriter != null)
responseWriter.Close();
if (clientWriteStream != null) }
clientWriteStream.Close();
args.Client.Close();
} }
} }
private static List<Tuple<String, String>> ProcessResponse(HttpWebResponse Response) static List<Tuple<String, String>> ProcessResponse(HttpWebResponse response)
{ {
String value = null; String value = null;
String header = null; String header = null;
List<Tuple<String, String>> returnHeaders = new List<Tuple<String, String>>(); List<Tuple<String, String>> returnHeaders = new List<Tuple<String, String>>();
foreach (String s in Response.Headers.Keys) foreach (String s in response.Headers.Keys)
{ {
if (s.ToLower() == "set-cookie") if (s.ToLower() == "set-cookie")
{ {
header = s; header = s;
value = Response.Headers[s]; value = response.Headers[s];
} }
else else
returnHeaders.Add(new Tuple<String, String>(s, Response.Headers[s])); returnHeaders.Add(new Tuple<String, String>(s, response.Headers[s]));
} }
if (!String.IsNullOrWhiteSpace(value)) if (!String.IsNullOrWhiteSpace(value))
{ {
Response.Headers.Remove(header); response.Headers.Remove(header);
String[] cookies = cookieSplitRegEx.Split(value); String[] cookies = cookieSplitRegEx.Split(value);
foreach (String cookie in cookies) foreach (String cookie in cookies)
returnHeaders.Add(new Tuple<String, String>("Set-Cookie", cookie)); returnHeaders.Add(new Tuple<String, String>("Set-Cookie", cookie));
...@@ -180,123 +177,121 @@ namespace Titanium.Web.Proxy ...@@ -180,123 +177,121 @@ namespace Titanium.Web.Proxy
return returnHeaders; return returnHeaders;
} }
private static void WriteResponseStatus(Version Version, HttpStatusCode Code, String Description, StreamWriter ResponseWriter) static void WriteResponseStatus(Version version, HttpStatusCode code, String description, StreamWriter responseWriter)
{ {
String s = String.Format("HTTP/{0}.{1} {2} {3}", Version.Major, Version.Minor, (Int32)Code, Description); String s = String.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, (Int32)code, description);
ResponseWriter.WriteLine(s); responseWriter.WriteLine(s);
} }
private static void WriteResponseHeaders(StreamWriter ResponseWriter, List<Tuple<String, String>> Headers) static void WriteResponseHeaders(StreamWriter responseWriter, List<Tuple<String, String>> headers)
{ {
if (Headers != null) if (headers != null)
{ {
foreach (Tuple<String, String> header in Headers) foreach (Tuple<String, String> header in headers)
{ {
ResponseWriter.WriteLine(String.Format("{0}: {1}", header.Item1, header.Item2)); responseWriter.WriteLine(String.Format("{0}: {1}", header.Item1, header.Item2));
} }
} }
ResponseWriter.WriteLine(); responseWriter.WriteLine();
ResponseWriter.Flush(); responseWriter.Flush();
} }
private static void WriteResponseHeaders(StreamWriter ResponseWriter, List<Tuple<String, String>> Headers, int Length) static void WriteResponseHeaders(StreamWriter responseWriter, List<Tuple<String, String>> headers, int length)
{ {
if (Headers != null) if (headers != null)
{ {
foreach (Tuple<String, String> header in Headers) foreach (Tuple<String, String> header in headers)
{ {
if (header.Item1.ToLower() != "content-length") if (header.Item1.ToLower() != "content-length")
ResponseWriter.WriteLine(String.Format("{0}: {1}", header.Item1, header.Item2)); responseWriter.WriteLine(String.Format("{0}: {1}", header.Item1, header.Item2));
else else
ResponseWriter.WriteLine(String.Format("{0}: {1}", "content-length", Length.ToString())); responseWriter.WriteLine(String.Format("{0}: {1}", "content-length", length.ToString()));
} }
} }
ResponseWriter.WriteLine(); responseWriter.WriteLine();
ResponseWriter.Flush(); responseWriter.Flush();
} }
public static void SendNormal(Stream InStream, Stream OutStream) static void SendNormal(Stream inStream, Stream outStream)
{ {
Byte[] buffer = new Byte[BUFFER_SIZE]; Byte[] buffer = new Byte[BUFFER_SIZE];
int bytesRead; int bytesRead;
while ((bytesRead = InStream.Read(buffer, 0, buffer.Length)) > 0) while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) > 0)
{ {
OutStream.Write(buffer, 0, bytesRead); outStream.Write(buffer, 0, bytesRead);
} }
} }
//Send chunked response //Send chunked response
public static void SendChunked(Stream InStream, Stream OutStream) static void SendChunked(Stream inStream, Stream outStream)
{ {
Byte[] buffer = new Byte[BUFFER_SIZE]; Byte[] buffer = new Byte[BUFFER_SIZE];
var ChunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine); var chunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine);
int bytesRead; int bytesRead;
while ((bytesRead = InStream.Read(buffer, 0, buffer.Length)) > 0) while ((bytesRead = inStream.Read(buffer, 0, buffer.Length)) > 0)
{ {
var ChunkHead = Encoding.ASCII.GetBytes(bytesRead.ToString("x2")); var chunkHead = Encoding.ASCII.GetBytes(bytesRead.ToString("x2"));
OutStream.Write(ChunkHead, 0, ChunkHead.Length); outStream.Write(chunkHead, 0, chunkHead.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length); outStream.Write(chunkTrail, 0, chunkTrail.Length);
OutStream.Write(buffer, 0, bytesRead); outStream.Write(buffer, 0, bytesRead);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length); outStream.Write(chunkTrail, 0, chunkTrail.Length);
} }
var ChunkEnd = Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine); var ChunkEnd = Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
OutStream.Write(ChunkEnd, 0, ChunkEnd.Length); outStream.Write(ChunkEnd, 0, ChunkEnd.Length);
} }
public static void SendChunked(byte[] Data, Stream OutStream) static void SendChunked(byte[] data, Stream outStream)
{ {
Byte[] buffer = new Byte[BUFFER_SIZE]; Byte[] buffer = new Byte[BUFFER_SIZE];
var ChunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine); var chunkTrail = Encoding.ASCII.GetBytes(Environment.NewLine);
var ChunkHead = Encoding.ASCII.GetBytes(Data.Length.ToString("x2")); var chunkHead = Encoding.ASCII.GetBytes(data.Length.ToString("x2"));
OutStream.Write(ChunkHead, 0, ChunkHead.Length); outStream.Write(chunkHead, 0, chunkHead.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length); outStream.Write(chunkTrail, 0, chunkTrail.Length);
OutStream.Write(Data, 0, Data.Length); outStream.Write(data, 0, data.Length);
OutStream.Write(ChunkTrail, 0, ChunkTrail.Length); outStream.Write(chunkTrail, 0, chunkTrail.Length);
var ChunkEnd = Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine); var ChunkEnd = Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
OutStream.Write(ChunkEnd, 0, ChunkEnd.Length); outStream.Write(ChunkEnd, 0, ChunkEnd.Length);
} }
public static byte[] EncodeData(string ResponseData, Encoding e) static byte[] EncodeData(string responseData, Encoding e)
{ {
return e.GetBytes(responseData);
return e.GetBytes(ResponseData);
} }
public static void SendData(Stream OutStream, byte[] Data, bool IsChunked) static void SendData(Stream outStream, byte[] data, bool isChunked)
{ {
if (!IsChunked) if (!isChunked)
{ {
OutStream.Write(Data, 0, Data.Length); outStream.Write(data, 0, data.Length);
} }
else else
SendChunked(Data, OutStream); SendChunked(data, outStream);
} }
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
<Compile Include="Helpers\CertificateManager.cs" /> <Compile Include="Helpers\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" /> <Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\SystemProxy.cs" /> <Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RequestHandler.cs" /> <Compile Include="RequestHandler.cs" />
<Compile Include="ResponseHandler.cs" /> <Compile Include="ResponseHandler.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" /> <Compile Include="Helpers\CustomBinaryReader.cs" />
...@@ -89,9 +90,7 @@ ...@@ -89,9 +90,7 @@
<Compile Include="Helpers\Tcp.cs" /> <Compile Include="Helpers\Tcp.cs" />
<Compile Include="Helpers\Stream.cs" /> <Compile Include="Helpers\Stream.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup />
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="Titanium_Proxy_Test_Root.cer"> <None Include="Titanium_Proxy_Test_Root.cer">
......
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