Commit 725e1f75 authored by justcoding121's avatar justcoding121

make proxy server non-static object

parent 56270351
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -10,12 +8,19 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -10,12 +8,19 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
public class ProxyTestController public class ProxyTestController
{ {
private ProxyServer proxyServer;
public ProxyTestController()
{
proxyServer = new ProxyServer();
}
public void StartProxy() public void StartProxy()
{ {
ProxyServer.BeforeRequest += OnRequest; proxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse; proxyServer.BeforeResponse += OnResponse;
ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
ProxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning //Usefull for clients that use certificate pinning
...@@ -27,8 +32,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -27,8 +32,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
//An explicit endpoint is where the client knows about the existance of a proxy //An explicit endpoint is where the client knows about the existance of a proxy
//So client sends request in a proxy friendly manner //So client sends request in a proxy friendly manner
ProxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
ProxyServer.Start(); proxyServer.Start();
//Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy) //Transparent endpoint is usefull for reverse proxying (client is not aware of the existance of proxy)
...@@ -41,26 +46,26 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -41,26 +46,26 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
GenericCertificateName = "google.com" GenericCertificateName = "google.com"
}; };
ProxyServer.AddEndPoint(transparentEndPoint); proxyServer.AddEndPoint(transparentEndPoint);
//ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //ProxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
//ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //ProxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
foreach (var endPoint in ProxyServer.ProxyEndPoints) foreach (var endPoint in proxyServer.ProxyEndPoints)
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
//Only explicit proxies can be set as system proxy! //Only explicit proxies can be set as system proxy!
ProxyServer.SetAsSystemHttpProxy(explicitEndPoint); proxyServer.SetAsSystemHttpProxy(explicitEndPoint);
ProxyServer.SetAsSystemHttpsProxy(explicitEndPoint); proxyServer.SetAsSystemHttpsProxy(explicitEndPoint);
} }
public void Stop() public void Stop()
{ {
ProxyServer.BeforeRequest -= OnRequest; proxyServer.BeforeRequest -= OnRequest;
ProxyServer.BeforeResponse -= OnResponse; proxyServer.BeforeResponse -= OnResponse;
ProxyServer.Stop(); proxyServer.Stop();
} }
//intecept & cancel, redirect or update requests //intecept & cancel, redirect or update requests
......
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param> /// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="sslPolicyErrors"></param>
/// <returns></returns> /// <returns></returns>
internal static bool ValidateServerCertificate( internal bool ValidateServerCertificate(
object sender, object sender,
X509Certificate certificate, X509Certificate certificate,
X509Chain chain, X509Chain chain,
...@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy ...@@ -62,7 +62,7 @@ namespace Titanium.Web.Proxy
/// <param name="chain"></param> /// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="sslPolicyErrors"></param>
/// <returns></returns> /// <returns></returns>
internal static X509Certificate SelectClientCertificate( internal X509Certificate SelectClientCertificate(
object sender, object sender,
string targetHost, string targetHost,
X509CertificateCollection localCertificates, X509CertificateCollection localCertificates,
......
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary> /// </summary>
internal class DefaultDecompression : IDecompression internal class DefaultDecompression : IDecompression
{ {
public Task<byte[]> Decompress(byte[] compressedArray) public Task<byte[]> Decompress(byte[] compressedArray, int bufferSize)
{ {
return Task.FromResult(compressedArray); return Task.FromResult(compressedArray);
} }
......
...@@ -10,13 +10,13 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -10,13 +10,13 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary> /// </summary>
internal class DeflateDecompression : IDecompression internal class DeflateDecompression : IDecompression
{ {
public async Task<byte[]> Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray, int bufferSize)
{ {
var stream = new MemoryStream(compressedArray); var stream = new MemoryStream(compressedArray);
using (var decompressor = new DeflateStream(stream, CompressionMode.Decompress)) using (var decompressor = new DeflateStream(stream, CompressionMode.Decompress))
{ {
var buffer = new byte[ProxyConstants.BUFFER_SIZE]; var buffer = new byte[bufferSize];
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
......
...@@ -10,11 +10,11 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -10,11 +10,11 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary> /// </summary>
internal class GZipDecompression : IDecompression internal class GZipDecompression : IDecompression
{ {
public async Task<byte[]> Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray, int bufferSize)
{ {
using (var decompressor = new GZipStream(new MemoryStream(compressedArray), CompressionMode.Decompress)) using (var decompressor = new GZipStream(new MemoryStream(compressedArray), CompressionMode.Decompress))
{ {
var buffer = new byte[ProxyConstants.BUFFER_SIZE]; var buffer = new byte[bufferSize];
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
......
...@@ -7,6 +7,6 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -7,6 +7,6 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary> /// </summary>
internal interface IDecompression internal interface IDecompression
{ {
Task<byte[]> Decompress(byte[] compressedArray); Task<byte[]> Decompress(byte[] compressedArray, int bufferSize);
} }
} }
...@@ -10,12 +10,12 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -10,12 +10,12 @@ namespace Titanium.Web.Proxy.Decompression
/// </summary> /// </summary>
internal class ZlibDecompression : IDecompression internal class ZlibDecompression : IDecompression
{ {
public async Task<byte[]> Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray, int bufferSize)
{ {
var memoryStream = new MemoryStream(compressedArray); var memoryStream = new MemoryStream(compressedArray);
using (var decompressor = new ZlibStream(memoryStream, CompressionMode.Decompress)) using (var decompressor = new ZlibStream(memoryStream, CompressionMode.Decompress))
{ {
var buffer = new byte[ProxyConstants.BUFFER_SIZE]; var buffer = new byte[bufferSize];
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
......
...@@ -20,14 +20,16 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -20,14 +20,16 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public class SessionEventArgs : EventArgs, IDisposable public class SessionEventArgs : EventArgs, IDisposable
{ {
/// <summary> /// <summary>
/// Constructor to initialize the proxy /// Size of Buffers used by this object
/// </summary> /// </summary>
internal SessionEventArgs() private readonly int bufferSize;
{
ProxyClient = new ProxyClient(); /// <summary>
WebSession = new HttpWebClient(); /// Holds a reference to proxy response handler method
} /// </summary>
private readonly Func<SessionEventArgs, Task> httpResponseHandler;
/// <summary> /// <summary>
/// Holds a reference to client /// Holds a reference to client
...@@ -50,13 +52,18 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -50,13 +52,18 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// implement any cleanup here /// Constructor to initialize the proxy
/// </summary> /// </summary>
public void Dispose() internal SessionEventArgs(int bufferSize, Func<SessionEventArgs, Task> httpResponseHandler)
{ {
this.bufferSize = bufferSize;
this.httpResponseHandler = httpResponseHandler;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient();
} }
/// <summary> /// <summary>
/// Read request body content as bytes[] for current session /// Read request body content as bytes[] for current session
/// </summary> /// </summary>
...@@ -80,7 +87,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -80,7 +87,7 @@ namespace Titanium.Web.Proxy.EventArguments
//For chunked request we need to read data as they arrive, until we reach a chunk end symbol //For chunked request we need to read data as they arrive, until we reach a chunk end symbol
if (WebSession.Request.IsChunked) if (WebSession.Request.IsChunked)
{ {
await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(requestBodyStream); await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(bufferSize, requestBodyStream);
} }
else else
{ {
...@@ -88,11 +95,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -88,11 +95,11 @@ namespace Titanium.Web.Proxy.EventArguments
if (WebSession.Request.ContentLength > 0) if (WebSession.Request.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await this.ProxyClient.ClientStreamReader.CopyBytesToStream(requestBodyStream, WebSession.Request.ContentLength); await this.ProxyClient.ClientStreamReader.CopyBytesToStream(bufferSize, requestBodyStream, WebSession.Request.ContentLength);
} }
else if(WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0) else if(WebSession.Request.HttpVersion.Major == 1 && WebSession.Request.HttpVersion.Minor == 0)
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(requestBodyStream, long.MaxValue); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, requestBodyStream, long.MaxValue);
} }
WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray()); WebSession.Request.RequestBody = await GetDecompressedResponseBody(WebSession.Request.ContentEncoding, requestBodyStream.ToArray());
} }
...@@ -117,18 +124,18 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -117,18 +124,18 @@ namespace Titanium.Web.Proxy.EventArguments
//If chuncked the read chunk by chunk until we hit chunk end symbol //If chuncked the read chunk by chunk until we hit chunk end symbol
if (WebSession.Response.IsChunked) if (WebSession.Response.IsChunked)
{ {
await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(responseBodyStream); await WebSession.ServerConnection.StreamReader.CopyBytesToStreamChunked(bufferSize, responseBodyStream);
} }
else else
{ {
if (WebSession.Response.ContentLength > 0) if (WebSession.Response.ContentLength > 0)
{ {
//If not chunked then its easy just read the amount of bytes mentioned in content length header of response //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, WebSession.Response.ContentLength); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, WebSession.Response.ContentLength);
} }
else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0) else if(WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0)
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(responseBodyStream, long.MaxValue); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, long.MaxValue);
} }
WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray()); WebSession.Response.ResponseBody = await GetDecompressedResponseBody(WebSession.Response.ContentEncoding, responseBodyStream.ToArray());
...@@ -285,7 +292,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -285,7 +292,7 @@ namespace Titanium.Web.Proxy.EventArguments
var decompressionFactory = new DecompressionFactory(); var decompressionFactory = new DecompressionFactory();
var decompressor = decompressionFactory.Create(encodingType); var decompressor = decompressionFactory.Create(encodingType);
return await decompressor.Decompress(responseBodyStream); return await decompressor.Decompress(responseBodyStream, bufferSize);
} }
...@@ -338,7 +345,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -338,7 +345,7 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Request.CancelRequest = true; WebSession.Request.CancelRequest = true;
} }
/// a generic responder method /// a generic responder method
public async Task Respond(Response response) public async Task Respond(Response response)
{ {
...@@ -349,8 +356,15 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -349,8 +356,15 @@ namespace Titanium.Web.Proxy.EventArguments
WebSession.Response = response; WebSession.Response = response;
await ProxyServer.HandleHttpSessionResponse(this); await httpResponseHandler(this);
} }
/// <summary>
/// implement any cleanup here
/// </summary>
public void Dispose()
{
}
} }
} }
\ No newline at end of file
...@@ -35,22 +35,22 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -35,22 +35,22 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="stream"></param> /// <param name="stream"></param>
/// <param name="totalBytesToRead"></param> /// <param name="totalBytesToRead"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, Stream stream, long totalBytesToRead) internal static async Task CopyBytesToStream(this CustomBinaryReader streamReader, int bufferSize, Stream stream, long totalBytesToRead)
{ {
var totalbytesRead = 0; var totalbytesRead = 0;
long bytesToRead; long bytesToRead;
if (totalBytesToRead < ProxyConstants.BUFFER_SIZE) if (totalBytesToRead < bufferSize)
{ {
bytesToRead = totalBytesToRead; bytesToRead = totalBytesToRead;
} }
else else
bytesToRead = ProxyConstants.BUFFER_SIZE; bytesToRead = bufferSize;
while (totalbytesRead < totalBytesToRead) while (totalbytesRead < totalBytesToRead)
{ {
var buffer = await streamReader.ReadBytesAsync(bytesToRead); var buffer = await streamReader.ReadBytesAsync(bufferSize, bytesToRead);
if (buffer.Length == 0) if (buffer.Length == 0)
break; break;
...@@ -72,7 +72,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -72,7 +72,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="clientStreamReader"></param> /// <param name="clientStreamReader"></param>
/// <param name="stream"></param> /// <param name="stream"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, Stream stream) internal static async Task CopyBytesToStreamChunked(this CustomBinaryReader clientStreamReader, int bufferSize, Stream stream)
{ {
while (true) while (true)
{ {
...@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -81,7 +81,7 @@ namespace Titanium.Web.Proxy.Extensions
if (chunkSize != 0) if (chunkSize != 0)
{ {
var buffer = await clientStreamReader.ReadBytesAsync(chunkSize); var buffer = await clientStreamReader.ReadBytesAsync(bufferSize, chunkSize);
await stream.WriteAsync(buffer, 0, buffer.Length); await stream.WriteAsync(buffer, 0, buffer.Length);
//chunk trail //chunk trail
await clientStreamReader.ReadLineAsync(); await clientStreamReader.ReadLineAsync();
...@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -118,7 +118,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="isChunked"></param> /// <param name="isChunked"></param>
/// <param name="ContentLength"></param> /// <param name="ContentLength"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, Stream outStream, bool isChunked, long ContentLength) internal static async Task WriteResponseBody(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream, bool isChunked, long ContentLength)
{ {
if (!isChunked) if (!isChunked)
{ {
...@@ -126,12 +126,12 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -126,12 +126,12 @@ namespace Titanium.Web.Proxy.Extensions
if (ContentLength == -1) if (ContentLength == -1)
ContentLength = long.MaxValue; ContentLength = long.MaxValue;
int bytesToRead = ProxyConstants.BUFFER_SIZE; int bytesToRead = bufferSize;
if (ContentLength < ProxyConstants.BUFFER_SIZE) if (ContentLength < bufferSize)
bytesToRead = (int)ContentLength; bytesToRead = (int)ContentLength;
var buffer = new byte[ProxyConstants.BUFFER_SIZE]; var buffer = new byte[bufferSize];
var bytesRead = 0; var bytesRead = 0;
var totalBytesRead = 0; var totalBytesRead = 0;
...@@ -146,11 +146,11 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -146,11 +146,11 @@ namespace Titanium.Web.Proxy.Extensions
bytesRead = 0; bytesRead = 0;
var remainingBytes = (ContentLength - totalBytesRead); var remainingBytes = (ContentLength - totalBytesRead);
bytesToRead = remainingBytes > (long)ProxyConstants.BUFFER_SIZE ? ProxyConstants.BUFFER_SIZE : (int)remainingBytes; bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes;
} }
} }
else else
await WriteResponseBodyChunked(inStreamReader, outStream); await WriteResponseBodyChunked(inStreamReader, bufferSize, outStream);
} }
/// <summary> /// <summary>
...@@ -159,7 +159,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -159,7 +159,7 @@ namespace Titanium.Web.Proxy.Extensions
/// <param name="inStreamReader"></param> /// <param name="inStreamReader"></param>
/// <param name="outStream"></param> /// <param name="outStream"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, Stream outStream) internal static async Task WriteResponseBodyChunked(this CustomBinaryReader inStreamReader, int bufferSize, Stream outStream)
{ {
while (true) while (true)
{ {
...@@ -168,7 +168,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -168,7 +168,7 @@ namespace Titanium.Web.Proxy.Extensions
if (chunkSize != 0) if (chunkSize != 0)
{ {
var buffer = await inStreamReader.ReadBytesAsync(chunkSize); var buffer = await inStreamReader.ReadBytesAsync(bufferSize, chunkSize);
var chunkHeadBytes = Encoding.ASCII.GetBytes(chunkSize.ToString("x2")); var chunkHeadBytes = Encoding.ASCII.GetBytes(chunkSize.ToString("x2"));
......
...@@ -91,14 +91,14 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -91,14 +91,14 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="totalBytesToRead"></param> /// <param name="totalBytesToRead"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<byte[]> ReadBytesAsync(long totalBytesToRead) internal async Task<byte[]> ReadBytesAsync(int bufferSize, long totalBytesToRead)
{ {
int bytesToRead = ProxyConstants.BUFFER_SIZE; int bytesToRead = bufferSize;
if (totalBytesToRead < ProxyConstants.BUFFER_SIZE) if (totalBytesToRead < bufferSize)
bytesToRead = (int)totalBytesToRead; bytesToRead = (int)totalBytesToRead;
var buffer = new byte[ProxyConstants.BUFFER_SIZE]; var buffer = new byte[bufferSize];
var bytesRead = 0; var bytesRead = 0;
var totalBytesRead = 0; var totalBytesRead = 0;
...@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -115,7 +115,7 @@ namespace Titanium.Web.Proxy.Helpers
bytesRead = 0; bytesRead = 0;
var remainingBytes = (totalBytesToRead - totalBytesRead); var remainingBytes = (totalBytesToRead - totalBytesRead);
bytesToRead = remainingBytes > (long)ProxyConstants.BUFFER_SIZE ? ProxyConstants.BUFFER_SIZE : (int)remainingBytes; bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes;
} }
return outStream.ToArray(); return outStream.ToArray();
......
...@@ -6,9 +6,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -6,9 +6,9 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// A helper class to set proxy settings for firefox /// A helper class to set proxy settings for firefox
/// </summary> /// </summary>
public class FireFoxHelper public class FireFoxProxySettingsManager
{ {
public static void AddFirefox() public void AddFirefox()
{ {
try try
{ {
...@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -38,7 +38,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
public static void RemoveFirefox() public void RemoveFirefox()
{ {
try try
{ {
......
...@@ -11,7 +11,7 @@ using System.Linq; ...@@ -11,7 +11,7 @@ using System.Linq;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal static class NativeMethods internal class NativeMethods
{ {
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
...@@ -32,13 +32,15 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -32,13 +32,15 @@ namespace Titanium.Web.Proxy.Helpers
return "https=" + HostName + ":" + Port; return "https=" + HostName + ":" + Port;
} }
} }
/// <summary>
internal static class SystemProxyHelper /// Manage system proxy settings
/// </summary>
internal class SystemProxyManager
{ {
internal const int InternetOptionSettingsChanged = 39; internal const int InternetOptionSettingsChanged = 39;
internal const int InternetOptionRefresh = 37; internal const int InternetOptionRefresh = 37;
internal static void SetHttpProxy(string hostname, int port) internal void SetHttpProxy(string hostname, int port)
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
...@@ -66,7 +68,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -66,7 +68,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Remove the http proxy setting from current machine /// Remove the http proxy setting from current machine
/// </summary> /// </summary>
internal static void RemoveHttpProxy() internal void RemoveHttpProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
...@@ -100,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -100,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <param name="port"></param> /// <param name="port"></param>
internal static void SetHttpsProxy(string hostname, int port) internal void SetHttpsProxy(string hostname, int port)
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
...@@ -130,7 +132,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -130,7 +132,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Removes the https proxy setting to nothing /// Removes the https proxy setting to nothing
/// </summary> /// </summary>
internal static void RemoveHttpsProxy() internal void RemoveHttpsProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
...@@ -163,7 +165,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -163,7 +165,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Removes all types of proxy settings (both http & https) /// Removes all types of proxy settings (both http & https)
/// </summary> /// </summary>
internal static void DisableAllProxy() internal void DisableAllProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
...@@ -182,7 +184,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -182,7 +184,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="prevServerValue"></param> /// <param name="prevServerValue"></param>
/// <returns></returns> /// <returns></returns>
private static List<HttpSystemProxyValue> GetSystemProxyValues(string prevServerValue) private List<HttpSystemProxyValue> GetSystemProxyValues(string prevServerValue)
{ {
var result = new List<HttpSystemProxyValue>(); var result = new List<HttpSystemProxyValue>();
...@@ -215,7 +217,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -215,7 +217,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
private static HttpSystemProxyValue parseProxyValue(string value) private HttpSystemProxyValue parseProxyValue(string value)
{ {
var tmp = Regex.Replace(value, @"\s+", " ").Trim().ToLower(); var tmp = Regex.Replace(value, @"\s+", " ").Trim().ToLower();
if (tmp.StartsWith("http=")) if (tmp.StartsWith("http="))
...@@ -245,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -245,7 +247,7 @@ namespace Titanium.Web.Proxy.Helpers
/// Prepares the proxy server registry (create empty values if they don't exist) /// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary> /// </summary>
/// <param name="reg"></param> /// <param name="reg"></param>
private static void prepareRegistry(RegistryKey reg) private void prepareRegistry(RegistryKey reg)
{ {
if (reg.GetValue("ProxyEnable") == null) if (reg.GetValue("ProxyEnable") == null)
{ {
...@@ -262,7 +264,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -262,7 +264,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Refresh the settings so that the system know about a change in proxy setting /// Refresh the settings so that the system know about a change in proxy setting
/// </summary> /// </summary>
private static void Refresh() private void Refresh()
{ {
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0);
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionRefresh, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionRefresh, IntPtr.Zero, 0);
......
...@@ -4,6 +4,7 @@ using System.IO; ...@@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -12,7 +13,7 @@ using Titanium.Web.Proxy.Shared; ...@@ -12,7 +13,7 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal class TcpHelper internal class TcpHelper
{ {
/// <summary> /// <summary>
...@@ -26,8 +27,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -26,8 +27,8 @@ namespace Titanium.Web.Proxy.Helpers
/// <param name="tunnelPort"></param> /// <param name="tunnelPort"></param>
/// <param name="isHttps"></param> /// <param name="isHttps"></param>
/// <returns></returns> /// <returns></returns>
internal async static Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName, internal static async Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName,
int tunnelPort, bool isHttps) int tunnelPort, bool isHttps, SslProtocols supportedProtocols)
{ {
//prepare the prefix content //prepare the prefix content
StringBuilder sb = null; StringBuilder sb = null;
...@@ -63,7 +64,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -63,7 +64,7 @@ namespace Titanium.Web.Proxy.Helpers
try try
{ {
sslStream = new SslStream(tunnelStream); sslStream = new SslStream(tunnelStream);
await sslStream.AuthenticateAsClientAsync(hostName, null, ProxyConstants.SupportedSslProtocols, false); await sslStream.AuthenticateAsClientAsync(hostName, null, supportedProtocols, false);
tunnelStream = sslStream; tunnelStream = sslStream;
} }
catch catch
......
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Connection to server /// Connection to server
/// </summary> /// </summary>
internal TcpConnection ServerConnection { get; set; } internal TcpConnectionCache ServerConnection { get; set; }
public Request Request { get; set; } public Request Request { get; set; }
public Response Response { get; set; } public Response Response { get; set; }
...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Http
/// Set the tcp connection to server used by this webclient /// Set the tcp connection to server used by this webclient
/// </summary> /// </summary>
/// <param name="Connection"></param> /// <param name="Connection"></param>
internal void SetConnection(TcpConnection Connection) internal void SetConnection(TcpConnectionCache Connection)
{ {
Connection.LastAccess = DateTime.Now; Connection.LastAccess = DateTime.Now;
ServerConnection = Connection; ServerConnection = Connection;
...@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -53,7 +53,7 @@ namespace Titanium.Web.Proxy.Http
/// Prepare & send the http(s) request /// Prepare & send the http(s) request
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task SendRequest() internal async Task SendRequest(bool enable100ContinueBehaviour)
{ {
Stream stream = ServerConnection.Stream; Stream stream = ServerConnection.Stream;
...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http
await stream.WriteAsync(requestBytes, 0, requestBytes.Length); await stream.WriteAsync(requestBytes, 0, requestBytes.Length);
await stream.FlushAsync(); await stream.FlushAsync();
if (ProxyServer.Enable100ContinueBehaviour) if (enable100ContinueBehaviour)
if (this.Request.ExpectContinue) if (this.Request.ExpectContinue)
{ {
var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3); var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3);
......
...@@ -18,8 +18,15 @@ namespace Titanium.Web.Proxy.Network ...@@ -18,8 +18,15 @@ namespace Titanium.Web.Proxy.Network
private const string CertCreateFormat = private const string CertCreateFormat =
"-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 {5}"; "-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 {5}";
/// <summary>
/// Cache dictionary
/// </summary>
private readonly IDictionary<string, CachedCertificate> certificateCache; private readonly IDictionary<string, CachedCertificate> certificateCache;
private static SemaphoreSlim semaphoreLock = new SemaphoreSlim(1);
/// <summary>
/// A lock to manage concurrency
/// </summary>
private SemaphoreSlim semaphoreLock = new SemaphoreSlim(1);
internal string Issuer { get; private set; } internal string Issuer { get; private set; }
internal string RootCertificateName { get; private set; } internal string RootCertificateName { get; private set; }
...@@ -241,7 +248,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -241,7 +248,7 @@ namespace Titanium.Web.Proxy.Network
return certCreatArgs; return certCreatArgs;
} }
private static bool clearCertificates { get; set; } private bool clearCertificates { get; set; }
/// <summary> /// <summary>
/// Stops the certificate cache clear process /// Stops the certificate cache clear process
...@@ -254,7 +261,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -254,7 +261,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// A method to clear outdated certificates /// A method to clear outdated certificates
/// </summary> /// </summary>
internal async void ClearIdleCertificates() internal async void ClearIdleCertificates(int certificateCacheTimeOutMinutes)
{ {
clearCertificates = true; clearCertificates = true;
while (clearCertificates) while (clearCertificates)
...@@ -263,7 +270,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -263,7 +270,7 @@ namespace Titanium.Web.Proxy.Network
try try
{ {
var cutOff = DateTime.Now.AddMinutes(-1 * ProxyServer.CertificateCacheTimeOutMinutes); var cutOff = DateTime.Now.AddMinutes(-1 * certificateCacheTimeOutMinutes);
var outdated = certificateCache var outdated = certificateCache
.Where(x => x.Value.LastAccess < cutOff) .Where(x => x.Value.LastAccess < cutOff)
......
...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -8,7 +8,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// An object that holds TcpConnection to a particular server & port /// An object that holds TcpConnection to a particular server & port
/// </summary> /// </summary>
public class TcpConnection public class TcpConnectionCache
{ {
internal string HostName { get; set; } internal string HostName { get; set; }
internal int port { get; set; } internal int port { get; set; }
...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -37,7 +37,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
internal DateTime LastAccess { get; set; } internal DateTime LastAccess { get; set; }
internal TcpConnection() internal TcpConnectionCache()
{ {
LastAccess = DateTime.Now; LastAccess = DateTime.Now;
} }
......
...@@ -10,23 +10,25 @@ using Titanium.Web.Proxy.Helpers; ...@@ -10,23 +10,25 @@ using Titanium.Web.Proxy.Helpers;
using System.Threading; using System.Threading;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
using Titanium.Web.Proxy.Models;
using System.Security.Authentication;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
/// <summary> /// <summary>
/// A class that manages Tcp Connection to server used by this proxy server /// A class that manages Tcp Connection to server used by this proxy server
/// </summary> /// </summary>
internal class TcpConnectionManager internal class TcpConnectionCacheManager
{ {
/// <summary> /// <summary>
/// Connection cache /// Connection cache
/// </summary> /// </summary>
static Dictionary<string, List<TcpConnection>> connectionCache = new Dictionary<string, List<TcpConnection>>(); Dictionary<string, List<TcpConnectionCache>> connectionCache = new Dictionary<string, List<TcpConnectionCache>>();
/// <summary> /// <summary>
/// A lock to manage concurrency /// A lock to manage concurrency
/// </summary> /// </summary>
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1); SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
/// <summary> /// <summary>
/// Get a TcpConnection to the specified host, port optionally HTTPS and a particular HTTP version /// Get a TcpConnection to the specified host, port optionally HTTPS and a particular HTTP version
...@@ -36,10 +38,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -36,10 +38,12 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param> /// <param name="isHttps"></param>
/// <param name="version"></param> /// <param name="version"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task<TcpConnection> GetClient(string hostname, int port, bool isHttps, Version version) internal async Task<TcpConnectionCache> GetClient(string hostname, int port, bool isHttps, Version version,
ExternalProxy upStreamHttpProxy, ExternalProxy upStreamHttpsProxy, int bufferSize, SslProtocols supportedSslProtocols,
RemoteCertificateValidationCallback remoteCertificateValidationCallBack, LocalCertificateSelectionCallback localCertificateSelectionCallback)
{ {
List<TcpConnection> cachedConnections = null; List<TcpConnectionCache> cachedConnections = null;
TcpConnection cached = null; TcpConnectionCache cached = null;
//Get a unique string to identify this connection //Get a unique string to identify this connection
var key = GetConnectionKey(hostname, port, isHttps, version); var key = GetConnectionKey(hostname, port, isHttps, version);
...@@ -77,12 +81,14 @@ namespace Titanium.Web.Proxy.Network ...@@ -77,12 +81,14 @@ namespace Titanium.Web.Proxy.Network
if (cached == null) if (cached == null)
cached = await CreateClient(hostname, port, isHttps, version); cached = await CreateClient(hostname, port, isHttps, version, upStreamHttpProxy, upStreamHttpsProxy, bufferSize, supportedSslProtocols,
remoteCertificateValidationCallBack, localCertificateSelectionCallback);
if (cachedConnections == null || cachedConnections.Count() <= 2) if (cachedConnections == null || cachedConnections.Count() <= 2)
{ {
var task = CreateClient(hostname, port, isHttps, version) var task = CreateClient(hostname, port, isHttps, version, upStreamHttpProxy, upStreamHttpsProxy, bufferSize, supportedSslProtocols,
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); }); remoteCertificateValidationCallBack, localCertificateSelectionCallback)
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
} }
return cached; return cached;
...@@ -96,7 +102,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -96,7 +102,7 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param> /// <param name="isHttps"></param>
/// <param name="version"></param> /// <param name="version"></param>
/// <returns></returns> /// <returns></returns>
internal static string GetConnectionKey(string hostname, int port, bool isHttps, Version version) internal string GetConnectionKey(string hostname, int port, bool isHttps, Version version)
{ {
return string.Format("{0}:{1}:{2}:{3}:{4}", hostname.ToLower(), port, isHttps, version.Major, version.Minor); return string.Format("{0}:{1}:{2}:{3}:{4}", hostname.ToLower(), port, isHttps, version.Major, version.Minor);
} }
...@@ -109,7 +115,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -109,7 +115,9 @@ namespace Titanium.Web.Proxy.Network
/// <param name="isHttps"></param> /// <param name="isHttps"></param>
/// <param name="version"></param> /// <param name="version"></param>
/// <returns></returns> /// <returns></returns>
private static async Task<TcpConnection> CreateClient(string hostname, int port, bool isHttps, Version version) private async Task<TcpConnectionCache> CreateClient(string hostname, int port, bool isHttps, Version version,
ExternalProxy upStreamHttpProxy, ExternalProxy upStreamHttpsProxy, int bufferSize, SslProtocols supportedSslProtocols,
RemoteCertificateValidationCallback remoteCertificateValidationCallBack, LocalCertificateSelectionCallback localCertificateSelectionCallback)
{ {
TcpClient client; TcpClient client;
Stream stream; Stream stream;
...@@ -119,12 +127,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -119,12 +127,12 @@ namespace Titanium.Web.Proxy.Network
SslStream sslStream = null; SslStream sslStream = null;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections //If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (ProxyServer.UpStreamHttpsProxy != null) if (upStreamHttpsProxy != null)
{ {
client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port); client = new TcpClient(upStreamHttpsProxy.HostName, upStreamHttpsProxy.Port);
stream = (Stream)client.GetStream(); stream = (Stream)client.GetStream();
using (var writer = new StreamWriter(stream, Encoding.ASCII, ProxyConstants.BUFFER_SIZE, true)) using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true))
{ {
await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", hostname, port, version)); await writer.WriteLineAsync(string.Format("CONNECT {0}:{1} {2}", hostname, port, version));
await writer.WriteLineAsync(string.Format("Host: {0}:{1}", hostname, port)); await writer.WriteLineAsync(string.Format("Host: {0}:{1}", hostname, port));
...@@ -152,9 +160,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -152,9 +160,9 @@ namespace Titanium.Web.Proxy.Network
try try
{ {
sslStream = new SslStream(stream, true, new RemoteCertificateValidationCallback(ProxyServer.ValidateServerCertificate), sslStream = new SslStream(stream, true, remoteCertificateValidationCallBack,
new LocalCertificateSelectionCallback(ProxyServer.SelectClientCertificate)); localCertificateSelectionCallback);
await sslStream.AuthenticateAsClientAsync(hostname, null, ProxyConstants.SupportedSslProtocols, false); await sslStream.AuthenticateAsClientAsync(hostname, null, supportedSslProtocols, false);
stream = (Stream)sslStream; stream = (Stream)sslStream;
} }
catch catch
...@@ -166,9 +174,9 @@ namespace Titanium.Web.Proxy.Network ...@@ -166,9 +174,9 @@ namespace Titanium.Web.Proxy.Network
} }
else else
{ {
if (ProxyServer.UpStreamHttpProxy != null) if (upStreamHttpProxy != null)
{ {
client = new TcpClient(ProxyServer.UpStreamHttpProxy.HostName, ProxyServer.UpStreamHttpProxy.Port); client = new TcpClient(upStreamHttpProxy.HostName, upStreamHttpProxy.Port);
stream = (Stream)client.GetStream(); stream = (Stream)client.GetStream();
} }
else else
...@@ -178,7 +186,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -178,7 +186,7 @@ namespace Titanium.Web.Proxy.Network
} }
} }
return new TcpConnection() return new TcpConnectionCache()
{ {
HostName = hostname, HostName = hostname,
port = port, port = port,
...@@ -195,7 +203,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -195,7 +203,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
/// <param name="connection"></param> /// <param name="connection"></param>
/// <returns></returns> /// <returns></returns>
internal static async Task ReleaseClient(TcpConnection connection) internal async Task ReleaseClient(TcpConnectionCache connection)
{ {
connection.LastAccess = DateTime.Now; connection.LastAccess = DateTime.Now;
...@@ -203,25 +211,25 @@ namespace Titanium.Web.Proxy.Network ...@@ -203,25 +211,25 @@ namespace Titanium.Web.Proxy.Network
await connectionAccessLock.WaitAsync(); await connectionAccessLock.WaitAsync();
try try
{ {
List<TcpConnection> cachedConnections; List<TcpConnectionCache> cachedConnections;
connectionCache.TryGetValue(key, out cachedConnections); connectionCache.TryGetValue(key, out cachedConnections);
if (cachedConnections != null) if (cachedConnections != null)
cachedConnections.Add(connection); cachedConnections.Add(connection);
else else
connectionCache.Add(key, new List<TcpConnection>() { connection }); connectionCache.Add(key, new List<TcpConnectionCache>() { connection });
} }
finally { connectionAccessLock.Release(); } finally { connectionAccessLock.Release(); }
} }
private static bool clearConenctions { get; set; } private bool clearConenctions { get; set; }
/// <summary> /// <summary>
/// Stop clearing idle connections /// Stop clearing idle connections
/// </summary> /// </summary>
internal static void StopClearIdleConnections() internal void StopClearIdleConnections()
{ {
clearConenctions = false; clearConenctions = false;
} }
...@@ -229,7 +237,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -229,7 +237,7 @@ namespace Titanium.Web.Proxy.Network
/// <summary> /// <summary>
/// A method to clear idle connections /// A method to clear idle connections
/// </summary> /// </summary>
internal async static void ClearIdleConnections() internal async void ClearIdleConnections(int connectionCacheTimeOutMinutes)
{ {
clearConenctions = true; clearConenctions = true;
while (clearConenctions) while (clearConenctions)
...@@ -237,7 +245,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -237,7 +245,7 @@ namespace Titanium.Web.Proxy.Network
await connectionAccessLock.WaitAsync(); await connectionAccessLock.WaitAsync();
try try
{ {
var cutOff = DateTime.Now.AddMinutes(-1 * ProxyServer.ConnectionCacheTimeOutMinutes); var cutOff = DateTime.Now.AddMinutes(-1 * connectionCacheTimeOutMinutes);
connectionCache connectionCache
.SelectMany(x => x.Value) .SelectMany(x => x.Value)
......
This diff is collapsed.
This diff is collapsed.
...@@ -17,7 +17,7 @@ namespace Titanium.Web.Proxy ...@@ -17,7 +17,7 @@ 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
public static async Task HandleHttpSessionResponse(SessionEventArgs args) public async Task HandleHttpSessionResponse(SessionEventArgs args)
{ {
//read response & headers from server //read response & headers from server
await args.WebSession.ReceiveResponse(); await args.WebSession.ReceiveResponse();
...@@ -86,11 +86,11 @@ namespace Titanium.Web.Proxy ...@@ -86,11 +86,11 @@ namespace Titanium.Web.Proxy
//Write body only if response is chunked or content length >0 //Write body only if response is chunked or content length >0
//Is none are true then check if connection:close header exist, if so write response until server or client terminates the connection //Is none are true then check if connection:close header exist, if so write response until server or client terminates the connection
if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || !args.WebSession.Response.ResponseKeepAlive) if (args.WebSession.Response.IsChunked || args.WebSession.Response.ContentLength > 0 || !args.WebSession.Response.ResponseKeepAlive)
await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength); await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(BUFFER_SIZE, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength);
//write response if connection:keep-alive header exist and when version is http/1.0 //write response if connection:keep-alive header exist and when version is http/1.0
//Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream) //Because in Http 1.0 server can return a response without content-length (expectation being client would read until end of stream)
else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0) else if (args.WebSession.Response.ResponseKeepAlive && args.WebSession.Response.HttpVersion.Minor == 0)
await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength); await args.WebSession.ServerConnection.StreamReader.WriteResponseBody(BUFFER_SIZE, args.ProxyClient.ClientStream, args.WebSession.Response.IsChunked, args.WebSession.Response.ContentLength);
} }
await args.ProxyClient.ClientStream.FlushAsync(); await args.ProxyClient.ClientStream.FlushAsync();
...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy ...@@ -112,7 +112,7 @@ namespace Titanium.Web.Proxy
/// <param name="encodingType"></param> /// <param name="encodingType"></param>
/// <param name="responseBodyStream"></param> /// <param name="responseBodyStream"></param>
/// <returns></returns> /// <returns></returns>
private static async Task<byte[]> GetCompressedResponseBody(string encodingType, byte[] responseBodyStream) private async Task<byte[]> GetCompressedResponseBody(string encodingType, byte[] responseBodyStream)
{ {
var compressionFactory = new CompressionFactory(); var compressionFactory = new CompressionFactory();
var compressor = compressionFactory.Create(encodingType); var compressor = compressionFactory.Create(encodingType);
...@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy ...@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy
/// <param name="description"></param> /// <param name="description"></param>
/// <param name="responseWriter"></param> /// <param name="responseWriter"></param>
/// <returns></returns> /// <returns></returns>
private static async Task WriteResponseStatus(Version version, string code, string description, private async Task WriteResponseStatus(Version version, string code, string description,
StreamWriter responseWriter) StreamWriter responseWriter)
{ {
await responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description)); await responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description));
...@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy ...@@ -139,7 +139,7 @@ namespace Titanium.Web.Proxy
/// <param name="responseWriter"></param> /// <param name="responseWriter"></param>
/// <param name="headers"></param> /// <param name="headers"></param>
/// <returns></returns> /// <returns></returns>
private static async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers) private async Task WriteResponseHeaders(StreamWriter responseWriter, List<HttpHeader> headers)
{ {
if (headers != null) if (headers != null)
{ {
...@@ -159,7 +159,7 @@ namespace Titanium.Web.Proxy ...@@ -159,7 +159,7 @@ namespace Titanium.Web.Proxy
/// Fix the proxy specific headers before sending response headers to client /// Fix the proxy specific headers before sending response headers to client
/// </summary> /// </summary>
/// <param name="headers"></param> /// <param name="headers"></param>
private static void FixResponseProxyHeaders(List<HttpHeader> headers) private void FixResponseProxyHeaders(List<HttpHeader> headers)
{ {
//If proxy-connection close was returned inform to close the connection //If proxy-connection close was returned inform to close the connection
var proxyHeader = headers.FirstOrDefault(x => x.Name.ToLower() == "proxy-connection"); var proxyHeader = headers.FirstOrDefault(x => x.Name.ToLower() == "proxy-connection");
...@@ -186,7 +186,7 @@ namespace Titanium.Web.Proxy ...@@ -186,7 +186,7 @@ namespace Titanium.Web.Proxy
/// <param name="clientStreamReader"></param> /// <param name="clientStreamReader"></param>
/// <param name="clientStreamWriter"></param> /// <param name="clientStreamWriter"></param>
/// <param name="args"></param> /// <param name="args"></param>
private static void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader, private void Dispose(TcpClient client, IDisposable clientStream, IDisposable clientStreamReader,
IDisposable clientStreamWriter, IDisposable args) IDisposable clientStreamWriter, IDisposable args)
{ {
if (args != null) if (args != null)
......
using System; using System;
using System.Security.Authentication;
using System.Text; using System.Text;
namespace Titanium.Web.Proxy.Shared namespace Titanium.Web.Proxy.Shared
...@@ -9,7 +8,7 @@ namespace Titanium.Web.Proxy.Shared ...@@ -9,7 +8,7 @@ namespace Titanium.Web.Proxy.Shared
/// </summary> /// </summary>
internal class ProxyConstants internal class ProxyConstants
{ {
internal static readonly char[] SpaceSplit = { ' ' }; internal static readonly char[] SpaceSplit = { ' ' };
internal static readonly char[] ColonSplit = { ':' }; internal static readonly char[] ColonSplit = { ':' };
internal static readonly char[] SemiColonSplit = { ';' }; internal static readonly char[] SemiColonSplit = { ';' };
...@@ -18,8 +17,5 @@ namespace Titanium.Web.Proxy.Shared ...@@ -18,8 +17,5 @@ namespace Titanium.Web.Proxy.Shared
internal static readonly byte[] ChunkEnd = internal static readonly byte[] ChunkEnd =
Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine); Encoding.ASCII.GetBytes(0.ToString("x2") + Environment.NewLine + Environment.NewLine);
public static SslProtocols SupportedSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3;
public static readonly int BUFFER_SIZE = 8192;
} }
} }
...@@ -77,8 +77,8 @@ ...@@ -77,8 +77,8 @@
<Compile Include="Http\Request.cs" /> <Compile Include="Http\Request.cs" />
<Compile Include="Http\Response.cs" /> <Compile Include="Http\Response.cs" />
<Compile Include="Models\ExternalProxy.cs" /> <Compile Include="Models\ExternalProxy.cs" />
<Compile Include="Network\TcpConnection.cs" /> <Compile Include="Network\TcpConnectionCache.cs" />
<Compile Include="Network\TcpConnectionManager.cs" /> <Compile Include="Network\TcpConnectionCacheManager.cs" />
<Compile Include="Models\HttpHeader.cs" /> <Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" /> <Compile Include="Http\HttpWebClient.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
......
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