Commit ab1fd394 authored by titanium007's avatar titanium007

Fix stack overflow

Fixed stack overflow by avoiding recursive calls using threadpool
parent 9e666d00
......@@ -16,17 +16,17 @@ namespace Titanium.Web.Proxy.Test
public static void Main(string[] args)
{
//On Console exit make sure we also exit the proxy
handler = new ConsoleEventDelegate(ConsoleEventCallback);
SetConsoleCtrlHandler(handler, true);
NativeMethods.handler = new NativeMethods.ConsoleEventDelegate(ConsoleEventCallback);
NativeMethods.SetConsoleCtrlHandler(NativeMethods.handler, true);
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;
}
Console.Write("Do you want to set this as a System Proxy? (Y/N):");
......@@ -36,18 +36,18 @@ namespace Titanium.Web.Proxy.Test
controller.SetAsSystemProxy = true;
}
//Start proxy controller
controller.StartProxy();
Console.WriteLine("Hit any key to exit..");
Console.WriteLine();
Console.WriteLine();
Console.Read();
controller.Stop();
}
static bool ConsoleEventCallback(int eventType)
{
if (eventType == 2)
......@@ -55,21 +55,25 @@ namespace Titanium.Web.Proxy.Test
try
{
controller.Stop();
}
catch { }
}
return false;
}
// Keeps it from getting garbage collected
private static ConsoleEventDelegate handler;
// Pinvoke
private delegate bool ConsoleEventDelegate(int eventType);
}
internal static class NativeMethods
{
[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
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
//Insert script to read the Browser URL and send it back to proxy
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
GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal
......@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Helpers
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}";
private readonly IDictionary<string, X509Certificate2> _certificateCache;
private readonly IDictionary<string, X509Certificate2> certificateCache;
public string Issuer { get; private set; }
public string RootCertificateName { get; private set; }
......@@ -27,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
MyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
RootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
_certificateCache = new Dictionary<string, X509Certificate2>();
certificateCache = new Dictionary<string, X509Certificate2>();
}
/// <summary>
......@@ -69,8 +69,8 @@ namespace Titanium.Web.Proxy.Helpers
}
protected virtual X509Certificate2 CreateCertificate(X509Store store, string certificateName)
{
if (_certificateCache.ContainsKey(certificateName))
return _certificateCache[certificateName];
if (certificateCache.ContainsKey(certificateName))
return certificateCache[certificateName];
lock (store)
{
......@@ -102,8 +102,8 @@ namespace Titanium.Web.Proxy.Helpers
finally
{
store.Close();
if (certificate != null && !_certificateCache.ContainsKey(certificateName))
_certificateCache.Add(certificateName, certificate);
if (certificate != null && !certificateCache.ContainsKey(certificateName))
certificateCache.Add(certificateName, certificate);
}
}
}
......@@ -151,9 +151,9 @@ namespace Titanium.Web.Proxy.Helpers
{
store.Close();
if (certificates == null &&
_certificateCache.ContainsKey(certificateName))
certificateCache.ContainsKey(certificateName))
{
_certificateCache.Remove(certificateName);
certificateCache.Remove(certificateName);
}
}
}
......
......@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics.CodeAnalysis;
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())
{
......@@ -45,17 +47,16 @@ namespace Titanium.Web.Proxy.Helpers
zip.Write(bytes, 0, bytes.Length);
}
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())
{
......@@ -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())
{
......
......@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.Helpers
public string ReadLine()
{
char[] buf = new char[1];
StringBuilder _readBuffer = new StringBuilder();
StringBuilder readBuffer = new StringBuilder();
try
{
var charsRead = 0;
......@@ -29,24 +29,24 @@ namespace Titanium.Web.Proxy.Helpers
{
if (lastChar == '\r' && buf[0] == '\n')
{
return _readBuffer.Remove(_readBuffer.Length - 1, 1).ToString();
return readBuffer.Remove(readBuffer.Length - 1, 1).ToString();
}
else
if (buf[0] == '\0')
{
return _readBuffer.ToString();
return readBuffer.ToString();
}
else
_readBuffer.Append(buf[0]);
readBuffer.Append(buf[0]);
lastChar = buf[0];
}
return _readBuffer.ToString();
return readBuffer.ToString();
}
catch (IOException)
{ return _readBuffer.ToString(); }
catch (Exception e)
{ throw e; }
{ return readBuffer.ToString(); }
catch (Exception)
{ throw; }
}
......
......@@ -8,6 +8,7 @@ namespace Titanium.Web.Proxy.Helpers
{
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
public static void URLPeriodFix()
{
......
......@@ -7,12 +7,16 @@ using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Helpers
{
public static class SystemProxyHelper
internal static class NativeMethods
{
[DllImport("wininet.dll")]
public 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;
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
}
public static class SystemProxyHelper
{
public const int INTERNET_OPTION_SETTINGS_CHANGED = 39;
public const int INTERNET_OPTION_REFRESH = 37;
static bool settingsReturn, refreshReturn;
static object prevProxyServer;
static object prevProxyEnable;
......@@ -23,7 +27,7 @@ namespace Titanium.Web.Proxy.Helpers
prevProxyEnable = reg.GetValue("ProxyEnable");
prevProxyServer = reg.GetValue("ProxyServer");
reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", "http="+hostname+":" + port + ";");
reg.SetValue("ProxyServer", "http=" + hostname + ":" + port + ";");
refresh();
}
public static void EnableProxyHTTPS(string hostname, int port)
......@@ -43,8 +47,8 @@ namespace Titanium.Web.Proxy.Helpers
}
private static void refresh()
{
settingsReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
settingsReturn = NativeMethods.InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
refreshReturn = NativeMethods.InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
}
}
}
......@@ -13,16 +13,16 @@ namespace Titanium.Web.Proxy.Helpers
{
private static readonly int BUFFER_SIZE = 8192;
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 tunnelReadBuffer = new byte[BUFFER_SIZE];
Task sendRelay = new Task(() => StreamHelper.CopyTo(ClientStream, tunnelStream, BUFFER_SIZE));
Task receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, ClientStream, BUFFER_SIZE));
Task sendRelay = new Task(() => StreamHelper.CopyTo(clientStream, tunnelStream, BUFFER_SIZE));
Task receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
......@@ -35,21 +35,21 @@ namespace Titanium.Web.Proxy.Helpers
if (tunnelClient != null)
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();
sb.Append(HttpCmd);
sb.Append(httpCmd);
sb.Append(Environment.NewLine);
string hostname = SecureHostName;
for (int i = 1; i < RequestLines.Count; i++)
string hostname = secureHostName;
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())
{
case "host":
......@@ -69,7 +69,7 @@ namespace Titanium.Web.Proxy.Helpers
sb.Append(Environment.NewLine);
int tunnelPort = 80;
if (IsHttps)
if (isHttps)
{
tunnelPort = 443;
......@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Helpers
System.Net.Sockets.TcpClient tunnelClient = new System.Net.Sockets.TcpClient(hostname, tunnelPort);
var tunnelStream = tunnelClient.GetStream() as System.IO.Stream;
if (IsHttps)
if (isHttps)
{
var sslStream = new SslStream(tunnelStream);
sslStream.AuthenticateAsClient(hostname);
......@@ -87,8 +87,8 @@ namespace Titanium.Web.Proxy.Helpers
}
var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), ClientStream, tunnelStream, BUFFER_SIZE));
var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, ClientStream, BUFFER_SIZE));
var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), clientStream, tunnelStream, BUFFER_SIZE));
var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE));
sendRelay.Start();
receiveRelay.Start();
......
......@@ -3,48 +3,73 @@ using System.Text;
using System.IO;
using System.Net;
using Titanium.Web.Proxy.Helpers;
using System.Net.Sockets;
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 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 Version RequestHttpVersion { get; set; }
internal bool RequestIsAlive { get; set; }
internal bool CancelRequest { get; set; }
internal CustomBinaryReader ClientStreamReader { get; set; }
internal Stream ClientStream { get; set; }
internal Stream ServerResponseStream { get; set; }
internal Encoding Encoding { get; set; }
internal string RequestHtmlBody { get; set; }
internal bool RequestWasModified { get; set; }
internal Stream ServerResponseStream { get; set; }
internal string ResponseHtmlBody { 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; }
internal string ResponseHtmlBody { get; set; }
if (this.ServerResponseStream != null)
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()
{
......@@ -68,9 +93,9 @@ namespace Titanium.Web.Proxy.Models
RequestWasModified = true;
return RequestHtmlBody;
}
public void SetRequestHtmlBody(string Body)
public void SetRequestHtmlBody(string body)
{
this.RequestHtmlBody = Body;
this.RequestHtmlBody = body;
RequestWasModified = true;
}
public string GetResponseHtmlBody()
......@@ -101,30 +126,30 @@ namespace Titanium.Web.Proxy.Models
}
ResponseHtmlBody = ResponseData;
ResponseWasModified = true;
}
return ResponseHtmlBody;
}
public void SetResponseHtmlBody(string Body)
public void SetResponseHtmlBody(string body)
{
this.ResponseHtmlBody = Body;
this.ResponseHtmlBody = body;
}
//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();
}
public void Ok(string Html)
public void Ok(string html)
{
if (Html == null)
Html = string.Empty;
if (html == null)
html = string.Empty;
var result = Encoding.Default.GetBytes(Html);
var result = Encoding.Default.GetBytes(html);
StreamWriter connectStreamWriter = new StreamWriter(ClientStream);
var s = String.Format("HTTP/{0}.{1} {2} {3}", RequestHttpVersion.Major, RequestHttpVersion.Minor, 200, "Ok");
......@@ -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
private static TcpListener listener;
private static Thread listenerThread;
private static bool ShouldListen { get; set; }
public static event EventHandler<SessionEventArgs> BeforeRequest;
public static event EventHandler<SessionEventArgs> BeforeResponse;
......@@ -64,6 +66,7 @@ namespace Titanium.Web.Proxy
CertManager = new CertificateManager("Titanium",
"Titanium Root Certificate Authority");
}
public ProxyServer()
{
......@@ -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()
{
......@@ -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) { }
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -79,6 +79,7 @@
<Compile Include="Helpers\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RequestHandler.cs" />
<Compile Include="ResponseHandler.cs" />
<Compile Include="Helpers\CustomBinaryReader.cs" />
......@@ -89,9 +90,7 @@
<Compile Include="Helpers\Tcp.cs" />
<Compile Include="Helpers\Stream.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<None Include="packages.config" />
<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