diff --git a/Titanium.Web.Proxy/CertificateHandler.cs b/Titanium.Web.Proxy/CertificateHandler.cs index 288bde770..ebc92dddc 100644 --- a/Titanium.Web.Proxy/CertificateHandler.cs +++ b/Titanium.Web.Proxy/CertificateHandler.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; @@ -26,11 +25,13 @@ internal bool ValidateServerCertificate( //if user callback is registered then do it if (ServerCertificateValidationCallback != null) { - var args = new CertificateValidationEventArgs(); + var args = new CertificateValidationEventArgs + { + Certificate = certificate, + Chain = chain, + SslPolicyErrors = sslPolicyErrors + }; - args.Certificate = certificate; - args.Chain = chain; - args.SslPolicyErrors = sslPolicyErrors; Delegate[] invocationList = ServerCertificateValidationCallback.GetInvocationList(); @@ -73,7 +74,6 @@ internal X509Certificate SelectClientCertificate( string[] acceptableIssuers) { X509Certificate clientCertificate = null; - var customSslStream = sender as SslStream; if (acceptableIssuers != null && acceptableIssuers.Length > 0 && @@ -100,13 +100,15 @@ internal X509Certificate SelectClientCertificate( //If user call back is registered if (ClientCertificateSelectionCallback != null) { - var args = new CertificateSelectionEventArgs(); + var args = new CertificateSelectionEventArgs + { + TargetHost = targetHost, + LocalCertificates = localCertificates, + RemoteCertificate = remoteCertificate, + AcceptableIssuers = acceptableIssuers, + ClientCertificate = clientCertificate + }; - args.TargetHost = targetHost; - args.LocalCertificates = localCertificates; - args.RemoteCertificate = remoteCertificate; - args.AcceptableIssuers = acceptableIssuers; - args.ClientCertificate = clientCertificate; Delegate[] invocationList = ClientCertificateSelectionCallback.GetInvocationList(); Task[] handlerTasks = new Task[invocationList.Length]; diff --git a/Titanium.Web.Proxy/Decompression/GZipDecompression.cs b/Titanium.Web.Proxy/Decompression/GZipDecompression.cs index c1e9dc274..1902d8291 100644 --- a/Titanium.Web.Proxy/Decompression/GZipDecompression.cs +++ b/Titanium.Web.Proxy/Decompression/GZipDecompression.cs @@ -1,7 +1,6 @@ using System.IO; using System.IO.Compression; using System.Threading.Tasks; -using Titanium.Web.Proxy.Shared; namespace Titanium.Web.Proxy.Decompression { diff --git a/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs b/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs index 1793ffa90..187e54e18 100644 --- a/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs +++ b/Titanium.Web.Proxy/EventArguments/CertificateSelectionEventArgs.cs @@ -8,12 +8,29 @@ namespace Titanium.Web.Proxy.EventArguments /// public class CertificateSelectionEventArgs : EventArgs { + /// + /// Sender object. + /// public object Sender { get; internal set; } + /// + /// Target host. + /// public string TargetHost { get; internal set; } + /// + /// Local certificates. + /// public X509CertificateCollection LocalCertificates { get; internal set; } + /// + /// Remote certificate. + /// public X509Certificate RemoteCertificate { get; internal set; } + /// + /// Acceptable issuers. + /// public string[] AcceptableIssuers { get; internal set; } - + /// + /// Client Certificate. + /// public X509Certificate ClientCertificate { get; set; } } diff --git a/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs b/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs index 3f6c013fd..d401308a7 100644 --- a/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs +++ b/Titanium.Web.Proxy/EventArguments/CertificateValidationEventArgs.cs @@ -7,17 +7,24 @@ namespace Titanium.Web.Proxy.EventArguments /// /// An argument passed on to the user for validating the server certificate during SSL authentication /// - public class CertificateValidationEventArgs : EventArgs, IDisposable + public class CertificateValidationEventArgs : EventArgs { + /// + /// Certificate + /// public X509Certificate Certificate { get; internal set; } + /// + /// Certificate chain + /// public X509Chain Chain { get; internal set; } + /// + /// SSL policy errors. + /// public SslPolicyErrors SslPolicyErrors { get; internal set; } + /// + /// is a valid certificate? + /// public bool IsValid { get; set; } - - public void Dispose() - { - - } } } diff --git a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs b/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs index 8b08f57c4..cb0c7d28f 100644 --- a/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs +++ b/Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs @@ -44,7 +44,9 @@ public class SessionEventArgs : EventArgs, IDisposable /// public Guid Id => WebSession.RequestId; - //Should we send a rerequest + /// + /// Should we send a rerequest + /// public bool ReRequest { get; @@ -56,7 +58,9 @@ public bool ReRequest /// public bool IsHttps => WebSession.Request.RequestUri.Scheme == Uri.UriSchemeHttps; - + /// + /// Client End Point. + /// public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; /// @@ -65,8 +69,14 @@ public bool ReRequest /// public HttpWebClient WebSession { get; set; } + /// + /// Are we using a custom upstream HTTP proxy? + /// public ExternalProxy CustomUpStreamHttpProxyUsed { get; set; } + /// + /// Are we using a custom upstream HTTPS proxy? + /// public ExternalProxy CustomUpStreamHttpsProxyUsed { get; set; } /// @@ -105,7 +115,7 @@ private async Task ReadRequestBody() //For chunked request we need to read data as they arrive, until we reach a chunk end symbol if (WebSession.Request.IsChunked) { - await this.ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(bufferSize, requestBodyStream); + await ProxyClient.ClientStreamReader.CopyBytesToStreamChunked(bufferSize, requestBodyStream); } else { @@ -113,7 +123,7 @@ private async Task ReadRequestBody() if (WebSession.Request.ContentLength > 0) { //If not chunked then its easy just read the amount of bytes mentioned in content length header of response - await this.ProxyClient.ClientStreamReader.CopyBytesToStream(bufferSize, requestBodyStream, + await ProxyClient.ClientStreamReader.CopyBytesToStream(bufferSize, requestBodyStream, WebSession.Request.ContentLength); } @@ -431,7 +441,7 @@ public async Task Ok(byte[] result, Dictionary headers)             await GenericResponse(html, null, status); } - ///  + /// /// Before request is made to server  /// Respond with the specified HTML string to client /// and the specified status @@ -485,12 +495,17 @@ public async Task GenericResponse(byte[] result, Dictionary WebSession.Request.CancelRequest = true; } + /// + /// Redirect to URL. + /// + /// + /// public async Task Redirect(string url) { var response = new RedirectResponse(); response.HttpVersion = WebSession.Request.HttpVersion; - response.ResponseHeaders.Add("Location", new Models.HttpHeader("Location", url)); + response.ResponseHeaders.Add("Location", new HttpHeader("Location", url)); response.ResponseBody = Encoding.ASCII.GetBytes(string.Empty); await Respond(response); diff --git a/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs b/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs index 79a74e60e..8a5fdf427 100644 --- a/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs +++ b/Titanium.Web.Proxy/Exceptions/BodyNotFoundException.cs @@ -1,5 +1,4 @@ -using System; - + namespace Titanium.Web.Proxy.Exceptions { /// @@ -7,6 +6,10 @@ namespace Titanium.Web.Proxy.Exceptions /// public class BodyNotFoundException : ProxyException { + /// + /// Constructor. + /// + /// public BodyNotFoundException(string message) : base(message) { diff --git a/Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs b/Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs index d355ce329..bb6ab960a 100644 --- a/Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs +++ b/Titanium.Web.Proxy/Extensions/ByteArrayExtensions.cs @@ -2,6 +2,9 @@ namespace Titanium.Web.Proxy.Extensions { + /// + /// Extension methods for Byte Arrays. + /// public static class ByteArrayExtensions { /// @@ -14,7 +17,7 @@ public static class ByteArrayExtensions /// public static T[] SubArray(this T[] data, int index, int length) { - T[] result = new T[length]; + var result = new T[length]; Array.Copy(data, index, result, 0, length); return result; } diff --git a/Titanium.Web.Proxy/Extensions/TcpExtensions.cs b/Titanium.Web.Proxy/Extensions/TcpExtensions.cs index c2bc9a2c7..a77852032 100644 --- a/Titanium.Web.Proxy/Extensions/TcpExtensions.cs +++ b/Titanium.Web.Proxy/Extensions/TcpExtensions.cs @@ -12,11 +12,11 @@ internal static class TcpExtensions internal static bool IsConnected(this Socket client) { // This is how you can determine whether a socket is still connected. - bool blockingState = client.Blocking; + var blockingState = client.Blocking; try { - byte[] tmp = new byte[1]; + var tmp = new byte[1]; client.Blocking = false; client.Send(tmp, 0, 0); @@ -25,14 +25,7 @@ internal static bool IsConnected(this Socket client) catch (SocketException e) { // 10035 == WSAEWOULDBLOCK - if (e.NativeErrorCode.Equals(10035)) - { - return true; - } - else - { - return false; - } + return e.NativeErrorCode.Equals(10035); } finally { diff --git a/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs b/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs index adb673b6b..a69a2be54 100644 --- a/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs +++ b/Titanium.Web.Proxy/Helpers/CustomBinaryReader.cs @@ -4,7 +4,6 @@ using System.Text; using System.Threading.Tasks; using Titanium.Web.Proxy.Extensions; -using Titanium.Web.Proxy.Shared; namespace Titanium.Web.Proxy.Helpers { @@ -16,15 +15,15 @@ namespace Titanium.Web.Proxy.Helpers /// internal class CustomBinaryReader : IDisposable { - private Stream stream; - private Encoding encoding; + private readonly Stream stream; + private readonly Encoding encoding; internal CustomBinaryReader(Stream stream) { this.stream = stream; //default to UTF-8 - this.encoding = Encoding.UTF8; + encoding = Encoding.UTF8; } internal Stream BaseStream => stream; @@ -40,7 +39,7 @@ internal async Task ReadLineAsync() var lastChar = default(char); var buffer = new byte[1]; - while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0) + while ((await stream.ReadAsync(buffer, 0, 1)) > 0) { //if new line if (lastChar == '\r' && buffer[0] == '\n') @@ -82,6 +81,7 @@ internal async Task> ReadAllLinesAsync() /// /// Read the specified number of raw bytes from the base stream /// + /// /// /// internal async Task ReadBytesAsync(int bufferSize, long totalBytesToRead) @@ -98,7 +98,7 @@ internal async Task ReadBytesAsync(int bufferSize, long totalBytesToRead using (var outStream = new MemoryStream()) { - while ((bytesRead += await this.stream.ReadAsync(buffer, 0, bytesToRead)) > 0) + while ((bytesRead += await stream.ReadAsync(buffer, 0, bytesToRead)) > 0) { await outStream.WriteAsync(buffer, 0, bytesRead); totalBytesRead += bytesRead; diff --git a/Titanium.Web.Proxy/Helpers/Firefox.cs b/Titanium.Web.Proxy/Helpers/Firefox.cs index 16077ffaf..3ab7fd36a 100644 --- a/Titanium.Web.Proxy/Helpers/Firefox.cs +++ b/Titanium.Web.Proxy/Helpers/Firefox.cs @@ -8,7 +8,10 @@ namespace Titanium.Web.Proxy.Helpers /// public class FireFoxProxySettingsManager { - public void AddFirefox() + /// + /// Add Firefox settings. + /// + public void AddFirefox() { try { @@ -16,21 +19,17 @@ public void AddFirefox() new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Mozilla\\Firefox\\Profiles\\").GetDirectories("*.default"); var myFfPrefFile = myProfileDirectory[0].FullName + "\\prefs.js"; - if (File.Exists(myFfPrefFile)) - { - // We have a pref file so let''s make sure it has the proxy setting - var myReader = new StreamReader(myFfPrefFile); - var myPrefContents = myReader.ReadToEnd(); - myReader.Close(); - if (myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);")) - { - // Add the proxy enable line and write it back to the file - myPrefContents = myPrefContents.Replace("user_pref(\"network.proxy.type\", 0);", ""); + if (!File.Exists(myFfPrefFile)) return; + // We have a pref file so let''s make sure it has the proxy setting + var myReader = new StreamReader(myFfPrefFile); + var myPrefContents = myReader.ReadToEnd(); + myReader.Close(); + if (!myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);")) return; + // Add the proxy enable line and write it back to the file + myPrefContents = myPrefContents.Replace("user_pref(\"network.proxy.type\", 0);", ""); - File.Delete(myFfPrefFile); - File.WriteAllText(myFfPrefFile, myPrefContents); - } - } + File.Delete(myFfPrefFile); + File.WriteAllText(myFfPrefFile, myPrefContents); } catch (Exception) { @@ -38,7 +37,10 @@ public void AddFirefox() } } - public void RemoveFirefox() + /// + /// Remove firefox settings. + /// + public void RemoveFirefox() { try { @@ -46,20 +48,18 @@ public void RemoveFirefox() new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Mozilla\\Firefox\\Profiles\\").GetDirectories("*.default"); var myFfPrefFile = myProfileDirectory[0].FullName + "\\prefs.js"; - if (File.Exists(myFfPrefFile)) + if (!File.Exists(myFfPrefFile)) return; + // We have a pref file so let''s make sure it has the proxy setting + var myReader = new StreamReader(myFfPrefFile); + var myPrefContents = myReader.ReadToEnd(); + myReader.Close(); + if (!myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);")) { - // We have a pref file so let''s make sure it has the proxy setting - var myReader = new StreamReader(myFfPrefFile); - var myPrefContents = myReader.ReadToEnd(); - myReader.Close(); - if (!myPrefContents.Contains("user_pref(\"network.proxy.type\", 0);")) - { - // Add the proxy enable line and write it back to the file - myPrefContents = myPrefContents + "\n\r" + "user_pref(\"network.proxy.type\", 0);"; + // Add the proxy enable line and write it back to the file + myPrefContents = myPrefContents + "\n\r" + "user_pref(\"network.proxy.type\", 0);"; - File.Delete(myFfPrefFile); - File.WriteAllText(myFfPrefFile, myPrefContents); - } + File.Delete(myFfPrefFile); + File.WriteAllText(myFfPrefFile, myPrefContents); } } catch (Exception) diff --git a/Titanium.Web.Proxy/Helpers/Network.cs b/Titanium.Web.Proxy/Helpers/Network.cs index fc0d49081..27d81c9d8 100644 --- a/Titanium.Web.Proxy/Helpers/Network.cs +++ b/Titanium.Web.Proxy/Helpers/Network.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Linq; using System.Net; -using System.Text; -using System.Threading.Tasks; namespace Titanium.Web.Proxy.Helpers { @@ -33,28 +29,14 @@ internal static int GetProcessIdFromPort(int port, bool ipV6Enabled) /// Adapated from below link /// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost /// - /// /// internal static bool IsLocalIpAddress(IPAddress address) { - try - { - // get local IP addresses - IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName()); - - // test if any host IP equals to any local IP or to localhost - - // is localhost - if (IPAddress.IsLoopback(address)) return true; - // is local address - foreach (IPAddress localIP in localIPs) - { - if (address.Equals(localIP)) return true; - } - - } - catch { } - return false; + // get local IP addresses + var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); + // test if any host IP equals to any local IP or to localhost + return IPAddress.IsLoopback(address) || localIPs.Contains(address); } } } diff --git a/Titanium.Web.Proxy/Helpers/SystemProxy.cs b/Titanium.Web.Proxy/Helpers/SystemProxy.cs index 24206a645..ce95577f8 100644 --- a/Titanium.Web.Proxy/Helpers/SystemProxy.cs +++ b/Titanium.Web.Proxy/Helpers/SystemProxy.cs @@ -4,11 +4,8 @@ using System.Text.RegularExpressions; using System.Collections.Generic; using System.Linq; -using System.Net.Sockets; -/// -/// Helper classes for setting system proxy settings -/// +// Helper classes for setting system proxy settings namespace Titanium.Web.Proxy.Helpers { internal enum ProxyProtocolType diff --git a/Titanium.Web.Proxy/Helpers/Tcp.cs b/Titanium.Web.Proxy/Helpers/Tcp.cs index 9a30e4624..08ba30dfe 100644 --- a/Titanium.Web.Proxy/Helpers/Tcp.cs +++ b/Titanium.Web.Proxy/Helpers/Tcp.cs @@ -140,6 +140,7 @@ internal static TcpTable GetExtendedTcpTable(IpVersion ipVersion) /// /// /// + /// /// internal static async Task SendRaw(int bufferSize, int connectionTimeOutSeconds, string remoteHostName, int remotePort, string httpCmd, Version httpVersion, Dictionary requestHeaders, diff --git a/Titanium.Web.Proxy/Http/HttpWebClient.cs b/Titanium.Web.Proxy/Http/HttpWebClient.cs index 83a87a528..5f0ef6251 100644 --- a/Titanium.Web.Proxy/Http/HttpWebClient.cs +++ b/Titanium.Web.Proxy/Http/HttpWebClient.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.IO; using System.Text; using System.Threading.Tasks; using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network.Tcp; using Titanium.Web.Proxy.Shared; @@ -15,17 +13,26 @@ namespace Titanium.Web.Proxy.Http /// public class HttpWebClient { - - /// /// Connection to server /// internal TcpConnection ServerConnection { get; set; } - public Guid RequestId { get; private set; } - + /// + /// Request ID. + /// + public Guid RequestId { get; } + /// + /// Headers passed with Connect. + /// public List ConnectHeaders { get; set; } + /// + /// Web Request. + /// public Request Request { get; set; } + /// + /// Web Response. + /// public Response Response { get; set; } /// @@ -37,15 +44,14 @@ public class HttpWebClient /// /// Is Https? /// - public bool IsHttps => this.Request.RequestUri.Scheme == Uri.UriSchemeHttps; + public bool IsHttps => Request.RequestUri.Scheme == Uri.UriSchemeHttps; internal HttpWebClient() { - this.RequestId = Guid.NewGuid(); - - this.Request = new Request(); - this.Response = new Response(); + RequestId = Guid.NewGuid(); + Request = new Request(); + Response = new Response(); } /// @@ -65,18 +71,18 @@ internal void SetConnection(TcpConnection connection) /// internal async Task SendRequest(bool enable100ContinueBehaviour) { - Stream stream = ServerConnection.Stream; + var stream = ServerConnection.Stream; - StringBuilder requestLines = new StringBuilder(); + var requestLines = new StringBuilder(); //prepare the request & headers - if ((ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false) || (ServerConnection.UpStreamHttpsProxy != null && ServerConnection.IsHttps == true)) + if ((ServerConnection.UpStreamHttpProxy != null && ServerConnection.IsHttps == false) || (ServerConnection.UpStreamHttpsProxy != null && ServerConnection.IsHttps)) { - requestLines.AppendLine(string.Join(" ", this.Request.Method, this.Request.RequestUri.AbsoluteUri, $"HTTP/{this.Request.HttpVersion.Major}.{this.Request.HttpVersion.Minor}")); + requestLines.AppendLine(string.Join(" ", Request.Method, Request.RequestUri.AbsoluteUri, $"HTTP/{Request.HttpVersion.Major}.{Request.HttpVersion.Minor}")); } else { - requestLines.AppendLine(string.Join(" ", this.Request.Method, this.Request.RequestUri.PathAndQuery, $"HTTP/{this.Request.HttpVersion.Major}.{this.Request.HttpVersion.Minor}")); + requestLines.AppendLine(string.Join(" ", Request.Method, Request.RequestUri.PathAndQuery, $"HTTP/{Request.HttpVersion.Major}.{Request.HttpVersion.Minor}")); } //Send Authentication to Upstream proxy if needed @@ -86,7 +92,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) requestLines.AppendLine("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ServerConnection.UpStreamHttpProxy.UserName + ":" + ServerConnection.UpStreamHttpProxy.Password))); } //write request headers - foreach (var headerItem in this.Request.RequestHeaders) + foreach (var headerItem in Request.RequestHeaders) { var header = headerItem.Value; if (headerItem.Key != "Proxy-Authorization") @@ -96,7 +102,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) } //write non unique request headers - foreach (var headerItem in this.Request.NonUniqueRequestHeaders) + foreach (var headerItem in Request.NonUniqueRequestHeaders) { var headers = headerItem.Value; foreach (var header in headers) @@ -110,15 +116,15 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) requestLines.AppendLine(); - string request = requestLines.ToString(); - byte[] requestBytes = Encoding.ASCII.GetBytes(request); + var request = requestLines.ToString(); + var requestBytes = Encoding.ASCII.GetBytes(request); await stream.WriteAsync(requestBytes, 0, requestBytes.Length); await stream.FlushAsync(); if (enable100ContinueBehaviour) { - if (this.Request.ExpectContinue) + if (Request.ExpectContinue) { var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3); var responseStatusCode = httpResult[1].Trim(); @@ -128,13 +134,13 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) if (responseStatusCode.Equals("100") && responseStatusDescription.ToLower().Equals("continue")) { - this.Request.Is100Continue = true; + Request.Is100Continue = true; await ServerConnection.StreamReader.ReadLineAsync(); } else if (responseStatusCode.Equals("417") && responseStatusDescription.ToLower().Equals("expectation failed")) { - this.Request.ExpectationFailed = true; + Request.ExpectationFailed = true; await ServerConnection.StreamReader.ReadLineAsync(); } } @@ -148,7 +154,7 @@ internal async Task SendRequest(bool enable100ContinueBehaviour) internal async Task ReceiveResponse() { //return if this is already read - if (this.Response.ResponseStatusCode != null) return; + if (Response.ResponseStatusCode != null) return; var httpResult = (await ServerConnection.StreamReader.ReadLineAsync()).Split(ProxyConstants.SpaceSplit, 3); @@ -161,33 +167,33 @@ internal async Task ReceiveResponse() var httpVersion = httpResult[0].Trim().ToLower(); var version = new Version(1, 1); - if (httpVersion == "http/1.0") + if (0 == string.CompareOrdinal(httpVersion, "http/1.0")) { version = new Version(1, 0); } - this.Response.HttpVersion = version; - this.Response.ResponseStatusCode = httpResult[1].Trim(); - this.Response.ResponseStatusDescription = httpResult[2].Trim(); + Response.HttpVersion = version; + Response.ResponseStatusCode = httpResult[1].Trim(); + Response.ResponseStatusDescription = httpResult[2].Trim(); //For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request - if (this.Response.ResponseStatusCode.Equals("100") - && this.Response.ResponseStatusDescription.ToLower().Equals("continue")) + if (Response.ResponseStatusCode.Equals("100") + && Response.ResponseStatusDescription.ToLower().Equals("continue")) { //Read the next line after 100-continue - this.Response.Is100Continue = true; - this.Response.ResponseStatusCode = null; + Response.Is100Continue = true; + Response.ResponseStatusCode = null; await ServerConnection.StreamReader.ReadLineAsync(); //now receive response await ReceiveResponse(); return; } - else if (this.Response.ResponseStatusCode.Equals("417") - && this.Response.ResponseStatusDescription.ToLower().Equals("expectation failed")) + else if (Response.ResponseStatusCode.Equals("417") + && Response.ResponseStatusDescription.ToLower().Equals("expectation failed")) { //read next line after expectation failed response - this.Response.ExpectationFailed = true; - this.Response.ResponseStatusCode = null; + Response.ExpectationFailed = true; + Response.ResponseStatusCode = null; await ServerConnection.StreamReader.ReadLineAsync(); //now receive response await ReceiveResponse(); diff --git a/Titanium.Web.Proxy/Http/Request.cs b/Titanium.Web.Proxy/Http/Request.cs index 6fb51940a..9b7094d00 100644 --- a/Titanium.Web.Proxy/Http/Request.cs +++ b/Titanium.Web.Proxy/Http/Request.cs @@ -34,12 +34,7 @@ internal string Host get { var hasHeader = RequestHeaders.ContainsKey("host"); - if (hasHeader) - { - return RequestHeaders["host"].Value; - } - - return null; + return hasHeader ? RequestHeaders["host"].Value : null; } set { @@ -154,11 +149,11 @@ public string ContentType if (hasHeader) { var header = RequestHeaders["content-type"]; - header.Value = value.ToString(); + header.Value = value; } else { - RequestHeaders.Add("content-type", new HttpHeader("content-type", value.ToString())); + RequestHeaders.Add("content-type", new HttpHeader("content-type", value)); } } @@ -219,14 +214,10 @@ public bool ExpectContinue { var hasHeader = RequestHeaders.ContainsKey("expect"); - if (hasHeader) - { - var header = RequestHeaders["expect"]; - - return header.Value.Equals("100-continue"); - } + if (!hasHeader) return false; + var header = RequestHeaders["expect"]; - return false; + return header.Value.Equals("100-continue"); } } @@ -275,13 +266,7 @@ internal bool UpgradeToWebSocket var header = RequestHeaders["upgrade"]; - if (header.Value.ToLower() == "websocket") - { - return true; - } - - return false; - + return header.Value.ToLower() == "websocket"; } } @@ -305,6 +290,9 @@ internal bool UpgradeToWebSocket /// public bool ExpectationFailed { get; internal set; } + /// + /// Constructor. + /// public Request() { RequestHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/Titanium.Web.Proxy/Http/Response.cs b/Titanium.Web.Proxy/Http/Response.cs index 04bf3e182..415ec59aa 100644 --- a/Titanium.Web.Proxy/Http/Response.cs +++ b/Titanium.Web.Proxy/Http/Response.cs @@ -12,7 +12,13 @@ namespace Titanium.Web.Proxy.Http /// public class Response { + /// + /// Response Status Code. + /// public string ResponseStatusCode { get; set; } + /// + /// Response Status description. + /// public string ResponseStatusDescription { get; set; } internal Encoding Encoding => this.GetResponseCharacterEncoding(); @@ -26,14 +32,10 @@ internal string ContentEncoding { var hasHeader = ResponseHeaders.ContainsKey("content-encoding"); - if (hasHeader) - { - var header = ResponseHeaders["content-encoding"]; + if (!hasHeader) return null; + var header = ResponseHeaders["content-encoding"]; - return header.Value.Trim(); - } - - return null; + return header.Value.Trim(); } } @@ -229,10 +231,13 @@ internal bool IsChunked /// public bool ExpectationFailed { get; internal set; } + /// + /// Constructor. + /// public Response() { - this.ResponseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - this.NonUniqueResponseHeaders = new Dictionary>(StringComparer.OrdinalIgnoreCase); + ResponseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + NonUniqueResponseHeaders = new Dictionary>(StringComparer.OrdinalIgnoreCase); } } diff --git a/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs b/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs index 15d06583d..c67cf6c4f 100644 --- a/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs +++ b/Titanium.Web.Proxy/Http/Responses/GenericResponse.cs @@ -7,16 +7,25 @@     ///      public class GenericResponse : Response     { +        /// +        /// Constructor. +        /// +        ///         public GenericResponse(HttpStatusCode status)         {             ResponseStatusCode = ((int)status).ToString();             ResponseStatusDescription = status.ToString();          } +        /// +        /// Constructor. +        /// +        /// +        ///         public GenericResponse(string statusCode, string statusDescription)         {             ResponseStatusCode = statusCode; -            ResponseStatusDescription = statusCode; +            ResponseStatusDescription = statusDescription;         }     } } diff --git a/Titanium.Web.Proxy/Http/Responses/OkResponse.cs b/Titanium.Web.Proxy/Http/Responses/OkResponse.cs index 7343c196d..c1f7e8261 100644 --- a/Titanium.Web.Proxy/Http/Responses/OkResponse.cs +++ b/Titanium.Web.Proxy/Http/Responses/OkResponse.cs @@ -5,6 +5,9 @@ /// public sealed class OkResponse : Response { + /// + /// Constructor. + /// public OkResponse() { ResponseStatusCode = "200"; diff --git a/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs b/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs index 4340faec8..fad100b83 100644 --- a/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs +++ b/Titanium.Web.Proxy/Http/Responses/RedirectResponse.cs @@ -5,6 +5,9 @@ /// public sealed class RedirectResponse : Response { + /// + /// Constructor. + /// public RedirectResponse() { ResponseStatusCode = "302"; diff --git a/Titanium.Web.Proxy/Models/EndPoint.cs b/Titanium.Web.Proxy/Models/EndPoint.cs index bbeb3ff3e..d331d6510 100644 --- a/Titanium.Web.Proxy/Models/EndPoint.cs +++ b/Titanium.Web.Proxy/Models/EndPoint.cs @@ -10,20 +10,38 @@ namespace Titanium.Web.Proxy.Models /// public abstract class ProxyEndPoint { - public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) + /// + /// Constructor. + /// + /// + /// + /// + protected ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) { this.IpAddress = IpAddress; this.Port = Port; this.EnableSsl = EnableSsl; } + /// + /// Ip Address. + /// public IPAddress IpAddress { get; internal set; } + /// + /// Port. + /// public int Port { get; internal set; } + /// + /// Enable SSL? + /// public bool EnableSsl { get; internal set; } - public bool IpV6Enabled => IpAddress == IPAddress.IPv6Any - || IpAddress == IPAddress.IPv6Loopback - || IpAddress == IPAddress.IPv6None; + /// + /// Is IPv6 enabled? + /// + public bool IpV6Enabled => Equals(IpAddress, IPAddress.IPv6Any) + || Equals(IpAddress, IPAddress.IPv6Loopback) + || Equals(IpAddress, IPAddress.IPv6None); internal TcpListener listener { get; set; } } @@ -37,14 +55,26 @@ public class ExplicitProxyEndPoint : ProxyEndPoint internal bool IsSystemHttpProxy { get; set; } internal bool IsSystemHttpsProxy { get; set; } - public List ExcludedHttpsHostNameRegex { get; set; } + /// + /// List of host names to exclude using Regular Expressions. + /// + public List ExcludedHttpsHostNameRegex { get; set; } + /// + /// Generic certificate to use for SSL decryption. + /// public X509Certificate2 GenericCertificate { get; set; } + /// + /// Constructor. + /// + /// + /// + /// public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) : base(IpAddress, Port, EnableSsl) { - + } } @@ -54,13 +84,19 @@ public ExplicitProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) /// public class TransparentProxyEndPoint : ProxyEndPoint { - //Name of the Certificate need to be sent (same as the hostname we want to proxy) - //This is valid only when UseServerNameIndication is set to false - public string GenericCertificateName { get; set; } - - // public bool UseServerNameIndication { get; set; } + /// + /// Name of the Certificate need to be sent (same as the hostname we want to proxy) + /// This is valid only when UseServerNameIndication is set to false + /// + public string GenericCertificateName { get; set; } + /// + /// Constructor. + /// + /// + /// + /// public TransparentProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) : base(IpAddress, Port, EnableSsl) { diff --git a/Titanium.Web.Proxy/Models/ExternalProxy.cs b/Titanium.Web.Proxy/Models/ExternalProxy.cs index 5bf48314a..d7e6828fa 100644 --- a/Titanium.Web.Proxy/Models/ExternalProxy.cs +++ b/Titanium.Web.Proxy/Models/ExternalProxy.cs @@ -13,10 +13,16 @@ public class ExternalProxy private string userName; private string password; + /// + /// Use default windows credentials? + /// public bool UseDefaultCredentials { get; set; } + /// + /// Username. + /// public string UserName { - get { return UseDefaultCredentials ? DefaultCredentials.Value.UserName : userName; } + get => UseDefaultCredentials ? DefaultCredentials.Value.UserName : userName; set { userName = value; @@ -28,9 +34,12 @@ public string UserName { } } + /// + /// Password. + /// public string Password { - get { return UseDefaultCredentials ? DefaultCredentials.Value.Password : password; } + get => UseDefaultCredentials ? DefaultCredentials.Value.Password : password; set { password = value; @@ -42,7 +51,13 @@ public string Password } } + /// + /// Host name. + /// public string HostName { get; set; } + /// + /// Port. + /// public int Port { get; set; } } } diff --git a/Titanium.Web.Proxy/Models/HttpHeader.cs b/Titanium.Web.Proxy/Models/HttpHeader.cs index fb2cc2dd4..7a6896fbb 100644 --- a/Titanium.Web.Proxy/Models/HttpHeader.cs +++ b/Titanium.Web.Proxy/Models/HttpHeader.cs @@ -7,6 +7,12 @@ namespace Titanium.Web.Proxy.Models /// public class HttpHeader { + /// + /// Constructor. + /// + /// + /// + /// public HttpHeader(string name, string value) { if (string.IsNullOrEmpty(name)) @@ -18,7 +24,13 @@ public HttpHeader(string name, string value) Value = value.Trim(); } + /// + /// Header Name. + /// public string Name { get; set; } + /// + /// Header Value. + /// public string Value { get; set; } /// @@ -27,7 +39,7 @@ public HttpHeader(string name, string value) /// public override string ToString() { - return string.Format("{0}: {1}", Name, Value); + return $"{Name}: {Value}"; } } } \ No newline at end of file diff --git a/Titanium.Web.Proxy/Network/CertificateMaker.cs b/Titanium.Web.Proxy/Network/CertificateMaker.cs index 00965dade..e7d1ecf6a 100644 --- a/Titanium.Web.Proxy/Network/CertificateMaker.cs +++ b/Titanium.Web.Proxy/Network/CertificateMaker.cs @@ -6,187 +6,197 @@ namespace Titanium.Web.Proxy.Network { + /// + /// Certificate Maker - uses MakeCert + /// public class CertificateMaker { - private Type typeX500DN; + private readonly Type typeX500DN; - private Type typeX509PrivateKey; + private readonly Type typeX509PrivateKey; - private Type typeOID; + private readonly Type typeOID; - private Type typeOIDS; + private readonly Type typeOIDS; - private Type typeKUExt; + private readonly Type typeKUExt; - private Type typeEKUExt; + private readonly Type typeEKUExt; - private Type typeRequestCert; + private readonly Type typeRequestCert; - private Type typeX509Extensions; + private readonly Type typeX509Extensions; - private Type typeBasicConstraints; + private readonly Type typeBasicConstraints; - private Type typeSignerCertificate; + private readonly Type typeSignerCertificate; - private Type typeX509Enrollment; + private readonly Type typeX509Enrollment; - private Type typeAlternativeName; + //private Type typeAlternativeName; - private Type typeAlternativeNames; + //private Type typeAlternativeNames; - private Type typeAlternativeNamesExt; + //private Type typeAlternativeNamesExt; - private string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0"; + private readonly string sProviderName = "Microsoft Enhanced Cryptographic Provider v1.0"; private object _SharedPrivateKey; + /// + /// Constructor. + /// public CertificateMaker() { - this.typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true); - this.typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true); - this.typeOID = Type.GetTypeFromProgID("X509Enrollment.CObjectId", true); - this.typeOIDS = Type.GetTypeFromProgID("X509Enrollment.CObjectIds.1", true); - this.typeEKUExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionEnhancedKeyUsage"); - this.typeKUExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionKeyUsage"); - this.typeRequestCert = Type.GetTypeFromProgID("X509Enrollment.CX509CertificateRequestCertificate"); - this.typeX509Extensions = Type.GetTypeFromProgID("X509Enrollment.CX509Extensions"); - this.typeBasicConstraints = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionBasicConstraints"); - this.typeSignerCertificate = Type.GetTypeFromProgID("X509Enrollment.CSignerCertificate"); - this.typeX509Enrollment = Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment"); - this.typeAlternativeName = Type.GetTypeFromProgID("X509Enrollment.CAlternativeName"); - this.typeAlternativeNames = Type.GetTypeFromProgID("X509Enrollment.CAlternativeNames"); - this.typeAlternativeNamesExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionAlternativeNames"); + typeX500DN = Type.GetTypeFromProgID("X509Enrollment.CX500DistinguishedName", true); + typeX509PrivateKey = Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey", true); + typeOID = Type.GetTypeFromProgID("X509Enrollment.CObjectId", true); + typeOIDS = Type.GetTypeFromProgID("X509Enrollment.CObjectIds.1", true); + typeEKUExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionEnhancedKeyUsage"); + typeKUExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionKeyUsage"); + typeRequestCert = Type.GetTypeFromProgID("X509Enrollment.CX509CertificateRequestCertificate"); + typeX509Extensions = Type.GetTypeFromProgID("X509Enrollment.CX509Extensions"); + typeBasicConstraints = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionBasicConstraints"); + typeSignerCertificate = Type.GetTypeFromProgID("X509Enrollment.CSignerCertificate"); + typeX509Enrollment = Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment"); + //this.typeAlternativeName = Type.GetTypeFromProgID("X509Enrollment.CAlternativeName"); + //this.typeAlternativeNames = Type.GetTypeFromProgID("X509Enrollment.CAlternativeNames"); + //this.typeAlternativeNamesExt = Type.GetTypeFromProgID("X509Enrollment.CX509ExtensionAlternativeNames"); } + /// + /// Make certificate. + /// + /// + /// + /// + /// public X509Certificate2 MakeCertificate(string sSubjectCN, bool isRoot,X509Certificate2 signingCert=null) { - return this.MakeCertificateInternal(sSubjectCN, isRoot, true, signingCert); + return MakeCertificateInternal(sSubjectCN, isRoot, true, signingCert); } - private X509Certificate2 MakeCertificate(bool IsRoot, string SubjectCN, string FullSubject, int PrivateKeyLength, string HashAlg, DateTime ValidFrom, DateTime ValidTo, X509Certificate2 SigningCertificate) + private X509Certificate2 MakeCertificate(bool IsRoot, string FullSubject, int PrivateKeyLength, string HashAlg, DateTime ValidFrom, DateTime ValidTo, X509Certificate2 SigningCertificate) { - X509Certificate2 cert; if (IsRoot != (null == SigningCertificate)) { - throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", "oSigningCertificate"); + throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(IsRoot)); } - object x500DN = Activator.CreateInstance(this.typeX500DN); - object[] subject = new object[] { FullSubject, 0 }; - this.typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500DN, subject); - object x500DN2 = Activator.CreateInstance(this.typeX500DN); + var x500DN = Activator.CreateInstance(typeX500DN); + var subject = new object[] { FullSubject, 0 }; + typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500DN, subject); + var x500DN2 = Activator.CreateInstance(typeX500DN); if (!IsRoot) { subject[0] = SigningCertificate.Subject; } - this.typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500DN2, subject); + typeX500DN.InvokeMember("Encode", BindingFlags.InvokeMethod, null, x500DN2, subject); object sharedPrivateKey = null; if (!IsRoot) { - sharedPrivateKey = this._SharedPrivateKey; + sharedPrivateKey = _SharedPrivateKey; } if (sharedPrivateKey == null) { - sharedPrivateKey = Activator.CreateInstance(this.typeX509PrivateKey); - subject = new object[] { this.sProviderName }; - this.typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); + sharedPrivateKey = Activator.CreateInstance(typeX509PrivateKey); + subject = new object[] { sProviderName }; + typeX509PrivateKey.InvokeMember("ProviderName", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); subject[0] = 2; - this.typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); + typeX509PrivateKey.InvokeMember("ExportPolicy", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); subject = new object[] { (IsRoot ? 2 : 1) }; - this.typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); + typeX509PrivateKey.InvokeMember("KeySpec", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); if (!IsRoot) { subject = new object[] { 176 }; - this.typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); + typeX509PrivateKey.InvokeMember("KeyUsage", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); } subject[0] = PrivateKeyLength; - this.typeX509PrivateKey.InvokeMember("Length", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); - this.typeX509PrivateKey.InvokeMember("Create", BindingFlags.InvokeMethod, null, sharedPrivateKey, null); + typeX509PrivateKey.InvokeMember("Length", BindingFlags.PutDispProperty, null, sharedPrivateKey, subject); + typeX509PrivateKey.InvokeMember("Create", BindingFlags.InvokeMethod, null, sharedPrivateKey, null); if (!IsRoot) { - this._SharedPrivateKey = sharedPrivateKey; + _SharedPrivateKey = sharedPrivateKey; } } subject = new object[1]; - object obj3 = Activator.CreateInstance(this.typeOID); + var obj3 = Activator.CreateInstance(typeOID); subject[0] = "1.3.6.1.5.5.7.3.1"; - this.typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, obj3, subject); - object obj4 = Activator.CreateInstance(this.typeOIDS); + typeOID.InvokeMember("InitializeFromValue", BindingFlags.InvokeMethod, null, obj3, subject); + var obj4 = Activator.CreateInstance(typeOIDS); subject[0] = obj3; - this.typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj4, subject); - object obj5 = Activator.CreateInstance(this.typeEKUExt); + typeOIDS.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj4, subject); + var obj5 = Activator.CreateInstance(typeEKUExt); subject[0] = obj4; - this.typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj5, subject); - object obj6 = Activator.CreateInstance(this.typeRequestCert); - subject = new object[] { 1, sharedPrivateKey, string.Empty }; - this.typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, obj6, subject); - subject = new object[] { x500DN }; - this.typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, obj6, subject); + typeEKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj5, subject); + var obj6 = Activator.CreateInstance(typeRequestCert); + subject = new[] { 1, sharedPrivateKey, string.Empty }; + typeRequestCert.InvokeMember("InitializeFromPrivateKey", BindingFlags.InvokeMethod, null, obj6, subject); + subject = new[] { x500DN }; + typeRequestCert.InvokeMember("Subject", BindingFlags.PutDispProperty, null, obj6, subject); subject[0] = x500DN; - this.typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, obj6, subject); + typeRequestCert.InvokeMember("Issuer", BindingFlags.PutDispProperty, null, obj6, subject); subject[0] = ValidFrom; - this.typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, obj6, subject); + typeRequestCert.InvokeMember("NotBefore", BindingFlags.PutDispProperty, null, obj6, subject); subject[0] = ValidTo; - this.typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, obj6, subject); - object obj7 = Activator.CreateInstance(this.typeKUExt); + typeRequestCert.InvokeMember("NotAfter", BindingFlags.PutDispProperty, null, obj6, subject); + var obj7 = Activator.CreateInstance(typeKUExt); subject[0] = 176; - this.typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj7, subject); - object obj8 = this.typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, obj6, null); + typeKUExt.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj7, subject); + var obj8 = typeRequestCert.InvokeMember("X509Extensions", BindingFlags.GetProperty, null, obj6, null); subject = new object[1]; if (!IsRoot) { subject[0] = obj7; - this.typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); + typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); } subject[0] = obj5; - this.typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); + typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); if (!IsRoot) { - object obj12 = Activator.CreateInstance(this.typeSignerCertificate); + var obj12 = Activator.CreateInstance(typeSignerCertificate); subject = new object[] { 0, 0, 12, SigningCertificate.Thumbprint }; - this.typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, obj12, subject); - subject = new object[] { obj12 }; - this.typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, obj6, subject); + typeSignerCertificate.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, obj12, subject); + subject = new[] { obj12 }; + typeRequestCert.InvokeMember("SignerCertificate", BindingFlags.PutDispProperty, null, obj6, subject); } else { - object obj13 = Activator.CreateInstance(this.typeBasicConstraints); + var obj13 = Activator.CreateInstance(typeBasicConstraints); subject = new object[] { "true", "0" }; - this.typeBasicConstraints.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj13, subject); - subject = new object[] { obj13 }; - this.typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); + typeBasicConstraints.InvokeMember("InitializeEncode", BindingFlags.InvokeMethod, null, obj13, subject); + subject = new[] { obj13 }; + typeX509Extensions.InvokeMember("Add", BindingFlags.InvokeMethod, null, obj8, subject); } - object obj14 = Activator.CreateInstance(this.typeOID); + var obj14 = Activator.CreateInstance(typeOID); subject = new object[] { 1, 0, 0, HashAlg }; - this.typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, obj14, subject); - subject = new object[] { obj14 }; - this.typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, obj6, subject); - this.typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, obj6, null); - object obj15 = Activator.CreateInstance(this.typeX509Enrollment); + typeOID.InvokeMember("InitializeFromAlgorithmName", BindingFlags.InvokeMethod, null, obj14, subject); + subject = new[] { obj14 }; + typeRequestCert.InvokeMember("HashAlgorithm", BindingFlags.PutDispProperty, null, obj6, subject); + typeRequestCert.InvokeMember("Encode", BindingFlags.InvokeMethod, null, obj6, null); + var obj15 = Activator.CreateInstance(typeX509Enrollment); subject[0] = obj6; - this.typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, obj15, subject); + typeX509Enrollment.InvokeMember("InitializeFromRequest", BindingFlags.InvokeMethod, null, obj15, subject); if (IsRoot) { subject[0] = "DO_NOT_TRUST_TitaniumProxy-CE"; - this.typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, obj15, subject); + typeX509Enrollment.InvokeMember("CertificateFriendlyName", BindingFlags.PutDispProperty, null, obj15, subject); } subject[0] = 0; - object obj16 = this.typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, obj15, subject); - subject = new object[] { 2, obj16, 0, string.Empty }; - this.typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, obj15, subject); + var obj16 = typeX509Enrollment.InvokeMember("CreateRequest", BindingFlags.InvokeMethod, null, obj15, subject); + subject = new[] { 2, obj16, 0, string.Empty }; + typeX509Enrollment.InvokeMember("InstallResponse", BindingFlags.InvokeMethod, null, obj15, subject); subject = new object[] { null, 0, 1 }; - string empty = string.Empty; try { - empty = (string)this.typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, obj15, subject); + var empty = (string)typeX509Enrollment.InvokeMember("CreatePFX", BindingFlags.InvokeMethod, null, obj15, subject); return new X509Certificate2(Convert.FromBase64String(empty), string.Empty, X509KeyStorageFlags.Exportable); } - catch (Exception exception1) + catch (Exception) { - Exception exception = exception1; - cert = null; + // ignored } - return cert; + return null; } private X509Certificate2 MakeCertificateInternal(string sSubjectCN, bool isRoot, bool switchToMTAIfNeeded,X509Certificate2 signingCert=null) @@ -194,39 +204,26 @@ private X509Certificate2 MakeCertificateInternal(string sSubjectCN, bool isRoot, X509Certificate2 rCert=null; if (switchToMTAIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA) { - ManualResetEvent manualResetEvent = new ManualResetEvent(false); - ThreadPool.QueueUserWorkItem((object o) => + var manualResetEvent = new ManualResetEvent(false); + ThreadPool.QueueUserWorkItem(o => { - rCert = this.MakeCertificateInternal(sSubjectCN, isRoot, false,signingCert); + rCert = MakeCertificateInternal(sSubjectCN, isRoot, false,signingCert); manualResetEvent.Set(); }); manualResetEvent.WaitOne(); manualResetEvent.Close(); return rCert; } - string fullSubject = string.Format("CN={0}{1}", sSubjectCN, "");//Subject - string HashAlgo = "SHA256"; //Sig Algo - int GraceDays = -366; //Grace Days - int ValidDays = 1825; //ValiDays - int keyLength = 2048; //KeyLength - - DateTime graceTime = DateTime.Now.AddDays((double)GraceDays); - DateTime now = DateTime.Now; - try - { - if (!isRoot) - { - rCert = this.MakeCertificate(false, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays((double)ValidDays), signingCert); - } - else - { - rCert = this.MakeCertificate(true, sSubjectCN, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays((double)ValidDays), null); - } - } - catch (Exception e) - { - throw e; - } + var fullSubject = $"CN={sSubjectCN}";//Subject + var HashAlgo = "SHA256"; //Sig Algo + var GraceDays = -366; //Grace Days + var ValidDays = 1825; //ValiDays + var keyLength = 2048; //KeyLength + + var graceTime = DateTime.Now.AddDays(GraceDays); + var now = DateTime.Now; + rCert = !isRoot ? MakeCertificate(false, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), signingCert) : + MakeCertificate(true, fullSubject, keyLength, HashAlgo, graceTime, now.AddDays(ValidDays), null); return rCert; } } diff --git a/Titanium.Web.Proxy/Network/CertificateManager.cs b/Titanium.Web.Proxy/Network/CertificateManager.cs index 2b6e7babd..f7a45cb55 100644 --- a/Titanium.Web.Proxy/Network/CertificateManager.cs +++ b/Titanium.Web.Proxy/Network/CertificateManager.cs @@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Network /// internal class CertificateManager : IDisposable { - private CertificateMaker certEngine = null; + private readonly CertificateMaker certEngine; private bool clearCertificates { get; set; } /// @@ -21,10 +21,10 @@ internal class CertificateManager : IDisposable /// private readonly IDictionary certificateCache; - private Action exceptionFunc; + private readonly Action exceptionFunc; - internal string Issuer { get; private set; } - internal string RootCertificateName { get; private set; } + internal string Issuer { get; } + internal string RootCertificateName { get; } internal X509Certificate2 rootCertificate { get; set; } @@ -35,29 +35,28 @@ internal CertificateManager(string issuer, string rootCertificateName, Action(); } internal X509Certificate2 GetRootCertificate() { - var fileName = Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "rootCert.pfx"); + var path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + if (null == path) throw new NullReferenceException(); + var fileName = Path.Combine(path, "rootCert.pfx"); - if (File.Exists(fileName)) + if (!File.Exists(fileName)) return null; + try { - try - { - return new X509Certificate2(fileName, string.Empty, X509KeyStorageFlags.Exportable); - - } - catch (Exception e) - { - exceptionFunc(e); - return null; - } + return new X509Certificate2(fileName, string.Empty, X509KeyStorageFlags.Exportable); + + } + catch (Exception e) + { + exceptionFunc(e); + return null; } - return null; } /// /// Attempts to create a RootCertificate @@ -75,7 +74,7 @@ internal bool CreateTrustedRootCertificate() { rootCertificate = CreateCertificate(RootCertificateName, true); } - catch(Exception e) + catch (Exception e) { exceptionFunc(e); } @@ -83,38 +82,36 @@ internal bool CreateTrustedRootCertificate() { try { - var fileName = Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "rootCert.pfx"); + var path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + if (null == path) throw new NullReferenceException(); + var fileName = Path.Combine(path, "rootCert.pfx"); File.WriteAllBytes(fileName, rootCertificate.Export(X509ContentType.Pkcs12)); } - catch(Exception e) + catch (Exception e) { exceptionFunc(e); } } return rootCertificate != null; } + /// /// Create an SSL certificate /// - /// /// /// /// internal virtual X509Certificate2 CreateCertificate(string certificateName, bool isRootCertificate) { - try + + if (certificateCache.ContainsKey(certificateName)) { - if (certificateCache.ContainsKey(certificateName)) - { - var cached = certificateCache[certificateName]; - cached.LastAccess = DateTime.Now; - return cached.Certificate; - } + var cached = certificateCache[certificateName]; + cached.LastAccess = DateTime.Now; + return cached.Certificate; } - catch - { - } + X509Certificate2 certificate = null; lock (string.Intern(certificateName)) { @@ -124,7 +121,7 @@ internal virtual X509Certificate2 CreateCertificate(string certificateName, bool { certificate = certEngine.MakeCertificate(certificateName, isRootCertificate, rootCertificate); } - catch(Exception e) + catch (Exception e) { exceptionFunc(e); } @@ -166,27 +163,20 @@ internal async void ClearIdleCertificates(int certificateCacheTimeOutMinutes) clearCertificates = true; while (clearCertificates) { + var cutOff = DateTime.Now.AddMinutes(-1 * certificateCacheTimeOutMinutes); - try - { - var cutOff = DateTime.Now.AddMinutes(-1 * certificateCacheTimeOutMinutes); + var outdated = certificateCache + .Where(x => x.Value.LastAccess < cutOff) + .ToList(); - var outdated = certificateCache - .Where(x => x.Value.LastAccess < cutOff) - .ToList(); - - foreach (var cache in outdated) - certificateCache.Remove(cache.Key); - } - finally - { - } + foreach (var cache in outdated) + certificateCache.Remove(cache.Key); //after a minute come back to check for outdated certificates in cache await Task.Delay(1000 * 60); } } - + internal bool TrustRootCertificate() { if (rootCertificate == null) @@ -213,7 +203,7 @@ internal bool TrustRootCertificate() } return true; } - catch + catch { return false; } diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs b/Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs index 300a69530..5186c70a2 100644 --- a/Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs +++ b/Titanium.Web.Proxy/Network/Tcp/TcpConnection.cs @@ -47,6 +47,9 @@ internal TcpConnection() LastAccess = DateTime.Now; } + /// + /// Dispose. + /// public void Dispose() { Stream.Close(); diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs b/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs index 123ec9d78..33d717154 100644 --- a/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs +++ b/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs @@ -19,14 +19,12 @@ namespace Titanium.Web.Proxy.Network.Tcp /// internal class TcpConnectionFactory { - /// /// Creates a TCP connection to server /// /// /// /// - /// /// /// /// @@ -69,7 +67,7 @@ internal async Task CreateClient(int bufferSize, int connectionTi if (!string.IsNullOrEmpty(externalHttpsProxy.UserName) && externalHttpsProxy.Password != null) { await writer.WriteLineAsync("Proxy-Connection: keep-alive"); - await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password))); + await writer.WriteLineAsync("Proxy-Authorization" + ": Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(externalHttpsProxy.UserName + ":" + externalHttpsProxy.Password))); } await writer.WriteLineAsync(); await writer.FlushAsync(); @@ -81,7 +79,7 @@ internal async Task CreateClient(int bufferSize, int connectionTi var result = await reader.ReadLineAsync(); - if (!new string[] { "200 OK", "connection established" }.Any(s => result.ToLower().Contains(s.ToLower()))) + if (!new[] { "200 OK", "connection established" }.Any(s => result.ToLower().Contains(s.ToLower()))) { throw new Exception("Upstream proxy failed to create a secure tunnel"); } diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpRow.cs b/Titanium.Web.Proxy/Network/Tcp/TcpRow.cs index 55fe279d8..4fc1a49dd 100644 --- a/Titanium.Web.Proxy/Network/Tcp/TcpRow.cs +++ b/Titanium.Web.Proxy/Network/Tcp/TcpRow.cs @@ -29,16 +29,16 @@ public TcpRow(NativeMethods.TcpRow tcpRow) /// /// Gets the local end point. /// - public IPEndPoint LocalEndPoint { get; private set; } + public IPEndPoint LocalEndPoint { get; } /// /// Gets the remote end point. /// - public IPEndPoint RemoteEndPoint { get; private set; } + public IPEndPoint RemoteEndPoint { get; } /// /// Gets the process identifier. /// - public int ProcessId { get; private set; } + public int ProcessId { get; } } } \ No newline at end of file diff --git a/Titanium.Web.Proxy/Network/Tcp/TcpTable.cs b/Titanium.Web.Proxy/Network/Tcp/TcpTable.cs index 984674e15..92b6c9f21 100644 --- a/Titanium.Web.Proxy/Network/Tcp/TcpTable.cs +++ b/Titanium.Web.Proxy/Network/Tcp/TcpTable.cs @@ -6,7 +6,9 @@ namespace Titanium.Web.Proxy.Network.Tcp /// /// Represents collection of TcpRows /// - /// + /// + /// System.Collections.Generic.IEnumerable{Proxy.Tcp.TcpRow} + /// internal class TcpTable : IEnumerable { private readonly IEnumerable tcpRows; diff --git a/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs b/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs index abc3fde1a..b71b69fdf 100644 --- a/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs +++ b/Titanium.Web.Proxy/ProxyAuthorizationHandler.cs @@ -24,58 +24,78 @@ private async Task CheckAuthorization(StreamWriter clientStreamWriter, IEn try { - if (!httpHeaders.Where(t => t.Name == "Proxy-Authorization").Any()) + if (httpHeaders.All(t => t.Name != "Proxy-Authorization")) { await WriteResponseStatus(new Version(1, 1), "407", "Proxy Authentication Required", clientStreamWriter); - var response = new Response(); - response.ResponseHeaders = new Dictionary(); - response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"")); - response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close")); + var response = new Response + { + ResponseHeaders = new Dictionary + { + { + "Proxy-Authenticate", + new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"") + }, + {"Proxy-Connection", new HttpHeader("Proxy-Connection", "close")} + } + }; await WriteResponseHeaders(clientStreamWriter, response); await clientStreamWriter.WriteLineAsync(); return false; } - else + var header = httpHeaders.FirstOrDefault(t => t.Name == "Proxy-Authorization"); + if (null == header) throw new NullReferenceException(); + var headerValue = header.Value.Trim(); + if (!headerValue.ToLower().StartsWith("basic")) { - var headerValue = httpHeaders.Where(t => t.Name == "Proxy-Authorization").FirstOrDefault().Value.Trim(); - if (!headerValue.ToLower().StartsWith("basic")) + //Return not authorized + await WriteResponseStatus(new Version(1, 1), "407", + "Proxy Authentication Invalid", clientStreamWriter); + var response = new Response { - //Return not authorized - await WriteResponseStatus(new Version(1, 1), "407", - "Proxy Authentication Invalid", clientStreamWriter); - var response = new Response(); - response.ResponseHeaders = new Dictionary(); - response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"")); - response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close")); - await WriteResponseHeaders(clientStreamWriter, response); + ResponseHeaders = new Dictionary + { + { + "Proxy-Authenticate", + new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"") + }, + {"Proxy-Connection", new HttpHeader("Proxy-Connection", "close")} + } + }; + await WriteResponseHeaders(clientStreamWriter, response); - await clientStreamWriter.WriteLineAsync(); - return false; - } - headerValue = headerValue.Substring(5).Trim(); + await clientStreamWriter.WriteLineAsync(); + return false; + } + headerValue = headerValue.Substring(5).Trim(); - var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValue)); - if (decoded.Contains(":") == false) + var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValue)); + if (decoded.Contains(":") == false) + { + //Return not authorized + await WriteResponseStatus(new Version(1, 1), "407", + "Proxy Authentication Invalid", clientStreamWriter); + var response = new Response { - //Return not authorized - await WriteResponseStatus(new Version(1, 1), "407", - "Proxy Authentication Invalid", clientStreamWriter); - var response = new Response(); - response.ResponseHeaders = new Dictionary(); - response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"")); - response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close")); - await WriteResponseHeaders(clientStreamWriter, response); + ResponseHeaders = new Dictionary + { + { + "Proxy-Authenticate", + new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"") + }, + {"Proxy-Connection", new HttpHeader("Proxy-Connection", "close")} + } + }; + await WriteResponseHeaders(clientStreamWriter, response); - await clientStreamWriter.WriteLineAsync(); - return false; - } - var username = decoded.Substring(0, decoded.IndexOf(':')); - var password = decoded.Substring(decoded.IndexOf(':') + 1); - return await AuthenticateUserFunc(username, password).ConfigureAwait(false); + await clientStreamWriter.WriteLineAsync(); + return false; } + var username = decoded.Substring(0, decoded.IndexOf(':')); + var password = decoded.Substring(decoded.IndexOf(':') + 1); + return await AuthenticateUserFunc(username, password).ConfigureAwait(false); } catch (Exception e) { @@ -83,10 +103,14 @@ await WriteResponseStatus(new Version(1, 1), "407", //Return not authorized await WriteResponseStatus(new Version(1, 1), "407", "Proxy Authentication Invalid", clientStreamWriter); - var response = new Response(); - response.ResponseHeaders = new Dictionary(); - response.ResponseHeaders.Add("Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"")); - response.ResponseHeaders.Add("Proxy-Connection", new HttpHeader("Proxy-Connection", "close")); + var response = new Response + { + ResponseHeaders = new Dictionary + { + {"Proxy-Authenticate", new HttpHeader("Proxy-Authenticate", "Basic realm=\"TitaniumProxy\"")}, + {"Proxy-Connection", new HttpHeader("Proxy-Connection", "close")} + } + }; await WriteResponseHeaders(clientStreamWriter, response); await clientStreamWriter.WriteLineAsync(); diff --git a/Titanium.Web.Proxy/ProxyServer.cs b/Titanium.Web.Proxy/ProxyServer.cs index 36fcf2ad2..d096779fb 100644 --- a/Titanium.Web.Proxy/ProxyServer.cs +++ b/Titanium.Web.Proxy/ProxyServer.cs @@ -47,14 +47,16 @@ public partial class ProxyServer : IDisposable /// /// A object that creates tcp connection to server /// - private TcpConnectionFactory tcpConnectionFactory { get; set; } + private TcpConnectionFactory tcpConnectionFactory { get; } /// /// Manage system proxy settings /// - private SystemProxyManager systemProxySettingsManager { get; set; } + private SystemProxyManager systemProxySettingsManager { get; } +#if !DEBUG private FireFoxProxySettingsManager firefoxProxySettingsManager { get; set; } +#endif /// /// Buffer size used throughout this proxy @@ -138,14 +140,8 @@ public partial class ProxyServer : IDisposable /// public Action ExceptionFunc { - get - { - return exceptionFunc ?? defaultExceptionFunc.Value; - } - set - { - exceptionFunc = value; - } + get => exceptionFunc ?? defaultExceptionFunc.Value; + set => exceptionFunc = value; } /// @@ -172,6 +168,7 @@ public Func> GetCustomUpStreamHttpProxyFun /// /// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests /// return the ExternalProxy object with valid credentials + /// public Func> GetCustomUpStreamHttpsProxyFunc { get; @@ -203,6 +200,11 @@ public Func> GetCustomUpStreamHttpsProxyFu /// public ProxyServer() : this(null, null) { } + /// + /// Constructor. + /// + /// Name of root certificate. + /// Name of root certificate issuer. public ProxyServer(string rootCertificateName, string rootCertificateIssuerName) { RootCertificateName = rootCertificateName; @@ -214,8 +216,9 @@ public ProxyServer(string rootCertificateName, string rootCertificateIssuerName) ProxyEndPoints = new List(); tcpConnectionFactory = new TcpConnectionFactory(); systemProxySettingsManager = new SystemProxyManager(); - firefoxProxySettingsManager = new FireFoxProxySettingsManager(); - +#if !DEBUG + new FireFoxProxySettingsManager(); +#endif RootCertificateName = RootCertificateName ?? "Titanium Root Certificate Authority"; RootCertificateIssuerName = RootCertificateIssuerName ?? "Titanium"; } @@ -277,7 +280,7 @@ public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) #if !DEBUG firefoxProxySettingsManager.AddFirefox(); #endif - Console.WriteLine("Set endpoint at Ip {1} and port: {2} as System HTTP Proxy", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); + Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System HTTP Proxy", endPoint.IpAddress, endPoint.Port); } @@ -313,7 +316,7 @@ public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) #if !DEBUG firefoxProxySettingsManager.AddFirefox(); #endif - Console.WriteLine("Set endpoint at Ip {1} and port: {2} as System HTTPS Proxy", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); + Console.WriteLine("Set endpoint at Ip {0} and port: {1} as System HTTPS Proxy", endPoint.IpAddress, endPoint.Port); } /// @@ -461,6 +464,7 @@ private void QuitListen(ProxyEndPoint endPoint) /// private void ValidateEndPointAsSystemProxy(ExplicitProxyEndPoint endPoint) { + if (endPoint == null) throw new ArgumentNullException(nameof(endPoint)); if (ProxyEndPoints.Contains(endPoint) == false) { throw new Exception("Cannot set endPoints not added to proxy as system proxy"); @@ -542,6 +546,9 @@ private void OnAcceptConnection(IAsyncResult asyn) endPoint.listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint); } + /// + /// Dispose Proxy. + /// public void Dispose() { if (proxyRunning) @@ -551,5 +558,45 @@ public void Dispose() certificateCacheManager?.Dispose(); } + + /// + /// Invocator for BeforeRequest event. + /// + /// + /// + protected virtual void OnBeforeRequest(object sender, SessionEventArgs e) + { + BeforeRequest?.Invoke(sender, e); + } + + /// + /// Invocator for BeforeResponse event. + /// + /// + /// + /// + protected virtual void OnBeforeResponse(object sender, SessionEventArgs e) + { + BeforeResponse?.Invoke(sender, e); + } + /// + /// Invocator for ServerCertificateValidationCallback event. + /// + /// + /// + protected virtual void OnServerCertificateValidationCallback(object sender, CertificateValidationEventArgs e) + { + ServerCertificateValidationCallback?.Invoke(sender, e); + } + + /// + /// Invocator for ClientCertifcateSelectionCallback event. + /// + /// + /// + protected virtual void OnClientCertificateSelectionCallback(object sender, CertificateSelectionEventArgs e) + { + ClientCertificateSelectionCallback?.Invoke(sender, e); + } } } \ No newline at end of file diff --git a/Titanium.Web.Proxy/RequestHandler.cs b/Titanium.Web.Proxy/RequestHandler.cs index 7d2148182..d6d333295 100644 --- a/Titanium.Web.Proxy/RequestHandler.cs +++ b/Titanium.Web.Proxy/RequestHandler.cs @@ -11,7 +11,6 @@ using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Models; -using System.Security.Cryptography.X509Certificates; using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Http; using System.Threading.Tasks; @@ -58,29 +57,21 @@ private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpCli //Find the request Verb var httpVerb = httpCmdSplit[0]; - if (httpVerb.ToUpper() == "CONNECT") - { - httpRemoteUri = new Uri("http://" + httpCmdSplit[1]); - } - else - { - httpRemoteUri = new Uri(httpCmdSplit[1]); - } + httpRemoteUri = httpVerb.ToUpper() == "CONNECT" ? new Uri("http://" + httpCmdSplit[1]) : new Uri(httpCmdSplit[1]); //parse the HTTP version - Version version = new Version(1, 1); + var version = new Version(1, 1); if (httpCmdSplit.Length == 3) { - string httpVersion = httpCmdSplit[2].Trim(); + var httpVersion = httpCmdSplit[2].Trim(); - if (httpVersion == "http/1.0") + if (0 == string.CompareOrdinal(httpVersion, "http/1.0")) { version = new Version(1, 0); } } //filter out excluded host names - var excluded = endPoint.ExcludedHttpsHostNameRegex != null ? - endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)) : false; + var excluded = endPoint.ExcludedHttpsHostNameRegex != null && endPoint.ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)); List connectRequestHeaders = null; @@ -89,7 +80,7 @@ private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpCli if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80) { httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); - string tmpLine = null; + string tmpLine; connectRequestHeaders = new List(); while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync())) { @@ -114,15 +105,7 @@ private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpCli sslStream = new SslStream(clientStream, true); - X509Certificate2 certificate; - if (endPoint.GenericCertificate != null) - { - certificate = endPoint.GenericCertificate; - } - else - { - certificate = certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false); - } + var certificate = endPoint.GenericCertificate ?? certificateCacheManager.CreateCertificate(httpRemoteUri.Host, false); //Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, @@ -136,10 +119,7 @@ await sslStream.AuthenticateAsServerAsync(certificate, false, } catch { - if (sslStream != null) - { - sslStream.Dispose(); - } + sslStream?.Dispose(); Dispose(clientStream, clientStreamReader, clientStreamWriter, null); return; @@ -160,8 +140,8 @@ await sslStream.AuthenticateAsServerAsync(certificate, false, await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, httpCmd, version, null, false, SupportedSslProtocols, - new RemoteCertificateValidationCallback(ValidateServerCertificate), - new LocalCertificateSelectionCallback(SelectClientCertificate), + ValidateServerCertificate, + SelectClientCertificate, clientStream, tcpConnectionFactory, UpStreamEndPoint); Dispose(clientStream, clientStreamReader, clientStreamWriter, null); @@ -169,7 +149,7 @@ await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Hos } //Now create the request await HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, - httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequestHeaders, null, null); + httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.Host : null, endPoint, connectRequestHeaders); } catch (Exception) { @@ -189,14 +169,13 @@ private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcp CustomBinaryReader clientStreamReader = null; StreamWriter clientStreamWriter = null; - X509Certificate2 certificate = null; if (endPoint.EnableSsl) { var sslStream = new SslStream(clientStream, true); //implement in future once SNI supported by SSL stream, for now use the same certificate - certificate = certificateCacheManager.CreateCertificate(endPoint.GenericCertificateName, false); + var certificate = certificateCacheManager.CreateCertificate(endPoint.GenericCertificateName, false); try { @@ -259,8 +238,8 @@ private async Task HandleHttpSessionRequestInternal(TcpConnection connection, Se connection = await tcpConnectionFactory.CreateClient(BUFFER_SIZE, ConnectionTimeOutSeconds, args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, args.WebSession.Request.HttpVersion, args.IsHttps, SupportedSslProtocols, - new RemoteCertificateValidationCallback(ValidateServerCertificate), - new LocalCertificateSelectionCallback(SelectClientCertificate), + ValidateServerCertificate, + SelectClientCertificate, customUpStreamHttpProxy ?? UpStreamHttpProxy, customUpStreamHttpsProxy ?? UpStreamHttpsProxy, args.ProxyClient.ClientStream, UpStreamEndPoint); } @@ -367,9 +346,14 @@ await WriteResponseStatus(args.WebSession.Response.HttpVersion, "417", /// /// /// + /// + /// + /// + /// /// private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, - CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName, ProxyEndPoint endPoint, List connectHeaders, ExternalProxy customUpStreamHttpProxy = null, ExternalProxy customUpStreamHttpsProxy = null) + CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string httpsHostName, + ProxyEndPoint endPoint, List connectHeaders, ExternalProxy customUpStreamHttpProxy = null, ExternalProxy customUpStreamHttpsProxy = null) { TcpConnection connection = null; @@ -383,9 +367,12 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St break; } - var args = new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse); - args.ProxyClient.TcpClient = client; - args.WebSession.ConnectHeaders = connectHeaders; + var args = + new SessionEventArgs(BUFFER_SIZE, HandleHttpSessionResponse) + { + ProxyClient = {TcpClient = client}, + WebSession = {ConnectHeaders = connectHeaders} + }; args.WebSession.ProcessId = new Lazy(() => { @@ -409,12 +396,12 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St var httpMethod = httpCmdSplit[0]; //find the request HTTP version - Version httpVersion = new Version(1, 1); + var httpVersion = new Version(1, 1); if (httpCmdSplit.Length == 3) { var httpVersionString = httpCmdSplit[2].ToLower().Trim(); - if (httpVersionString == "http/1.0") + if (0 == string.CompareOrdinal(httpVersionString, "http/1.0")) { httpVersion = new Version(1, 0); } @@ -439,10 +426,8 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St { var existing = args.WebSession.Request.RequestHeaders[newHeader.Name]; - var nonUniqueHeaders = new List(); + var nonUniqueHeaders = new List {existing, newHeader}; - nonUniqueHeaders.Add(existing); - nonUniqueHeaders.Add(newHeader); args.WebSession.Request.NonUniqueRequestHeaders.Add(newHeader.Name, nonUniqueHeaders); args.WebSession.Request.RequestHeaders.Remove(newHeader.Name); @@ -455,8 +440,7 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St } var httpRemoteUri = new Uri(httpsHostName == null ? httpCmdSplit[1] - : (string.Concat("https://", args.WebSession.Request.Host == null ? - httpsHostName : args.WebSession.Request.Host, httpCmdSplit[1]))); + : (string.Concat("https://", args.WebSession.Request.Host ?? httpsHostName, httpCmdSplit[1]))); args.WebSession.Request.RequestUri = httpRemoteUri; @@ -479,10 +463,10 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St //If user requested interception do it if (BeforeRequest != null) { - Delegate[] invocationList = BeforeRequest.GetInvocationList(); - Task[] handlerTasks = new Task[invocationList.Length]; + var invocationList = BeforeRequest.GetInvocationList(); + var handlerTasks = new Task[invocationList.Length]; - for (int i = 0; i < invocationList.Length; i++) + for (var i = 0; i < invocationList.Length; i++) { handlerTasks[i] = ((Func)invocationList[i])(null, args); } @@ -495,8 +479,8 @@ private async Task HandleHttpSessionRequest(TcpClient client, string httpCmd, St { await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Host, httpRemoteUri.Port, httpCmd, httpVersion, args.WebSession.Request.RequestHeaders, args.IsHttps, - SupportedSslProtocols, new RemoteCertificateValidationCallback(ValidateServerCertificate), - new LocalCertificateSelectionCallback(SelectClientCertificate), + SupportedSslProtocols, ValidateServerCertificate, + SelectClientCertificate, clientStream, tcpConnectionFactory, UpStreamEndPoint); Dispose(clientStream, clientStreamReader, clientStreamWriter, args); @@ -504,7 +488,7 @@ await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Hos } //construct the web request that we are going to issue on behalf of the client. - await HandleHttpSessionRequestInternal(connection, args, customUpStreamHttpProxy, customUpStreamHttpsProxy, false).ConfigureAwait(false); + await HandleHttpSessionRequestInternal(null, args, customUpStreamHttpProxy, customUpStreamHttpsProxy, false).ConfigureAwait(false); if (args.WebSession.Request.CancelRequest) @@ -531,12 +515,8 @@ await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Hos } - if (connection != null) - { - //dispose - connection.Dispose(); - } - + //dispose + connection?.Dispose(); } /// @@ -547,8 +527,9 @@ await TcpHelper.SendRaw(BUFFER_SIZE, ConnectionTimeOutSeconds, httpRemoteUri.Hos /// private async Task WriteConnectResponse(StreamWriter clientStreamWriter, Version httpVersion) { - await clientStreamWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2}", httpVersion.Major, httpVersion.Minor, "200 Connection established")); - await clientStreamWriter.WriteLineAsync(string.Format("Timestamp: {0}", DateTime.Now)); + await clientStreamWriter.WriteLineAsync( + $"HTTP/{httpVersion.Major}.{httpVersion.Minor} 200 Connection established"); + await clientStreamWriter.WriteLineAsync($"Timestamp: {DateTime.Now}"); await clientStreamWriter.WriteLineAsync(); await clientStreamWriter.FlushAsync(); } @@ -570,9 +551,6 @@ private void PrepareRequestHeaders(Dictionary requestHeaders case "accept-encoding": header.Value = "gzip,deflate"; break; - - default: - break; } } diff --git a/Titanium.Web.Proxy/ResponseHandler.cs b/Titanium.Web.Proxy/ResponseHandler.cs index 530720bfa..2f531d194 100644 --- a/Titanium.Web.Proxy/ResponseHandler.cs +++ b/Titanium.Web.Proxy/ResponseHandler.cs @@ -17,7 +17,11 @@ namespace Titanium.Web.Proxy /// partial class ProxyServer { - //Called asynchronously when a request was successfully and we received the response + /// + /// Called asynchronously when a request was successfully and we received the response + /// + /// + /// public async Task HandleHttpSessionResponse(SessionEventArgs args) { //read response & headers from server @@ -156,14 +160,14 @@ private async Task GetCompressedResponseBody(string encodingType, byte[] private async Task WriteResponseStatus(Version version, string code, string description, StreamWriter responseWriter) { - await responseWriter.WriteLineAsync(string.Format("HTTP/{0}.{1} {2} {3}", version.Major, version.Minor, code, description)); + await responseWriter.WriteLineAsync($"HTTP/{version.Major}.{version.Minor} {code} {description}"); } /// /// Write response headers to client /// /// - /// + /// /// private async Task WriteResponseHeaders(StreamWriter responseWriter, Response response) { @@ -220,7 +224,6 @@ private void FixProxyHeaders(Dictionary headers) /// /// Handle dispose of a client/server session /// - /// /// /// /// @@ -235,21 +238,13 @@ private void Dispose(Stream clientStream, CustomBinaryReader clientStreamReader, clientStream.Dispose(); } - if (args != null) - { - args.Dispose(); - } + args?.Dispose(); - if (clientStreamReader != null) - { - clientStreamReader.Dispose(); - } + clientStreamReader?.Dispose(); - if (clientStreamWriter != null) - { - clientStreamWriter.Close(); - clientStreamWriter.Dispose(); - } + if (clientStreamWriter == null) return; + clientStreamWriter.Close(); + clientStreamWriter.Dispose(); } } } \ No newline at end of file diff --git a/Titanium.Web.Proxy/Shared/ProxyConstants.cs b/Titanium.Web.Proxy/Shared/ProxyConstants.cs index 27a4bda52..e51977ada 100644 --- a/Titanium.Web.Proxy/Shared/ProxyConstants.cs +++ b/Titanium.Web.Proxy/Shared/ProxyConstants.cs @@ -1,5 +1,4 @@ -using System; -using System.Text; +using System.Text; namespace Titanium.Web.Proxy.Shared {