diff --git a/Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs b/Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs index fe9f16c1c..d16dbfaef 100644 --- a/Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs +++ b/Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.IO; using System.Net; +using System.Net.Security; using System.Threading.Tasks; using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.Models; @@ -47,18 +47,18 @@ public void StartProxy() //Exclude Https addresses you don't want to proxy //Useful for clients that use certificate pinning //for example google.com and dropbox.com - ExcludedHttpsHostNameRegex = new List() { "dropbox.com" } + ExcludedHttpsHostNameRegex = new List { "dropbox.com" } //Include Https addresses you want to proxy (others will be excluded) //for example github.com - // IncludedHttpsHostNameRegex = new List() { "github.com" } + //IncludedHttpsHostNameRegex = new List { "github.com" } //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 //Optimizes performance by not creating a certificate for each https-enabled domain //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 @@ -150,7 +150,7 @@ public async Task OnRequest(object sender, SessionEventArgs e) //Modify response 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)) { @@ -189,7 +189,7 @@ public async Task OnResponse(object sender, SessionEventArgs e) public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) { //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; } diff --git a/Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs b/Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs index e2f3d0432..2b5ed878b 100644 --- a/Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs +++ b/Tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs b/Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs index c9f07f40c..1f851580e 100644 --- a/Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs +++ b/Tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs @@ -1,11 +1,12 @@ using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Diagnostics; using System.Net; +using System.Net.Http; +using System.Net.Security; using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.Models; -using System.Net.Http; -using System.Diagnostics; namespace Titanium.Web.Proxy.IntegrationTests { @@ -13,7 +14,6 @@ namespace Titanium.Web.Proxy.IntegrationTests public class SslTests { [TestMethod] - public void TestSsl() { //expand this to stress test to find @@ -103,7 +103,7 @@ public async Task OnResponse(object sender, SessionEventArgs e) public Task OnCertificateValidation(object sender, CertificateValidationEventArgs e) { //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; } diff --git a/Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs b/Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs index 651142271..5d37a623a 100644 --- a/Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs +++ b/Tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs @@ -1,8 +1,8 @@ using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Titanium.Web.Proxy.Network; -using System.Threading.Tasks; -using System.Collections.Generic; namespace Titanium.Web.Proxy.UnitTests { @@ -10,8 +10,7 @@ namespace Titanium.Web.Proxy.UnitTests public class CertificateManagerTests { private static readonly string[] hostNames - = new string[] { "facebook.com", "youtube.com", "google.com", - "bing.com", "yahoo.com"}; + = { "facebook.com", "youtube.com", "google.com", "bing.com", "yahoo.com"}; private readonly Random random = new Random(); diff --git a/Titanium.Web.Proxy.sln.DotSettings b/Titanium.Web.Proxy.sln.DotSettings index 1fc658854..2c8ffe8d7 100644 --- a/Titanium.Web.Proxy.sln.DotSettings +++ b/Titanium.Web.Proxy.sln.DotSettings @@ -1,8 +1,20 @@  True + False + 240 BC + CN + DN + EKU + KU + MTA + OID + OIDS <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> - <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> \ No newline at end of file + <Policy><Descriptor Staticness="Static, Instance" AccessRightKinds="Private" Description="Property (private)"><ElementKinds><Kind Name="PROPERTY" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></Policy> + True + True + True \ No newline at end of file diff --git a/Titanium.Web.Proxy/CertificateHandler.cs b/Titanium.Web.Proxy/CertificateHandler.cs index 134798937..b13ccfd82 100644 --- a/Titanium.Web.Proxy/CertificateHandler.cs +++ b/Titanium.Web.Proxy/CertificateHandler.cs @@ -1,8 +1,8 @@ using System; using System.Net.Security; using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Extensions; namespace Titanium.Web.Proxy { @@ -32,17 +32,8 @@ internal bool ValidateServerCertificate( SslPolicyErrors = sslPolicyErrors }; - - Delegate[] invocationList = ServerCertificateValidationCallback.GetInvocationList(); - Task[] handlerTasks = new Task[invocationList.Length]; - - for (int i = 0; i < invocationList.Length; i++) - { - handlerTasks[i] = ((Func) invocationList[i])(null, args); - } - - Task.WhenAll(handlerTasks).Wait(); - + //why is the sender null? + ServerCertificateValidationCallback.InvokeParallel(this, args); return args.IsValid; } @@ -108,17 +99,8 @@ internal X509Certificate SelectClientCertificate( ClientCertificate = clientCertificate }; - - Delegate[] invocationList = ClientCertificateSelectionCallback.GetInvocationList(); - Task[] handlerTasks = new Task[invocationList.Length]; - - for (int i = 0; i < invocationList.Length; i++) - { - handlerTasks[i] = ((Func) invocationList[i])(null, args); - } - - Task.WhenAll(handlerTasks).Wait(); - + //why is the sender null? + ClientCertificateSelectionCallback.InvokeParallel(this, args); return args.ClientCertificate; } diff --git a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 6af79368a..9f2824575 100644 --- a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net; using System.Text; -using Titanium.Web.Proxy.Exceptions; +using System.Threading.Tasks; 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.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.Network; namespace Titanium.Web.Proxy.EventArguments { @@ -56,7 +56,7 @@ public class SessionEventArgs : EventArgs, IDisposable /// /// Client End Point. /// - public IPEndPoint ClientEndPoint => (IPEndPoint) ProxyClient.TcpClient.Client.RemoteEndPoint; + public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; /// /// A web session corresponding to a single request/response sequence @@ -158,7 +158,7 @@ private async Task ReadResponseBody() await WebSession.ServerConnection.StreamReader.CopyBytesToStream(bufferSize, responseBodyStream, 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); } diff --git a/Titanium.Web.Proxy/Extensions/FuncExtensions.cs b/Titanium.Web.Proxy/Extensions/FuncExtensions.cs new file mode 100644 index 000000000..cfc1a2c78 --- /dev/null +++ b/Titanium.Web.Proxy/Extensions/FuncExtensions.cs @@ -0,0 +1,34 @@ +using System; +using System.Threading.Tasks; + +namespace Titanium.Web.Proxy.Extensions +{ + internal static class FuncExtensions + { + public static void InvokeParallel(this Func 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)invocationList[i])(sender, args); + } + + Task.WhenAll(handlerTasks).Wait(); + } + + public static async Task InvokeParallelAsync(this Func 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)invocationList[i])(sender, args); + } + + await Task.WhenAll(handlerTasks); + } + } +} diff --git a/Titanium.Web.Proxy/Extensions/StreamExtensions.cs b/Titanium.Web.Proxy/Extensions/StreamExtensions.cs index 4cf6be2bc..289e02290 100644 --- a/Titanium.Web.Proxy/Extensions/StreamExtensions.cs +++ b/Titanium.Web.Proxy/Extensions/StreamExtensions.cs @@ -136,7 +136,7 @@ internal static async Task WriteResponseBody(this CustomBinaryReader inStreamRea if (contentLength < bufferSize) { - bytesToRead = (int) contentLength; + bytesToRead = (int)contentLength; } var buffer = new byte[bufferSize]; @@ -153,8 +153,8 @@ internal static async Task WriteResponseBody(this CustomBinaryReader inStreamRea break; bytesRead = 0; - var remainingBytes = (contentLength - totalBytesRead); - bytesToRead = remainingBytes > (long) bufferSize ? bufferSize : (int) remainingBytes; + var remainingBytes = contentLength - totalBytesRead; + bytesToRead = remainingBytes > (long)bufferSize ? bufferSize : (int)remainingBytes; } } else diff --git a/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs b/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs index 32bce44f2..6f542c6ca 100644 --- a/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs +++ b/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs @@ -118,7 +118,7 @@ internal async Task ReadBytesAsync(long totalBytesToRead) var buffer = staticBuffer; if (totalBytesToRead < bufferSize) { - bytesToRead = (int) totalBytesToRead; + bytesToRead = (int)totalBytesToRead; buffer = new byte[bytesToRead]; } @@ -133,7 +133,7 @@ internal async Task ReadBytesAsync(long totalBytesToRead) break; var remainingBytes = totalBytesToRead - totalBytesRead; - bytesToRead = Math.Min(bufferSize, (int) remainingBytes); + bytesToRead = Math.Min(bufferSize, (int)remainingBytes); if (totalBytesRead + bytesToRead > buffer.Length) { diff --git a/Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs b/Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs index 78fa6db21..98281be68 100644 --- a/Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs +++ b/Titanium.Web.Proxy/Helpers/CustomBufferedStream.cs @@ -198,7 +198,7 @@ public override int EndRead(IAsyncResult asyncResult) { if (asyncResult is ReadAsyncResult) { - return ((ReadAsyncResult) asyncResult).ReadBytes; + return ((ReadAsyncResult)asyncResult).ReadBytes; } return baseStream.EndRead(asyncResult); diff --git a/Titanium.Web.Proxy/Helpers/SystemProxy.cs b/Titanium.Web.Proxy/Helpers/SystemProxy.cs index ec348319f..1edeb91b9 100644 --- a/Titanium.Web.Proxy/Helpers/SystemProxy.cs +++ b/Titanium.Web.Proxy/Helpers/SystemProxy.cs @@ -1,9 +1,9 @@ using System; -using System.Runtime.InteropServices; -using Microsoft.Win32; -using System.Text.RegularExpressions; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using Microsoft.Win32; // Helper classes for setting system proxy settings namespace Titanium.Web.Proxy.Helpers @@ -84,7 +84,7 @@ private void SetProxy(string hostname, int port, ProxyProtocolType protocolType) var exisitingContent = reg.GetValue("ProxyServer") as string; var existingSystemProxyValues = GetSystemProxyValues(exisitingContent); existingSystemProxyValues.RemoveAll(x => protocolType == ProxyProtocolType.Https ? x.IsHttps : !x.IsHttps); - existingSystemProxyValues.Add(new HttpSystemProxyValue() + existingSystemProxyValues.Add(new HttpSystemProxyValue { HostName = hostname, IsHttps = protocolType == ProxyProtocolType.Https, diff --git a/Titanium.Web.Proxy/Helpers/Tcp.cs b/Titanium.Web.Proxy/Helpers/Tcp.cs index e64da17b6..5cac82141 100644 --- a/Titanium.Web.Proxy/Helpers/Tcp.cs +++ b/Titanium.Web.Proxy/Helpers/Tcp.cs @@ -3,10 +3,9 @@ using System.IO; using System.Linq; using System.Net.NetworkInformation; -using System.Net.Security; using System.Runtime.InteropServices; -using System.Security.Authentication; using System.Text; +using System.Threading; using System.Threading.Tasks; using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Models; @@ -15,8 +14,6 @@ namespace Titanium.Web.Proxy.Helpers { - using System.Net; - internal enum IpVersion { Ipv4 = 1, @@ -232,7 +229,7 @@ internal static async Task SendRaw(ProxyServer server, finally { tcpConnection.Dispose(); - server.ServerConnectionCount--; + Interlocked.Decrement(ref server.ServerConnectionCountField); } } } diff --git a/Titanium.Web.Proxy/Http/HeaderParser.cs b/Titanium.Web.Proxy/Http/HeaderParser.cs index 27d8e051a..758d373eb 100644 --- a/Titanium.Web.Proxy/Http/HeaderParser.cs +++ b/Titanium.Web.Proxy/Http/HeaderParser.cs @@ -8,8 +8,8 @@ namespace Titanium.Web.Proxy.Http { internal static class HeaderParser { - internal static async Task ReadHeaders(CustomBinaryReader reader, - Dictionary> nonUniqueResponseHeaders, + internal static async Task ReadHeaders(CustomBinaryReader reader, + Dictionary> nonUniqueResponseHeaders, Dictionary headers) { string tmpLine; @@ -29,7 +29,7 @@ internal static async Task ReadHeaders(CustomBinaryReader reader, { var existing = headers[newHeader.Name]; - var nonUniqueHeaders = new List { existing, newHeader }; + var nonUniqueHeaders = new List {existing, newHeader}; nonUniqueResponseHeaders.Add(newHeader.Name, nonUniqueHeaders); headers.Remove(newHeader.Name); diff --git a/Titanium.Web.Proxy/Http/HttpWebClient.cs b/Titanium.Web.Proxy/Http/HttpWebClient.cs index 03bb2ae80..393d4b844 100644 --- a/Titanium.Web.Proxy/Http/HttpWebClient.cs +++ b/Titanium.Web.Proxy/Http/HttpWebClient.cs @@ -79,7 +79,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) var requestLines = new StringBuilder(); //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}"); } @@ -93,7 +93,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) { requestLines.AppendLine("Proxy-Connection: keep-alive"); 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 foreach (var headerItem in Request.RequestHeaders) diff --git a/Titanium.Web.Proxy/Http/Request.cs b/Titanium.Web.Proxy/Http/Request.cs index 949cd5570..0afdea85c 100644 --- a/Titanium.Web.Proxy/Http/Request.cs +++ b/Titanium.Web.Proxy/Http/Request.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Text; -using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Models; namespace Titanium.Web.Proxy.Http { @@ -241,7 +241,7 @@ public bool ExpectContinue /// request body as string /// internal string RequestBodyString { get; set; } - + internal bool RequestBodyRead { get; set; } internal bool RequestLocked { get; set; } diff --git a/Titanium.Web.Proxy/Http/Response.cs b/Titanium.Web.Proxy/Http/Response.cs index 08163a4b9..0393f4875 100644 --- a/Titanium.Web.Proxy/Http/Response.cs +++ b/Titanium.Web.Proxy/Http/Response.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Text; -using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Extensions; -using System; +using Titanium.Web.Proxy.Models; namespace Titanium.Web.Proxy.Http { diff --git a/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs b/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs index bf3a0753b..d2ad39f05 100644 --- a/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs +++ b/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs @@ -13,7 +13,7 @@ public class GenericResponse : Response /// public GenericResponse(HttpStatusCode status) { - ResponseStatusCode = ((int) status).ToString(); + ResponseStatusCode = ((int)status).ToString(); ResponseStatusDescription = status.ToString(); } diff --git a/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs b/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs index e7a8b7eb0..fba922e72 100644 --- a/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs +++ b/Titanium.Web.Proxy/Network/Certificate/BCCertificateMaker.cs @@ -110,7 +110,7 @@ private static X509Certificate2 GenerateCertificate(string hostName, // Corresponding private key 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) { diff --git a/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs b/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs index fed9f2ecb..1986c6588 100644 --- a/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs +++ b/Titanium.Web.Proxy/Network/Certificate/WinCertificateMaker.cs @@ -114,7 +114,7 @@ private X509Certificate2 MakeCertificate(bool isRoot, string subject, string ful typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, typeValue); typeValue[0] = 2; 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); if (!isRoot) @@ -243,7 +243,7 @@ private X509Certificate2 MakeCertificate(bool isRoot, string subject, string ful 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}; typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, x509Enrollment, typeValue); @@ -251,7 +251,7 @@ private X509Certificate2 MakeCertificate(bool isRoot, string subject, string ful 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); } catch (Exception) @@ -293,8 +293,7 @@ private X509Certificate2 MakeCertificateInternal(string sSubjectCN, bool isRoot, var graceTime = DateTime.Now.AddDays(GraceDays); var now = DateTime.Now; - rCert = !isRoot ? MakeCertificate(false, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), signingCert) : - MakeCertificate(true, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), null); + rCert = MakeCertificate(isRoot, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), isRoot ? null : signingCert); return rCert; } } diff --git a/Titanium.Web.Proxy/Network/CertificateManager.cs b/Titanium.Web.Proxy/Network/CertificateManager.cs index d3e7547de..a33ac22f5 100644 --- a/Titanium.Web.Proxy/Network/CertificateManager.cs +++ b/Titanium.Web.Proxy/Network/CertificateManager.cs @@ -1,12 +1,13 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; using System.Security.Cryptography.X509Certificates; 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.Network.Certificate; namespace Titanium.Web.Proxy.Network { @@ -51,7 +52,7 @@ internal CertificateEngine Engine if (certEngine == null) { certEngine = engine == CertificateEngine.BouncyCastle - ? (ICertificateMaker) new BCCertificateMaker() + ? (ICertificateMaker)new BCCertificateMaker() : new WinCertificateMaker(); } } @@ -132,12 +133,12 @@ private void ClearRootCertificate() private string GetRootCertificatePath() { - var assemblyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location; + var assemblyLocation = Assembly.GetExecutingAssembly().Location; // dynamically loaded assemblies returns string.Empty location if (assemblyLocation == string.Empty) { - assemblyLocation = System.Reflection.Assembly.GetEntryAssembly().Location; + assemblyLocation = Assembly.GetEntryAssembly().Location; } var path = Path.GetDirectoryName(assemblyLocation); diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 2bef02038..297718a0f 100644 --- a/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -1,13 +1,14 @@ using System; +using System.IO; +using System.Linq; +using System.Net.Security; using System.Net.Sockets; using System.Text; +using System.Threading; using System.Threading.Tasks; -using System.IO; -using System.Net.Security; +using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Models; -using System.Linq; -using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Shared; namespace Titanium.Web.Proxy.Network.Tcp @@ -17,7 +18,6 @@ namespace Titanium.Web.Proxy.Network.Tcp /// internal class TcpConnectionFactory { - /// /// Creates a TCP connection to server /// @@ -30,19 +30,19 @@ internal class TcpConnectionFactory /// /// /// - internal async Task CreateClient(ProxyServer server, + internal async Task CreateClient(ProxyServer server, string remoteHostName, int remotePort, Version httpVersion, - bool isHttps, + bool isHttps, ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy, Stream clientStream) { TcpClient client; 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 useHttpProxy = externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName && (externalHttpProxy.BypassForLocalhost && !isLocalhost); + bool useHttpsProxy = externalHttpsProxy != null && externalHttpsProxy.HostName != remoteHostName && externalHttpsProxy.BypassForLocalhost && !isLocalhost; + bool useHttpProxy = externalHttpProxy != null && externalHttpProxy.HostName != remoteHostName && externalHttpProxy.BypassForLocalhost && !isLocalhost; if (isHttps) { @@ -127,7 +127,7 @@ internal async Task CreateClient(ProxyServer server, client.LingerState = new LingerOption(true, 0); - server.ServerConnectionCount++; + Interlocked.Increment(ref server.ServerConnectionCountField); return new TcpConnection { diff --git a/Titanium.Web.Proxy/ProxyServer.cs b/Titanium.Web.Proxy/ProxyServer.cs index de3a0d928..2b25e1b2d 100644 --- a/Titanium.Web.Proxy/ProxyServer.cs +++ b/Titanium.Web.Proxy/ProxyServer.cs @@ -1,16 +1,17 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.Sockets; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; using System.Threading.Tasks; using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Network; -using System.Linq; -using System.Security.Authentication; using Titanium.Web.Proxy.Network.Tcp; -using System.Security.Cryptography.X509Certificates; namespace Titanium.Web.Proxy { @@ -35,6 +36,8 @@ public partial class ProxyServer : IDisposable private Action exceptionFunc; private bool trustRootCertificate; + private int clientConnectionCountField; + internal int ServerConnectionCountField; /// /// A object that creates tcp connection to server @@ -50,8 +53,7 @@ public partial class ProxyServer : IDisposable /// /// Set firefox to use default system proxy /// - private FireFoxProxySettingsManager firefoxProxySettingsManager - = new FireFoxProxySettingsManager(); + private FireFoxProxySettingsManager firefoxProxySettingsManager = new FireFoxProxySettingsManager(); #endif /// @@ -224,18 +226,18 @@ public Action ExceptionFunc /// List of supported Ssl versions /// public SslProtocols SupportedSslProtocols { get; set; } = SslProtocols.Tls - | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3; + | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Ssl3; /// /// Total number of active client connections /// - public int ClientConnectionCount { get; private set; } + public int ClientConnectionCount => clientConnectionCountField; /// /// Total number of active server connections /// - public int ServerConnectionCount { get; internal set; } + public int ServerConnectionCount => ServerConnectionCountField; /// /// Constructor @@ -596,7 +598,7 @@ private void OnAcceptConnection(IAsyncResult asyn) { Task.Run(async () => { - ClientConnectionCount++; + Interlocked.Increment(ref clientConnectionCountField); //This line is important! //contributors please don't remove it without discussion @@ -617,7 +619,7 @@ private void OnAcceptConnection(IAsyncResult asyn) } finally { - ClientConnectionCount--; + Interlocked.Decrement(ref clientConnectionCountField); tcpClient?.Close(); } }); diff --git a/Titanium.Web.Proxy/RequestHandler.cs b/Titanium.Web.Proxy/RequestHandler.cs index 59ed0c36f..f30543d1f 100644 --- a/Titanium.Web.Proxy/RequestHandler.cs +++ b/Titanium.Web.Proxy/RequestHandler.cs @@ -6,15 +6,15 @@ using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; -using Titanium.Web.Proxy.Exceptions; +using System.Threading.Tasks; using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Exceptions; +using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Helpers; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Http; -using System.Threading.Tasks; -using Titanium.Web.Proxy.Extensions; +using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Network.Tcp; +using Titanium.Web.Proxy.Shared; namespace Titanium.Web.Proxy { @@ -33,7 +33,7 @@ private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpCli clientStream.WriteTimeout = ConnectionTimeOutSeconds * 1000; var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); - var clientStreamWriter = new StreamWriter(clientStream) { NewLine = ProxyConstants.NewLine }; + var clientStreamWriter = new StreamWriter(clientStream) {NewLine = ProxyConstants.NewLine}; Uri httpRemoteUri; @@ -188,7 +188,7 @@ await sslStream.AuthenticateAsServerAsync(certificate, false, clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); - clientStreamWriter = new StreamWriter(clientStream) { NewLine = ProxyConstants.NewLine }; + clientStreamWriter = new StreamWriter(clientStream) {NewLine = ProxyConstants.NewLine}; //HTTPS server created - we can now decrypt the client's traffic } catch (Exception) @@ -205,7 +205,7 @@ await sslStream.AuthenticateAsServerAsync(certificate, false, else { clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); - clientStreamWriter = new StreamWriter(clientStream) { NewLine = ProxyConstants.NewLine }; + clientStreamWriter = new StreamWriter(clientStream) {NewLine = ProxyConstants.NewLine}; } //now read the request line @@ -392,8 +392,6 @@ await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417", /// /// /// - /// - /// /// private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName, @@ -408,18 +406,18 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St if (string.IsNullOrEmpty(httpCmd)) { Dispose(clientStream, - clientStreamReader, - clientStreamWriter, - connection); + clientStreamReader, + clientStreamWriter, + connection); break; } var args = new SessionEventArgs(BufferSize, HandleHttpSessionResponse) - { - ProxyClient = { TcpClient = client }, - WebSession = { ConnectHeaders = connectHeaders } - }; + { + ProxyClient = {TcpClient = client}, + WebSession = {ConnectHeaders = connectHeaders} + }; args.WebSession.ProcessId = new Lazy(() => { @@ -457,7 +455,8 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St //Read the request headers in to unique and non-unique header collections await HeaderParser.ReadHeaders(clientStreamReader, args.WebSession.Request.NonUniqueRequestHeaders, args.WebSession.Request.RequestHeaders); - var httpRemoteUri = new Uri(httpsHostName == null ? httpCmdSplit[1] + var httpRemoteUri = new Uri(httpsHostName == null + ? httpCmdSplit[1] : string.Concat("https://", args.WebSession.Request.Host ?? httpsHostName, httpCmdSplit[1])); args.WebSession.Request.RequestUri = httpRemoteUri; @@ -468,14 +467,14 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St args.ProxyClient.ClientStreamReader = clientStreamReader; args.ProxyClient.ClientStreamWriter = clientStreamWriter; - if (httpsHostName == null && - await CheckAuthorization(clientStreamWriter, + if (httpsHostName == null && + await CheckAuthorization(clientStreamWriter, args.WebSession.Request.RequestHeaders.Values) == false) { Dispose(clientStream, - clientStreamReader, - clientStreamWriter, - connection); + clientStreamReader, + clientStreamWriter, + connection); break; } @@ -486,15 +485,7 @@ await CheckAuthorization(clientStreamWriter, //If user requested interception do it if (BeforeRequest != null) { - var invocationList = BeforeRequest.GetInvocationList(); - var handlerTasks = new Task[invocationList.Length]; - - for (var i = 0; i < invocationList.Length; i++) - { - handlerTasks[i] = ((Func)invocationList[i])(this, args); - } - - await Task.WhenAll(handlerTasks); + await BeforeRequest.InvokeParallelAsync(this, args); } //if upgrading to websocket then relay the requet without reading the contents @@ -556,9 +547,9 @@ await TcpHelper.SendRaw(this, ExceptionFunc(new ProxyHttpException("Error occured whilst handling session request", e, args)); Dispose(clientStream, - clientStreamReader, - clientStreamWriter, - connection); + clientStreamReader, + clientStreamWriter, + connection); break; } } diff --git a/Titanium.Web.Proxy/ResponseHandler.cs b/Titanium.Web.Proxy/ResponseHandler.cs index 0fadbbee0..30dc49a47 100644 --- a/Titanium.Web.Proxy/ResponseHandler.cs +++ b/Titanium.Web.Proxy/ResponseHandler.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; using System.IO; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Compression; +using System.Threading; using System.Threading.Tasks; +using Titanium.Web.Proxy.Compression; +using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.Exceptions; using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Helpers; +using Titanium.Web.Proxy.Http; +using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Network.Tcp; namespace Titanium.Web.Proxy @@ -40,23 +41,15 @@ private async Task HandleHttpSessionResponse(SessionEventArgs args) //If user requested call back then do it if (BeforeResponse != null && !args.WebSession.Response.ResponseLocked) { - Delegate[] invocationList = BeforeResponse.GetInvocationList(); - Task[] handlerTasks = new Task[invocationList.Length]; - - for (int i = 0; i < invocationList.Length; i++) - { - handlerTasks[i] = ((Func)invocationList[i])(this, args); - } - - await Task.WhenAll(handlerTasks); + await BeforeResponse.InvokeParallelAsync(this, args); } if (args.ReRequest) { - if(args.WebSession.ServerConnection != null) + if (args.WebSession.ServerConnection != null) { args.WebSession.ServerConnection.Dispose(); - ServerConnectionCount--; + Interlocked.Decrement(ref ServerConnectionCountField); } var connection = await GetServerConnection(args); @@ -240,7 +233,7 @@ private void Dispose(Stream clientStream, StreamWriter clientStreamWriter, TcpConnection serverConnection) { - ServerConnectionCount--; + Interlocked.Decrement(ref ServerConnectionCountField); clientStream?.Close(); clientStream?.Dispose(); diff --git a/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj b/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj index 6b186297c..0e211df08 100644 --- a/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj +++ b/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj @@ -73,6 +73,7 @@ +