Commit 9afb81c6 authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #238 from justcoding121/develop

Beta
parents 69aa70c1 3e58c39d
using System;
using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Examples.Basic.Helpers
{
/// <summary>
/// Adapated from
/// http://stackoverflow.com/questions/13656846/how-to-programmatic-disable-c-sharp-console-applications-quick-edit-mode
/// </summary>
internal static class ConsoleHelper
{
const uint ENABLE_QUICK_EDIT = 0x0040;
// STD_INPUT_HANDLE (DWORD): -10 is the standard input device.
const int STD_INPUT_HANDLE = -10;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll")]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll")]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
internal static bool DisableQuickEditMode()
{
IntPtr consoleHandle = GetStdHandle(STD_INPUT_HANDLE);
// get current console mode
uint consoleMode;
if (!GetConsoleMode(consoleHandle, out consoleMode))
{
// ERROR: Unable to get console mode.
return false;
}
// Clear the quick edit bit in the mode flags
consoleMode &= ~ENABLE_QUICK_EDIT;
// set the new mode
if (!SetConsoleMode(consoleHandle, consoleMode))
{
// ERROR: Unable to set console mode
return false;
}
return true;
}
}
}
using System; using System;
using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Titanium.Web.Proxy.Examples.Basic.Helpers;
namespace Titanium.Web.Proxy.Examples.Basic namespace Titanium.Web.Proxy.Examples.Basic
{ {
...@@ -9,11 +11,13 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -9,11 +11,13 @@ namespace Titanium.Web.Proxy.Examples.Basic
public static void Main(string[] args) public static void Main(string[] args)
{ {
//fix console hang due to QuickEdit mode
ConsoleHelper.DisableQuickEditMode();
//On Console exit make sure we also exit the proxy //On Console exit make sure we also exit the proxy
NativeMethods.Handler = ConsoleEventCallback; NativeMethods.Handler = ConsoleEventCallback;
NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true); NativeMethods.SetConsoleCtrlHandler(NativeMethods.Handler, true);
//Start proxy controller //Start proxy controller
controller.StartProxy(); controller.StartProxy();
...@@ -50,5 +54,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -50,5 +54,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
// Pinvoke // Pinvoke
internal delegate bool ConsoleEventDelegate(int eventType); internal delegate bool ConsoleEventDelegate(int eventType);
} }
}
\ No newline at end of file }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Net; using System.Net;
using System.Net.Security;
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;
...@@ -47,18 +47,18 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -47,18 +47,18 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Useful for clients that use certificate pinning //Useful for clients that use certificate pinning
//for example google.com and dropbox.com //for example google.com and dropbox.com
ExcludedHttpsHostNameRegex = new List<string>() { "dropbox.com" } ExcludedHttpsHostNameRegex = new List<string> { "dropbox.com" }
//Include Https addresses you want to proxy (others will be excluded) //Include Https addresses you want to proxy (others will be excluded)
//for example github.com //for example github.com
// IncludedHttpsHostNameRegex = new List<string>() { "github.com" } //IncludedHttpsHostNameRegex = new List<string> { "github.com" }
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown //You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
//Use self-issued generic certificate on all https requests //Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each https-enabled domain //Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients //Useful when certificate trust is not required by proxy clients
// GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password") //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
}; };
//An explicit endpoint is where the client knows about the existence of a proxy //An explicit endpoint is where the client knows about the existence of a proxy
...@@ -107,7 +107,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -107,7 +107,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//intecept & cancel redirect or update requests //intecept & cancel redirect or update requests
public async Task OnRequest(object sender, SessionEventArgs e) public async Task OnRequest(object sender, SessionEventArgs e)
{ {
Console.WriteLine("Active Client Connections:" + ((ProxyServer) sender).ClientConnectionCount); Console.WriteLine("Active Client Connections:" + ((ProxyServer)sender).ClientConnectionCount);
Console.WriteLine(e.WebSession.Request.Url); Console.WriteLine(e.WebSession.Request.Url);
//read request headers //read request headers
...@@ -150,7 +150,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -150,7 +150,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//Modify response //Modify response
public async Task OnResponse(object sender, SessionEventArgs e) public async Task OnResponse(object sender, SessionEventArgs e)
{ {
Console.WriteLine("Active Server Connections:" + (sender as ProxyServer).ServerConnectionCount); Console.WriteLine("Active Server Connections:" + ((ProxyServer)sender).ServerConnectionCount);
if (requestBodyHistory.ContainsKey(e.Id)) if (requestBodyHistory.ContainsKey(e.Id))
{ {
...@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -189,7 +189,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{ {
//set IsValid to true/false based on Certificate Errors //set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None) if (e.SslPolicyErrors == SslPolicyErrors.None)
{ {
e.IsValid = true; e.IsValid = true;
} }
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Helpers\ConsoleHelper.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyTestController.cs" /> <Compile Include="ProxyTestController.cs" />
......
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
......
using System; using System;
using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using System.Net.Http;
using System.Diagnostics;
namespace Titanium.Web.Proxy.IntegrationTests namespace Titanium.Web.Proxy.IntegrationTests
{ {
...@@ -13,7 +14,6 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -13,7 +14,6 @@ namespace Titanium.Web.Proxy.IntegrationTests
public class SslTests public class SslTests
{ {
[TestMethod] [TestMethod]
public void TestSsl() public void TestSsl()
{ {
//expand this to stress test to find //expand this to stress test to find
...@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -103,7 +103,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)
{ {
//set IsValid to true/false based on Certificate Errors //set IsValid to true/false based on Certificate Errors
if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None) if (e.SslPolicyErrors == SslPolicyErrors.None)
{ {
e.IsValid = true; e.IsValid = true;
} }
......
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Titanium.Web.Proxy.UnitTests namespace Titanium.Web.Proxy.UnitTests
{ {
...@@ -10,8 +10,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -10,8 +10,7 @@ namespace Titanium.Web.Proxy.UnitTests
public class CertificateManagerTests public class CertificateManagerTests
{ {
private static readonly string[] hostNames private static readonly string[] hostNames
= new string[] { "facebook.com", "youtube.com", "google.com", = { "facebook.com", "youtube.com", "google.com", "bing.com", "yahoo.com" };
"bing.com", "yahoo.com"};
private readonly Random random = new Random(); private readonly Random random = new Random();
...@@ -36,16 +35,13 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -36,16 +35,13 @@ namespace Titanium.Web.Proxy.UnitTests
var certificate = mgr.CreateCertificate(host, false); var certificate = mgr.CreateCertificate(host, false);
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
})); }));
} }
} }
await Task.WhenAll(tasks.ToArray()); await Task.WhenAll(tasks.ToArray());
mgr.StopClearIdleCertificates(); mgr.StopClearIdleCertificates();
} }
} }
} }
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">240</s:Int64>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CN/@EntryIndexedValue">CN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DN/@EntryIndexedValue">DN</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EKU/@EntryIndexedValue">EKU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KU/@EntryIndexedValue">KU</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MTA/@EntryIndexedValue">MTA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OID/@EntryIndexedValue">OID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OIDS/@EntryIndexedValue">OIDS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=dda2ffa1_002D435c_002D4111_002D88eb_002D1a7c93c382f0/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=dda2ffa1_002D435c_002D4111_002D88eb_002D1a7c93c382f0/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="PROPERTY" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
\ No newline at end of file <s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
\ No newline at end of file
using System; using System;
using System.Net.Security; using System.Net.Security;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -32,17 +32,8 @@ namespace Titanium.Web.Proxy ...@@ -32,17 +32,8 @@ namespace Titanium.Web.Proxy
SslPolicyErrors = sslPolicyErrors SslPolicyErrors = sslPolicyErrors
}; };
//why is the sender null?
Delegate[] invocationList = ServerCertificateValidationCallback.GetInvocationList(); ServerCertificateValidationCallback.InvokeParallel(this, args);
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, CertificateValidationEventArgs, Task>) invocationList[i])(null, args);
}
Task.WhenAll(handlerTasks).Wait();
return args.IsValid; return args.IsValid;
} }
...@@ -108,17 +99,8 @@ namespace Titanium.Web.Proxy ...@@ -108,17 +99,8 @@ namespace Titanium.Web.Proxy
ClientCertificate = clientCertificate ClientCertificate = clientCertificate
}; };
//why is the sender null?
Delegate[] invocationList = ClientCertificateSelectionCallback.GetInvocationList(); ClientCertificateSelectionCallback.InvokeParallel(this, args);
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, CertificateSelectionEventArgs, Task>) invocationList[i])(null, args);
}
Task.WhenAll(handlerTasks).Wait();
return args.ClientCertificate; return args.ClientCertificate;
} }
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Exceptions; using System.Threading.Tasks;
using Titanium.Web.Proxy.Decompression; using Titanium.Web.Proxy.Decompression;
using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses; using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Extensions;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Network;
using System.Net;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
...@@ -56,7 +56,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -56,7 +56,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// <summary> /// <summary>
/// Client End Point. /// Client End Point.
/// </summary> /// </summary>
public IPEndPoint ClientEndPoint => (IPEndPoint) ProxyClient.TcpClient.Client.RemoteEndPoint; public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
/// <summary> /// <summary>
/// A web session corresponding to a single request/response sequence /// A web session corresponding to a single request/response sequence
...@@ -158,7 +158,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -158,7 +158,7 @@ namespace Titanium.Web.Proxy.EventArguments
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream,
WebSession.Response.ContentLength); WebSession.Response.ContentLength);
} }
else if ((WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0) || WebSession.Response.ContentLength == -1) else if (WebSession.Response.HttpVersion.Major == 1 && WebSession.Response.HttpVersion.Minor == 0 || WebSession.Response.ContentLength == -1)
{ {
await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, long.MaxValue); await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, long.MaxValue);
} }
...@@ -522,6 +522,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -522,6 +522,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
WebSession.Dispose();
} }
} }
} }
using System;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Extensions
{
internal static class FuncExtensions
{
public static void InvokeParallel<T>(this Func<object, T, Task> callback, object sender, T args)
{
Delegate[] invocationList = callback.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, T, Task>)invocationList[i])(sender, args);
}
Task.WhenAll(handlerTasks).Wait();
}
public static async Task InvokeParallelAsync<T>(this Func<object, T, Task> callback, object sender, T args)
{
Delegate[] invocationList = callback.GetInvocationList();
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, T, Task>)invocationList[i])(sender, args);
}
await Task.WhenAll(handlerTasks);
}
}
}
...@@ -136,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -136,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions
if (contentLength < bufferSize) if (contentLength < bufferSize)
{ {
bytesToRead = (int) contentLength; bytesToRead = (int)contentLength;
} }
var buffer = new byte[bufferSize]; var buffer = new byte[bufferSize];
...@@ -153,8 +153,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -153,8 +153,8 @@ namespace Titanium.Web.Proxy.Extensions
break; break;
bytesRead = 0; bytesRead = 0;
var remainingBytes = (contentLength - totalBytesRead); var remainingBytes = contentLength - totalBytesRead;
bytesToRead = remainingBytes > (long) bufferSize ? bufferSize : (int) remainingBytes; bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes;
} }
} }
else else
......
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
...@@ -18,10 +19,18 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -18,10 +19,18 @@ namespace Titanium.Web.Proxy.Helpers
private readonly byte[] staticBuffer; private readonly byte[] staticBuffer;
private readonly Encoding encoding; private readonly Encoding encoding;
private static readonly ConcurrentQueue<byte[]> buffers
= new ConcurrentQueue<byte[]>();
private volatile bool disposed;
internal CustomBinaryReader(CustomBufferedStream stream, int bufferSize) internal CustomBinaryReader(CustomBufferedStream stream, int bufferSize)
{ {
this.stream = stream; this.stream = stream;
staticBuffer = new byte[bufferSize]; if (!buffers.TryDequeue(out staticBuffer) || staticBuffer.Length != bufferSize)
{
staticBuffer = new byte[bufferSize];
}
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
...@@ -112,7 +121,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -112,7 +121,7 @@ namespace Titanium.Web.Proxy.Helpers
var buffer = staticBuffer; var buffer = staticBuffer;
if (totalBytesToRead < bufferSize) if (totalBytesToRead < bufferSize)
{ {
bytesToRead = (int) totalBytesToRead; bytesToRead = (int)totalBytesToRead;
buffer = new byte[bytesToRead]; buffer = new byte[bytesToRead];
} }
...@@ -127,7 +136,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -127,7 +136,7 @@ namespace Titanium.Web.Proxy.Helpers
break; break;
var remainingBytes = totalBytesToRead - totalBytesRead; var remainingBytes = totalBytesToRead - totalBytesRead;
bytesToRead = Math.Min(bufferSize, (int) remainingBytes); bytesToRead = Math.Min(bufferSize, (int)remainingBytes);
if (totalBytesRead + bytesToRead > buffer.Length) if (totalBytesRead + bytesToRead > buffer.Length)
{ {
...@@ -148,8 +157,18 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -148,8 +157,18 @@ namespace Titanium.Web.Proxy.Helpers
public void Dispose() public void Dispose()
{ {
if (!disposed)
{
disposed = true;
buffers.Enqueue(staticBuffer);
}
} }
/// <summary>
/// Increase size of buffer and copy existing content to new buffer
/// </summary>
/// <param name="buffer"></param>
/// <param name="size"></param>
private void ResizeBuffer(ref byte[] buffer, long size) private void ResizeBuffer(ref byte[] buffer, long size)
{ {
var newBuffer = new byte[size]; var newBuffer = new byte[size];
......
...@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -198,7 +198,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
if (asyncResult is ReadAsyncResult) if (asyncResult is ReadAsyncResult)
{ {
return ((ReadAsyncResult) asyncResult).ReadBytes; return ((ReadAsyncResult)asyncResult).ReadBytes;
} }
return baseStream.EndRead(asyncResult); return baseStream.EndRead(asyncResult);
......
using System; using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Text.RegularExpressions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Microsoft.Win32;
// Helper classes for setting system proxy settings // Helper classes for setting system proxy settings
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
...@@ -84,7 +84,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -84,7 +84,7 @@ namespace Titanium.Web.Proxy.Helpers
var exisitingContent = reg.GetValue("ProxyServer") as string; var exisitingContent = reg.GetValue("ProxyServer") as string;
var existingSystemProxyValues = GetSystemProxyValues(exisitingContent); var existingSystemProxyValues = GetSystemProxyValues(exisitingContent);
existingSystemProxyValues.RemoveAll(x => protocolType == ProxyProtocolType.Https ? x.IsHttps : !x.IsHttps); existingSystemProxyValues.RemoveAll(x => protocolType == ProxyProtocolType.Https ? x.IsHttps : !x.IsHttps);
existingSystemProxyValues.Add(new HttpSystemProxyValue() existingSystemProxyValues.Add(new HttpSystemProxyValue
{ {
HostName = hostname, HostName = hostname,
IsHttps = protocolType == ProxyProtocolType.Https, IsHttps = protocolType == ProxyProtocolType.Https,
......
...@@ -3,10 +3,9 @@ using System.Collections.Generic; ...@@ -3,10 +3,9 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Net.Security;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -15,8 +14,6 @@ using Titanium.Web.Proxy.Shared; ...@@ -15,8 +14,6 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
using System.Net;
internal enum IpVersion internal enum IpVersion
{ {
Ipv4 = 1, Ipv4 = 1,
...@@ -232,7 +229,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -232,7 +229,7 @@ namespace Titanium.Web.Proxy.Helpers
finally finally
{ {
tcpConnection.Dispose(); tcpConnection.Dispose();
server.ServerConnectionCount--; Interlocked.Decrement(ref server.ServerConnectionCountField);
} }
} }
} }
......
...@@ -8,8 +8,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -8,8 +8,8 @@ namespace Titanium.Web.Proxy.Http
{ {
internal static class HeaderParser internal static class HeaderParser
{ {
internal static async Task ReadHeaders(CustomBinaryReader reader, internal static async Task ReadHeaders(CustomBinaryReader reader,
Dictionary<string, List<HttpHeader>> nonUniqueResponseHeaders, Dictionary<string, List<HttpHeader>> nonUniqueResponseHeaders,
Dictionary<string, HttpHeader> headers) Dictionary<string, HttpHeader> headers)
{ {
string tmpLine; string tmpLine;
......
...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -11,7 +11,7 @@ namespace Titanium.Web.Proxy.Http
/// <summary> /// <summary>
/// Used to communicate with the server over HTTP(S) /// Used to communicate with the server over HTTP(S)
/// </summary> /// </summary>
public class HttpWebClient public class HttpWebClient : IDisposable
{ {
/// <summary> /// <summary>
/// Connection to server /// Connection to server
...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,7 +79,7 @@ namespace Titanium.Web.Proxy.Http
var requestLines = new StringBuilder(); var requestLines = new StringBuilder();
//prepare the request & headers //prepare the request & headers
if ((ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false) || (ServerConnection.UpStreamHttpsProxy != null && ServerConnection.IsHttps)) if (ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false || ServerConnection.UpStreamHttpsProxy != null && ServerConnection.IsHttps)
{ {
requestLines.AppendLine($"{Request.Method} {Request.RequestUri.AbsoluteUri} HTTP/{Request.HttpVersion.Major}.{Request.HttpVersion.Minor}"); requestLines.AppendLine($"{Request.Method} {Request.RequestUri.AbsoluteUri} HTTP/{Request.HttpVersion.Major}.{Request.HttpVersion.Minor}");
} }
...@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -93,7 +93,7 @@ namespace Titanium.Web.Proxy.Http
{ {
requestLines.AppendLine("Proxy-Connection: keep-alive"); requestLines.AppendLine("Proxy-Connection: keep-alive");
requestLines.AppendLine("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes( requestLines.AppendLine("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(
$"{ServerConnection.UpStreamHttpProxy.UserName}:{ServerConnection.UpStreamHttpProxy.Password}"))); $"{ServerConnection.UpStreamHttpProxy.UserName}:{ServerConnection.UpStreamHttpProxy.Password}")));
} }
//write request headers //write request headers
foreach (var headerItem in Request.RequestHeaders) foreach (var headerItem in Request.RequestHeaders)
...@@ -208,5 +208,20 @@ namespace Titanium.Web.Proxy.Http ...@@ -208,5 +208,20 @@ namespace Titanium.Web.Proxy.Http
//Read the response headers in to unique and non-unique header collections //Read the response headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.NonUniqueResponseHeaders, Response.ResponseHeaders); await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.NonUniqueResponseHeaders, Response.ResponseHeaders);
} }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
//not really needed since GC will collect it
//but just to be on safe side
Request.RequestBody = null;
Response.ResponseBody = null;
Request.RequestBodyString = null;
Response.ResponseBodyString = null;
}
} }
} }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
...@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -241,7 +241,7 @@ namespace Titanium.Web.Proxy.Http
/// request body as string /// request body as string
/// </summary> /// </summary>
internal string RequestBodyString { get; set; } internal string RequestBodyString { get; set; }
internal bool RequestBodyRead { get; set; } internal bool RequestBodyRead { get; set; }
internal bool RequestLocked { get; set; } internal bool RequestLocked { get; set; }
......
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using System; using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
......
...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Http.Responses
/// <param name="status"></param> /// <param name="status"></param>
public GenericResponse(HttpStatusCode status) public GenericResponse(HttpStatusCode status)
{ {
ResponseStatusCode = ((int) status).ToString(); ResponseStatusCode = ((int)status).ToString();
ResponseStatusDescription = status.ToString(); ResponseStatusDescription = status.ToString();
} }
......
...@@ -110,7 +110,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -110,7 +110,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
// Corresponding private key // Corresponding private key
var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
var seq = (Asn1Sequence) Asn1Object.FromByteArray(privateKeyInfo.ParsePrivateKey().GetDerEncoded()); var seq = (Asn1Sequence)Asn1Object.FromByteArray(privateKeyInfo.ParsePrivateKey().GetDerEncoded());
if (seq.Count != 9) if (seq.Count != 9)
{ {
......
...@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -89,7 +89,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
} }
var x500CertDN = Activator.CreateInstance(typeX500DN); var x500CertDN = Activator.CreateInstance(typeX500DN);
var typeValue = new object[] {fullSubject, 0}; var typeValue = new object[] { fullSubject, 0 };
typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500CertDN, typeValue); typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500CertDN, typeValue);
var x500RootCertDN = Activator.CreateInstance(typeX500DN); var x500RootCertDN = Activator.CreateInstance(typeX500DN);
...@@ -110,16 +110,16 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -110,16 +110,16 @@ namespace Titanium.Web.Proxy.Network.Certificate
if (sharedPrivateKey == null) if (sharedPrivateKey == null)
{ {
sharedPrivateKey = Activator.CreateInstance(typeX509PrivateKey); sharedPrivateKey = Activator.CreateInstance(typeX509PrivateKey);
typeValue = new object[] {sProviderName}; typeValue = new object[] { sProviderName };
typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue); typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
typeValue[0] = 2; typeValue[0] = 2;
typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue); typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
typeValue = new object[] {(isRoot ? 2 : 1)}; typeValue = new object[] { isRoot ? 2 : 1 };
typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue); typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
if (!isRoot) if (!isRoot)
{ {
typeValue = new object[] {176}; typeValue = new object[] { 176 };
typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue); typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue);
} }
...@@ -149,9 +149,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -149,9 +149,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
var requestCert = Activator.CreateInstance(typeRequestCert); var requestCert = Activator.CreateInstance(typeRequestCert);
typeValue = new[] {1, sharedPrivateKey, string.Empty}; typeValue = new[] { 1, sharedPrivateKey, string.Empty };
typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, requestCert, typeValue); typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, requestCert, typeValue);
typeValue = new[] {x500CertDN}; typeValue = new[] { x500CertDN };
typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, requestCert, typeValue); typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeValue[0] = x500RootCertDN; typeValue[0] = x500RootCertDN;
typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, requestCert, typeValue); typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, requestCert, typeValue);
...@@ -186,14 +186,14 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -186,14 +186,14 @@ namespace Titanium.Web.Proxy.Network.Certificate
var extNames = Activator.CreateInstance(typeExtNames); var extNames = Activator.CreateInstance(typeExtNames);
var altDnsNames = Activator.CreateInstance(typeCAlternativeName); var altDnsNames = Activator.CreateInstance(typeCAlternativeName);
typeValue = new object[] {3, subject}; typeValue = new object[] { 3, subject };
typeCAlternativeName.InvokeMember("InitializeFromString", BindingFlags.InvokeMethod, null, altDnsNames, typeValue); typeCAlternativeName.InvokeMember("InitializeFromString", BindingFlags.InvokeMethod, null, altDnsNames, typeValue);
typeValue = new[] {altDnsNames}; typeValue = new[] { altDnsNames };
typeAltNamesCollection.InvokeMember("Add", BindingFlags.InvokeMethod, null, altNameCollection, typeValue); typeAltNamesCollection.InvokeMember("Add", BindingFlags.InvokeMethod, null, altNameCollection, typeValue);
typeValue = new[] {altNameCollection}; typeValue = new[] { altNameCollection };
typeExtNames.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, extNames, typeValue); typeExtNames.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, extNames, typeValue);
typeValue[0] = extNames; typeValue[0] = extNames;
...@@ -204,27 +204,27 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -204,27 +204,27 @@ namespace Titanium.Web.Proxy.Network.Certificate
{ {
var signerCertificate = Activator.CreateInstance(typeSignerCertificate); var signerCertificate = Activator.CreateInstance(typeSignerCertificate);
typeValue = new object[] {0, 0, 12, signingCertificate.Thumbprint}; typeValue = new object[] { 0, 0, 12, signingCertificate.Thumbprint };
typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, signerCertificate, typeValue); typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, signerCertificate, typeValue);
typeValue = new[] {signerCertificate}; typeValue = new[] { signerCertificate };
typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, requestCert, typeValue); typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, requestCert, typeValue);
} }
else else
{ {
var basicConstraints = Activator.CreateInstance(typeBasicConstraints); var basicConstraints = Activator.CreateInstance(typeBasicConstraints);
typeValue = new object[] {"true", "0"}; typeValue = new object[] { "true", "0" };
typeBasicConstraints.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, basicConstraints, typeValue); typeBasicConstraints.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, basicConstraints, typeValue);
typeValue = new[] {basicConstraints}; typeValue = new[] { basicConstraints };
typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue); typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, certificate, typeValue);
} }
oid = Activator.CreateInstance(typeOID); oid = Activator.CreateInstance(typeOID);
typeValue = new object[] {1, 0, 0, hashAlg}; typeValue = new object[] { 1, 0, 0, hashAlg };
typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, oid, typeValue); typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, oid, typeValue);
typeValue = new[] {oid}; typeValue = new[] { oid };
typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, requestCert, typeValue); typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, requestCert, typeValue);
typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, requestCert, null); typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, requestCert, null);
...@@ -243,15 +243,15 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -243,15 +243,15 @@ namespace Titanium.Web.Proxy.Network.Certificate
typeValue[0] = 0; typeValue[0] = 0;
var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue); var createCertRequest = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
typeValue = new[] {2, createCertRequest, 0, string.Empty}; typeValue = new[] { 2, createCertRequest, 0, string.Empty };
typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue); typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
typeValue = new object[] {null, 0, 1}; typeValue = new object[] { null, 0, 1 };
try try
{ {
var empty = (string) typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue); var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue);
return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable); return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable);
} }
catch (Exception) catch (Exception)
...@@ -293,8 +293,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -293,8 +293,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
var graceTime = DateTime.Now.AddDays(GraceDays); var graceTime = DateTime.Now.AddDays(GraceDays);
var now = DateTime.Now; var now = DateTime.Now;
rCert = !isRoot ? MakeCertificate(false, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), signingCert) : rCert = MakeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), isRoot ? null : signingCert);
MakeCertificate(true, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), null);
return rCert; return rCert;
} }
} }
......
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq;
using System.Collections.Concurrent;
using System.IO;
using Titanium.Web.Proxy.Network.Certificate;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Network.Certificate;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
...@@ -51,7 +52,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -51,7 +52,7 @@ namespace Titanium.Web.Proxy.Network
if (certEngine == null) if (certEngine == null)
{ {
certEngine = engine == CertificateEngine.BouncyCastle certEngine = engine == CertificateEngine.BouncyCastle
? (ICertificateMaker) new BCCertificateMaker() ? (ICertificateMaker)new BCCertificateMaker()
: new WinCertificateMaker(); : new WinCertificateMaker();
} }
} }
...@@ -132,12 +133,12 @@ namespace Titanium.Web.Proxy.Network ...@@ -132,12 +133,12 @@ namespace Titanium.Web.Proxy.Network
private string GetRootCertificatePath() private string GetRootCertificatePath()
{ {
var assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; var assemblyLocation = Assembly.GetExecutingAssembly().Location;
// dynamically loaded assemblies returns string.Empty location // dynamically loaded assemblies returns string.Empty location
if (assemblyLocation == string.Empty) if (assemblyLocation == string.Empty)
{ {
assemblyLocation = System.Reflection.Assembly.GetEntryAssembly().Location; assemblyLocation = Assembly.GetEntryAssembly().Location;
} }
var path = Path.GetDirectoryName(assemblyLocation); var path = Path.GetDirectoryName(assemblyLocation);
...@@ -264,7 +265,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -264,7 +265,7 @@ namespace Titanium.Web.Proxy.Network
} }
if (certificate != null && !certificateCache.ContainsKey(certificateName)) if (certificate != null && !certificateCache.ContainsKey(certificateName))
{ {
certificateCache.Add(certificateName, new CachedCertificate {Certificate = certificate}); certificateCache.Add(certificateName, new CachedCertificate { Certificate = certificate });
} }
} }
else else
......
...@@ -58,7 +58,21 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -58,7 +58,21 @@ namespace Titanium.Web.Proxy.Network.Tcp
StreamReader?.Dispose(); StreamReader?.Dispose();
TcpClient?.Close(); try
{
if (TcpClient != null)
{
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
TcpClient.LingerState = new LingerOption(true, 0);
TcpClient.Close();
}
}
catch
{
}
} }
} }
} }
using System; using System;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO; using Titanium.Web.Proxy.Extensions;
using System.Net.Security;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using System.Linq;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Network.Tcp namespace Titanium.Web.Proxy.Network.Tcp
...@@ -17,7 +18,6 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -17,7 +18,6 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
internal class TcpConnectionFactory internal class TcpConnectionFactory
{ {
/// <summary> /// <summary>
/// Creates a TCP connection to server /// Creates a TCP connection to server
/// </summary> /// </summary>
...@@ -30,19 +30,19 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -30,19 +30,19 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="externalHttpsProxy"></param> /// <param name="externalHttpsProxy"></param>
/// <param name="clientStream"></param> /// <param name="clientStream"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpConnection> CreateClient(ProxyServer server, internal async Task<TcpConnection> CreateClient(ProxyServer server,
string remoteHostName, int remotePort, Version httpVersion, string remoteHostName, int remotePort, Version httpVersion,
bool isHttps, bool isHttps,
ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy, ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy,
Stream clientStream) Stream clientStream)
{ {
TcpClient client; TcpClient client;
CustomBufferedStream stream; CustomBufferedStream stream;
bool isLocalhost = (externalHttpsProxy == null && externalHttpProxy == null) ? false : NetworkHelper.IsLocalIpAddress(remoteHostName); bool isLocalhost = (externalHttpsProxy != null || externalHttpProxy != null) && NetworkHelper.IsLocalIpAddress(remoteHostName);
bool useHttpsProxy = externalHttpsProxy != null && externalHttpsProxy.HostName != remoteHostName && (externalHttpsProxy.BypassForLocalhost && !isLocalhost); bool useHttpsProxy = externalHttpsProxy != null && externalHttpsProxy.HostName != remoteHostName && externalHttpsProxy.BypassForLocalhost && !isLocalhost;
bool useHttpProxy = externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName && (externalHttpProxy.BypassForLocalhost && !isLocalhost); bool useHttpProxy = externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName && externalHttpProxy.BypassForLocalhost && !isLocalhost;
if (isHttps) if (isHttps)
{ {
...@@ -55,7 +55,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -55,7 +55,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port); await client.ConnectAsync(externalHttpsProxy.HostName, externalHttpsProxy.Port);
stream = new CustomBufferedStream(client.GetStream(), server.BufferSize); stream = new CustomBufferedStream(client.GetStream(), server.BufferSize);
using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true) {NewLine = ProxyConstants.NewLine}) using (var writer = new StreamWriter(stream, Encoding.ASCII, server.BufferSize, true) { NewLine = ProxyConstants.NewLine })
{ {
await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}"); await writer.WriteLineAsync($"CONNECT {remoteHostName}:{remotePort} HTTP/{httpVersion}");
await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}"); await writer.WriteLineAsync($"Host: {remoteHostName}:{remotePort}");
...@@ -75,7 +75,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -75,7 +75,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
{ {
var result = await reader.ReadLineAsync(); var result = await reader.ReadLineAsync();
if (!new[] {"200 OK", "connection established"}.Any(s => result.ContainsIgnoreCase(s))) if (!new[] { "200 OK", "connection established" }.Any(s => result.ContainsIgnoreCase(s)))
{ {
throw new Exception("Upstream proxy failed to create a secure tunnel"); throw new Exception("Upstream proxy failed to create a secure tunnel");
} }
...@@ -125,9 +125,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -125,9 +125,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
client.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000; client.ReceiveTimeout = server.ConnectionTimeOutSeconds * 1000;
client.SendTimeout = server.ConnectionTimeOutSeconds * 1000; client.SendTimeout = server.ConnectionTimeOutSeconds * 1000;
client.LingerState = new LingerOption(true, 0); Interlocked.Increment(ref server.ServerConnectionCountField);
server.ServerConnectionCount++;
return new TcpConnection return new TcpConnection
{ {
......
...@@ -70,8 +70,8 @@ namespace Titanium.Web.Proxy ...@@ -70,8 +70,8 @@ namespace Titanium.Web.Proxy
{ {
ResponseHeaders = new Dictionary<string, HttpHeader> ResponseHeaders = new Dictionary<string, HttpHeader>
{ {
{"Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"")}, { "Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"") },
{"Proxy-Connection", new HttpHeader("Proxy-Connection", "close")} { "Proxy-Connection", new HttpHeader("Proxy-Connection", "close") }
} }
}; };
await WriteResponseHeaders(clientStreamWriter, response); await WriteResponseHeaders(clientStreamWriter, response);
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using System.Linq;
using System.Security.Authentication;
using Titanium.Web.Proxy.Network.Tcp; using Titanium.Web.Proxy.Network.Tcp;
using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -35,6 +36,8 @@ namespace Titanium.Web.Proxy ...@@ -35,6 +36,8 @@ namespace Titanium.Web.Proxy
private Action<Exception> exceptionFunc; private Action<Exception> exceptionFunc;
private bool trustRootCertificate; private bool trustRootCertificate;
private int clientConnectionCountField;
internal int ServerConnectionCountField;
/// <summary> /// <summary>
/// A object that creates tcp connection to server /// A object that creates tcp connection to server
...@@ -50,8 +53,7 @@ namespace Titanium.Web.Proxy ...@@ -50,8 +53,7 @@ namespace Titanium.Web.Proxy
/// <summary> /// <summary>
/// Set firefox to use default system proxy /// Set firefox to use default system proxy
/// </summary> /// </summary>
private FireFoxProxySettingsManager firefoxProxySettingsManager private FireFoxProxySettingsManager firefoxProxySettingsManager = new FireFoxProxySettingsManager();
= new FireFoxProxySettingsManager();
#endif #endif
/// <summary> /// <summary>
...@@ -224,18 +226,18 @@ namespace Titanium.Web.Proxy ...@@ -224,18 +226,18 @@ namespace Titanium.Web.Proxy
/// List of supported Ssl versions /// List of supported Ssl versions
/// </summary> /// </summary>
public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Tls public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Tls
| SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3; | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3;
/// <summary> /// <summary>
/// Total number of active client connections /// Total number of active client connections
/// </summary> /// </summary>
public int ClientConnectionCount { get; private set; } public int ClientConnectionCount => clientConnectionCountField;
/// <summary> /// <summary>
/// Total number of active server connections /// Total number of active server connections
/// </summary> /// </summary>
public int ServerConnectionCount { get; internal set; } public int ServerConnectionCount => ServerConnectionCountField;
/// <summary> /// <summary>
/// Constructor /// Constructor
...@@ -381,8 +383,7 @@ namespace Titanium.Web.Proxy ...@@ -381,8 +383,7 @@ namespace Titanium.Web.Proxy
#if !DEBUG #if !DEBUG
firefoxProxySettingsManager.AddFirefox(); firefoxProxySettingsManager.AddFirefox();
#endif #endif
Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System HTTPS Proxy", Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System HTTPS Proxy", endPoint.IpAddress, endPoint.Port);
endPoint.IpAddress, endPoint.Port);
} }
/// <summary> /// <summary>
...@@ -596,13 +597,7 @@ namespace Titanium.Web.Proxy ...@@ -596,13 +597,7 @@ namespace Titanium.Web.Proxy
{ {
Task.Run(async () => Task.Run(async () =>
{ {
ClientConnectionCount++; Interlocked.Increment(ref clientConnectionCountField);
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
tcpClient.LingerState = new LingerOption(true, 0);
try try
{ {
...@@ -617,8 +612,23 @@ namespace Titanium.Web.Proxy ...@@ -617,8 +612,23 @@ namespace Titanium.Web.Proxy
} }
finally finally
{ {
ClientConnectionCount--; Interlocked.Decrement(ref clientConnectionCountField);
tcpClient?.Close();
try
{
if (tcpClient != null)
{
//This line is important!
//contributors please don't remove it without discussion
//It helps to avoid eventual deterioration of performance due to TCP port exhaustion
//due to default TCP CLOSE_WAIT timeout for 4 minutes
tcpClient.LingerState = new LingerOption(true, 0);
tcpClient.Close();
}
}
catch
{
}
} }
}); });
} }
......
This diff is collapsed.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Titanium.Web.Proxy.EventArguments; using System.Threading;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Compression;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions; using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.Tcp; using Titanium.Web.Proxy.Network.Tcp;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
...@@ -22,7 +23,7 @@ namespace Titanium.Web.Proxy ...@@ -22,7 +23,7 @@ namespace Titanium.Web.Proxy
/// Called asynchronously when a request was successfully and we received the response /// Called asynchronously when a request was successfully and we received the response
/// </summary> /// </summary>
/// <param name="args"></param> /// <param name="args"></param>
/// <returns>true if no errors</returns> /// <returns>true if client/server connection was terminated (and disposed) </returns>
private async Task<bool> HandleHttpSessionResponse(SessionEventArgs args) private async Task<bool> HandleHttpSessionResponse(SessionEventArgs args)
{ {
try try
...@@ -40,28 +41,20 @@ namespace Titanium.Web.Proxy ...@@ -40,28 +41,20 @@ namespace Titanium.Web.Proxy
//If user requested call back then do it //If user requested call back then do it
if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked)
{ {
Delegate[] invocationList = BeforeResponse.GetInvocationList(); await BeforeResponse.InvokeParallelAsync(this, args);
Task[] handlerTasks = new Task[invocationList.Length];
for (int i = 0; i < invocationList.Length; i++)
{
handlerTasks[i] = ((Func<object, SessionEventArgs, Task>)invocationList[i])(this, args);
}
await Task.WhenAll(handlerTasks);
} }
if (args.ReRequest) if (args.ReRequest)
{ {
if(args.WebSession.ServerConnection != null) if (args.WebSession.ServerConnection != null)
{ {
args.WebSession.ServerConnection.Dispose(); args.WebSession.ServerConnection.Dispose();
ServerConnectionCount--; Interlocked.Decrement(ref ServerConnectionCountField);
} }
var connection = await GetServerConnection(args); var connection = await GetServerConnection(args);
var result = await HandleHttpSessionRequestInternal(null, args, true); var disposed = await HandleHttpSessionRequestInternal(null, args, true);
return result; return disposed;
} }
args.WebSession.Response.ResponseLocked = true; args.WebSession.Response.ResponseLocked = true;
...@@ -137,12 +130,10 @@ namespace Titanium.Web.Proxy ...@@ -137,12 +130,10 @@ namespace Titanium.Web.Proxy
Dispose(args.ProxyClient.ClientStream, args.ProxyClient.ClientStreamReader, Dispose(args.ProxyClient.ClientStream, args.ProxyClient.ClientStreamReader,
args.ProxyClient.ClientStreamWriter, args.WebSession.ServerConnection); args.ProxyClient.ClientStreamWriter, args.WebSession.ServerConnection);
return false; return true;
} }
args.Dispose(); return false;
return true;
} }
/// <summary> /// <summary>
...@@ -240,15 +231,17 @@ namespace Titanium.Web.Proxy ...@@ -240,15 +231,17 @@ namespace Titanium.Web.Proxy
StreamWriter clientStreamWriter, StreamWriter clientStreamWriter,
TcpConnection serverConnection) TcpConnection serverConnection)
{ {
ServerConnectionCount--;
clientStream?.Close(); clientStream?.Close();
clientStream?.Dispose(); clientStream?.Dispose();
clientStreamReader?.Dispose(); clientStreamReader?.Dispose();
clientStreamWriter?.Dispose(); clientStreamWriter?.Dispose();
serverConnection?.Dispose(); if (serverConnection != null)
{
serverConnection.Dispose();
Interlocked.Decrement(ref ServerConnectionCountField);
}
} }
} }
} }
...@@ -7,9 +7,9 @@ namespace Titanium.Web.Proxy.Shared ...@@ -7,9 +7,9 @@ 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 = { ';' };
internal static readonly byte[] NewLineBytes = Encoding.ASCII.GetBytes(NewLine); internal static readonly byte[] NewLineBytes = Encoding.ASCII.GetBytes(NewLine);
......
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" /> <Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" /> <Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" /> <Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Extensions\FuncExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" /> <Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Helpers\CustomBufferedStream.cs" /> <Compile Include="Helpers\CustomBufferedStream.cs" />
<Compile Include="Helpers\Network.cs" /> <Compile Include="Helpers\Network.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