Commit 3ff60c1d authored by titanium007's avatar titanium007

Add stress test

parent e27a4f92
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Network;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Titanium.Web.Proxy.UnitTests
{
[TestClass]
public class CertificateManagerTests
{
private readonly static string[] hostNames
= new string[] { "facebook.com", "youtube.com", "google.com",
"bing.com", "yahoo.com"};
private readonly Random random = new Random();
[TestMethod]
public async Task Simple_Create_Certificate_Stress_Test()
{
var tasks = new List<Task>();
var mgr = new CertificateManager("Titanium","Titanium Root Certificate Authority");
mgr.ClearIdleCertificates(1);
for (int i = 0; i < 1000; i++)
{
foreach (var host in hostNames)
{
tasks.Add(Task.Run(async () =>
{
await Task.Delay(random.Next(0, 10) * 1000);
//get the connection
var certificate = await mgr.CreateCertificate(host, false);
Assert.IsNotNull(certificate);
}));
}
}
await Task.WhenAll(tasks.ToArray());
mgr.StopClearIdleCertificates();
}
}
}
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Network;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
namespace Titanium.Web.Proxy.UnitTests
{
[TestClass]
public class ConnectionManagerTests
{
private readonly static string[] hostNames
= new string[] { "facebook.com", "youtube.com", "google.com",
"bing.com", "yahoo.com"};
private readonly Random random = new Random();
[TestMethod]
public async Task Simple_Create_Connection_Stress_Test()
{
var tasks = new List<Task>();
var mgr = new TcpConnectionManager();
mgr.ClearIdleConnections(1);
for (int i = 0; i < 1000; i++)
{
foreach (var host in hostNames)
{
tasks.Add(Task.Run(async () =>
{
await Task.Delay(random.Next(0, 10) * 1000);
//get the connection
var httpConnection = await mgr.GetClient(host, 80, false, new Version(1, 1), null, null,
8096, System.Security.Authentication.SslProtocols.Default,
120, null, null);
//simulate a work with the connection
await Task.Delay(random.Next(0, 10) * 1000);
//print total number of connections on cache
Debug.WriteLine(mgr.connectionCache.Count);
Assert.IsNotNull(httpConnection);
Assert.IsNotNull(httpConnection.TcpClient);
Assert.IsTrue(httpConnection.TcpClient.Connected);
//release
await mgr.ReleaseClient(httpConnection);
}));
tasks.Add(Task.Run(async () =>
{
await Task.Delay(random.Next(0, 10) * 1000);
//get the connection
var httpsConnection = await mgr.GetClient(host, 443, true, new Version(1, 1), null, null,
8096, System.Security.Authentication.SslProtocols.Default,
120, null, null);
//simulate a work with the connection
await Task.Delay(random.Next(0, 10) * 1000);
//print total number of connections on cache
Debug.WriteLine(mgr.connectionCache.Count);
Assert.IsNotNull(httpsConnection);
Assert.IsNotNull(httpsConnection.TcpClient);
Assert.IsTrue(httpsConnection.TcpClient.Connected);
//release
await mgr.ReleaseClient(httpsConnection);
}));
}
}
await Task.WhenAll(tasks.ToArray());
mgr.StopClearIdleConnections();
}
}
}
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.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Titanium.Web.Proxy.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[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("b517e3d0-d03b-436f-ab03-34ba0d5321af")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B517E3D0-D03B-436F-AB03-34BA0D5321AF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Titanium.Web.Proxy.UnitTests</RootNamespace>
<AssemblyName>Titanium.Web.Proxy.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="CertificateManagerTests.cs" />
<Compile Include="ConnectionManagerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj">
<Project>{8d73a1be-868c-42d2-9ece-f32cc1a02906}</Project>
<Name>Titanium.Web.Proxy</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
...@@ -29,6 +29,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{AC9AE37A ...@@ -29,6 +29,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{AC9AE37A
.build\default.ps1 = .build\default.ps1 .build\default.ps1 = .build\default.ps1
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC1E0789-D348-49CF-8B67-5E99D50EDF64}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.UnitTests", "Tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj", "{B517E3D0-D03B-436F-AB03-34BA0D5321AF}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
...@@ -43,12 +47,17 @@ Global ...@@ -43,12 +47,17 @@ Global
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug|Any CPU.Build.0 = Debug|Any CPU {F3B7E553-1904-4E80-BDC7-212342B5C952}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|Any CPU.Build.0 = Release|Any CPU {F3B7E553-1904-4E80-BDC7-212342B5C952}.Release|Any CPU.Build.0 = Release|Any CPU
{B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{F3B7E553-1904-4E80-BDC7-212342B5C952} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} {F3B7E553-1904-4E80-BDC7-212342B5C952} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B}
{B517E3D0-D03B-436F-AB03-34BA0D5321AF} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
......
...@@ -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 TcpConnectionCache ServerConnection { get; set; } internal CachedTcpConnection 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(TcpConnectionCache Connection) internal void SetConnection(CachedTcpConnection Connection)
{ {
Connection.LastAccess = DateTime.Now; Connection.LastAccess = DateTime.Now;
ServerConnection = Connection; ServerConnection = Connection;
......
...@@ -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 TcpConnectionCache public class CachedTcpConnection
{ {
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 TcpConnectionCache() internal CachedTcpConnection()
{ {
LastAccess = DateTime.Now; LastAccess = DateTime.Now;
} }
......
...@@ -18,12 +18,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -18,12 +18,12 @@ 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 TcpConnectionCacheManager internal class TcpConnectionManager
{ {
/// <summary> /// <summary>
/// Connection cache /// Connection cache
/// </summary> /// </summary>
Dictionary<string, List<TcpConnectionCache>> connectionCache = new Dictionary<string, List<TcpConnectionCache>>(); internal Dictionary<string, List<CachedTcpConnection>> connectionCache = new Dictionary<string, List<CachedTcpConnection>>();
/// <summary> /// <summary>
/// A lock to manage concurrency /// A lock to manage concurrency
...@@ -38,12 +38,14 @@ namespace Titanium.Web.Proxy.Network ...@@ -38,12 +38,14 @@ 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 async Task<TcpConnectionCache> GetClient(string hostname, int port, bool isHttps, Version version, internal async Task<CachedTcpConnection> GetClient(string hostname, int port, bool isHttps, Version version,
ExternalProxy upStreamHttpProxy, ExternalProxy upStreamHttpsProxy, int bufferSize, SslProtocols supportedSslProtocols, ExternalProxy upStreamHttpProxy, ExternalProxy upStreamHttpsProxy, int bufferSize, SslProtocols supportedSslProtocols,
RemoteCertificateValidationCallback remoteCertificateValidationCallBack, LocalCertificateSelectionCallback localCertificateSelectionCallback) int connectionTimeOutSeconds,
RemoteCertificateValidationCallback remoteCertificateValidationCallBack,
LocalCertificateSelectionCallback localCertificateSelectionCallback)
{ {
List<TcpConnectionCache> cachedConnections = null; List<CachedTcpConnection> cachedConnections = null;
TcpConnectionCache cached = null; CachedTcpConnection 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);
...@@ -87,17 +89,10 @@ namespace Titanium.Web.Proxy.Network ...@@ -87,17 +89,10 @@ namespace Titanium.Web.Proxy.Network
if (cached == null) if (cached == null)
{ {
cached = await CreateClient(hostname, port, isHttps, version, upStreamHttpProxy, upStreamHttpsProxy, bufferSize, supportedSslProtocols, cached = await CreateClient(hostname, port, isHttps, version, connectionTimeOutSeconds, upStreamHttpProxy, upStreamHttpsProxy, bufferSize, supportedSslProtocols,
remoteCertificateValidationCallBack, localCertificateSelectionCallback); remoteCertificateValidationCallBack, localCertificateSelectionCallback);
} }
if (cachedConnections == null || cachedConnections.Count() <= 2)
{
var task = CreateClient(hostname, port, isHttps, version, upStreamHttpProxy, upStreamHttpsProxy, bufferSize, supportedSslProtocols,
remoteCertificateValidationCallBack, localCertificateSelectionCallback)
.ContinueWith(async (x) => { if (x.Status == TaskStatus.RanToCompletion) await ReleaseClient(x.Result); });
}
return cached; return cached;
} }
...@@ -122,7 +117,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -122,7 +117,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>
private async Task<TcpConnectionCache> CreateClient(string hostname, int port, bool isHttps, Version version, private async Task<CachedTcpConnection> CreateClient(string hostname, int port, bool isHttps, Version version, int connectionTimeOutSeconds,
ExternalProxy upStreamHttpProxy, ExternalProxy upStreamHttpsProxy, int bufferSize, SslProtocols supportedSslProtocols, ExternalProxy upStreamHttpProxy, ExternalProxy upStreamHttpsProxy, int bufferSize, SslProtocols supportedSslProtocols,
RemoteCertificateValidationCallback remoteCertificateValidationCallBack, LocalCertificateSelectionCallback localCertificateSelectionCallback) RemoteCertificateValidationCallback remoteCertificateValidationCallBack, LocalCertificateSelectionCallback localCertificateSelectionCallback)
{ {
...@@ -137,7 +132,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -137,7 +132,7 @@ namespace Titanium.Web.Proxy.Network
if (upStreamHttpsProxy != null) if (upStreamHttpsProxy != null)
{ {
client = new TcpClient(upStreamHttpsProxy.HostName, upStreamHttpsProxy.Port); client = new TcpClient(upStreamHttpsProxy.HostName, upStreamHttpsProxy.Port);
stream = (Stream)client.GetStream(); stream = client.GetStream();
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true)) using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize, true))
{ {
...@@ -164,7 +159,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -164,7 +159,7 @@ namespace Titanium.Web.Proxy.Network
else else
{ {
client = new TcpClient(hostname, port); client = new TcpClient(hostname, port);
stream = (Stream)client.GetStream(); stream = client.GetStream();
} }
try try
...@@ -174,7 +169,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -174,7 +169,7 @@ namespace Titanium.Web.Proxy.Network
await sslStream.AuthenticateAsClientAsync(hostname, null, supportedSslProtocols, false); await sslStream.AuthenticateAsClientAsync(hostname, null, supportedSslProtocols, false);
stream = (Stream)sslStream; stream = sslStream;
} }
catch catch
{ {
...@@ -191,16 +186,19 @@ namespace Titanium.Web.Proxy.Network ...@@ -191,16 +186,19 @@ namespace Titanium.Web.Proxy.Network
if (upStreamHttpProxy != null) if (upStreamHttpProxy != null)
{ {
client = new TcpClient(upStreamHttpProxy.HostName, upStreamHttpProxy.Port); client = new TcpClient(upStreamHttpProxy.HostName, upStreamHttpProxy.Port);
stream = (Stream)client.GetStream(); stream = client.GetStream();
} }
else else
{ {
client = new TcpClient(hostname, port); client = new TcpClient(hostname, port);
stream = (Stream)client.GetStream(); stream = client.GetStream();
} }
} }
return new TcpConnectionCache() client.ReceiveTimeout = connectionTimeOutSeconds * 1000;
client.SendTimeout = connectionTimeOutSeconds * 1000;
return new CachedTcpConnection()
{ {
HostName = hostname, HostName = hostname,
port = port, port = port,
...@@ -217,7 +215,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -217,7 +215,7 @@ namespace Titanium.Web.Proxy.Network
/// </summary> /// </summary>
/// <param name="connection"></param> /// <param name="connection"></param>
/// <returns></returns> /// <returns></returns>
internal async Task ReleaseClient(TcpConnectionCache connection) internal async Task ReleaseClient(CachedTcpConnection connection)
{ {
connection.LastAccess = DateTime.Now; connection.LastAccess = DateTime.Now;
...@@ -226,7 +224,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -226,7 +224,7 @@ namespace Titanium.Web.Proxy.Network
try try
{ {
List<TcpConnectionCache> cachedConnections; List<CachedTcpConnection> cachedConnections;
connectionCache.TryGetValue(key, out cachedConnections); connectionCache.TryGetValue(key, out cachedConnections);
if (cachedConnections != null) if (cachedConnections != null)
...@@ -235,7 +233,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -235,7 +233,7 @@ namespace Titanium.Web.Proxy.Network
} }
else else
{ {
connectionCache.Add(key, new List<TcpConnectionCache>() { connection }); connectionCache.Add(key, new List<CachedTcpConnection>() { connection });
} }
} }
......
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
...@@ -13,6 +14,7 @@ using System.Runtime.InteropServices; ...@@ -13,6 +14,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("Titanium.Web.Proxy.UnitTests")]
// Setting ComVisible to false makes the types in this assembly not visible // 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 // to COM components. If you need to access a type in this assembly from
......
...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy ...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// A object that manages tcp connection cache to server /// A object that manages tcp connection cache to server
/// </summary> /// </summary>
private TcpConnectionCacheManager tcpConnectionCacheManager { get; set; } private TcpConnectionManager tcpConnectionCacheManager { get; set; }
/// <summary> /// <summary>
/// Manage system proxy settings /// Manage system proxy settings
...@@ -67,15 +67,20 @@ namespace Titanium.Web.Proxy ...@@ -67,15 +67,20 @@ namespace Titanium.Web.Proxy
public bool Enable100ContinueBehaviour { get; set; } public bool Enable100ContinueBehaviour { get; set; }
/// <summary> /// <summary>
/// Minutes TCP connection cache to servers to be kept alive when in idle state /// Minutes TCP connection cache to servers to be kept alive from last time it was used
/// </summary> /// </summary>
public int ConnectionCacheTimeOutMinutes { get; set; } public int ServerConnectionCacheTimeOutMinutes { get; set; }
/// <summary> /// <summary>
/// Minutes certificates should be kept in cache when not used /// Minutes certificates should be kept in cache when not used
/// </summary> /// </summary>
public int CertificateCacheTimeOutMinutes { get; set; } public int CertificateCacheTimeOutMinutes { get; set; }
/// <summary>
/// Seconds client/server connection are to be kept alive when waiting for read/write to complete
/// </summary>
public int ConnectionTimeOutSeconds { get; set; }
/// <summary> /// <summary>
/// Intercept request to server /// Intercept request to server
/// </summary> /// </summary>
...@@ -122,11 +127,12 @@ namespace Titanium.Web.Proxy ...@@ -122,11 +127,12 @@ namespace Titanium.Web.Proxy
public ProxyServer() public ProxyServer()
{ {
//default values //default values
ConnectionCacheTimeOutMinutes = 3; ConnectionTimeOutSeconds = 120;
ServerConnectionCacheTimeOutMinutes = 3;
CertificateCacheTimeOutMinutes = 60; CertificateCacheTimeOutMinutes = 60;
ProxyEndPoints = new List<ProxyEndPoint>(); ProxyEndPoints = new List<ProxyEndPoint>();
tcpConnectionCacheManager = new TcpConnectionCacheManager(); tcpConnectionCacheManager = new TcpConnectionManager();
systemProxySettingsManager = new SystemProxyManager(); systemProxySettingsManager = new SystemProxyManager();
firefoxProxySettingsManager = new FireFoxProxySettingsManager(); firefoxProxySettingsManager = new FireFoxProxySettingsManager();
...@@ -273,7 +279,7 @@ namespace Titanium.Web.Proxy ...@@ -273,7 +279,7 @@ namespace Titanium.Web.Proxy
Listen(endPoint); Listen(endPoint);
} }
tcpConnectionCacheManager.ClearIdleConnections(ConnectionCacheTimeOutMinutes); tcpConnectionCacheManager.ClearIdleConnections(ServerConnectionCacheTimeOutMinutes);
certificateCacheManager.ClearIdleCertificates(CertificateCacheTimeOutMinutes); certificateCacheManager.ClearIdleCertificates(CertificateCacheTimeOutMinutes);
proxyRunning = true; proxyRunning = true;
......
...@@ -27,6 +27,10 @@ namespace Titanium.Web.Proxy ...@@ -27,6 +27,10 @@ namespace Titanium.Web.Proxy
private async void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient client) private async void HandleClient(ExplicitProxyEndPoint endPoint, TcpClient client)
{ {
Stream clientStream = client.GetStream(); Stream clientStream = client.GetStream();
clientStream.ReadTimeout = ConnectionTimeOutSeconds * 1000;
clientStream.WriteTimeout = ConnectionTimeOutSeconds * 1000;
var clientStreamReader = new CustomBinaryReader(clientStream); var clientStreamReader = new CustomBinaryReader(clientStream);
var clientStreamWriter = new StreamWriter(clientStream); var clientStreamWriter = new StreamWriter(clientStream);
...@@ -87,7 +91,8 @@ namespace Titanium.Web.Proxy ...@@ -87,7 +91,8 @@ namespace Titanium.Web.Proxy
//create the Tcp Connection to server and then release it to connection cache //create the Tcp Connection to server and then release it to connection cache
//Just doing what CONNECT request is asking as to do //Just doing what CONNECT request is asking as to do
var tunnelClient = await tcpConnectionCacheManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version, var tunnelClient = await tcpConnectionCacheManager.GetClient(httpRemoteUri.Host, httpRemoteUri.Port, true, version,
UpStreamHttpProxy, UpStreamHttpsProxy, BUFFER_SIZE, SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), UpStreamHttpProxy, UpStreamHttpsProxy, BUFFER_SIZE, SupportedSslProtocols, ConnectionTimeOutSeconds,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
new LocalCertificateSelectionCallback(SelectClientCertificate)); new LocalCertificateSelectionCallback(SelectClientCertificate));
await tcpConnectionCacheManager.ReleaseClient(tunnelClient); await tcpConnectionCacheManager.ReleaseClient(tunnelClient);
...@@ -150,6 +155,10 @@ namespace Titanium.Web.Proxy ...@@ -150,6 +155,10 @@ namespace Titanium.Web.Proxy
private async void HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient) private async void HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient)
{ {
Stream clientStream = tcpClient.GetStream(); Stream clientStream = tcpClient.GetStream();
clientStream.ReadTimeout = ConnectionTimeOutSeconds * 1000;
clientStream.WriteTimeout = ConnectionTimeOutSeconds * 1000;
CustomBinaryReader clientStreamReader = null; CustomBinaryReader clientStreamReader = null;
StreamWriter clientStreamWriter = null; StreamWriter clientStreamWriter = null;
X509Certificate2 certificate = null; X509Certificate2 certificate = null;
...@@ -209,7 +218,7 @@ namespace Titanium.Web.Proxy ...@@ -209,7 +218,7 @@ namespace Titanium.Web.Proxy
private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream,
CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName) CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName)
{ {
TcpConnectionCache connection = null; CachedTcpConnection connection = null;
//Loop through each subsequest request on this particular client connection //Loop through each subsequest request on this particular client connection
//(assuming HTTP connection is kept alive by client) //(assuming HTTP connection is kept alive by client)
...@@ -323,7 +332,7 @@ namespace Titanium.Web.Proxy ...@@ -323,7 +332,7 @@ namespace Titanium.Web.Proxy
//construct the web request that we are going to issue on behalf of the client. //construct the web request that we are going to issue on behalf of the client.
connection = await tcpConnectionCacheManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version, connection = await tcpConnectionCacheManager.GetClient(args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.IsHttps, version,
UpStreamHttpProxy, UpStreamHttpsProxy, BUFFER_SIZE, SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), UpStreamHttpProxy, UpStreamHttpsProxy, BUFFER_SIZE, SupportedSslProtocols, ConnectionTimeOutSeconds, new RemoteCertificateValidationCallback(ValidateServerCertificate),
new LocalCertificateSelectionCallback(SelectClientCertificate)); new LocalCertificateSelectionCallback(SelectClientCertificate));
args.WebSession.Request.RequestLocked = true; args.WebSession.Request.RequestLocked = true;
......
...@@ -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\TcpConnectionCache.cs" /> <Compile Include="Network\CachedTcpConnection.cs" />
<Compile Include="Network\TcpConnectionCacheManager.cs" /> <Compile Include="Network\TcpConnectionManager.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