Commit 6fb5f0bf authored by justcoding121's avatar justcoding121

Add comments

parent f59fb6a3
...@@ -12,10 +12,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -12,10 +12,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
{ {
public void StartProxy() public void StartProxy()
{ {
ProxyServer.BeforeRequest += OnRequest; //ProxyServer.BeforeRequest += OnRequest;
ProxyServer.BeforeResponse += OnResponse; //ProxyServer.BeforeResponse += OnResponse;
ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation; //ProxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
ProxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; //ProxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
//Usefull for clients that use certificate pinning //Usefull for clients that use certificate pinning
......
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class CompressionFactory /// <summary>
/// A factory to generate the compression methods based on the type of compression
/// </summary>
internal class CompressionFactory
{ {
public ICompression Create(string type) public ICompression Create(string type)
{ {
......
...@@ -4,7 +4,10 @@ using System.Threading.Tasks; ...@@ -4,7 +4,10 @@ using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class DeflateCompression : ICompression /// <summary>
/// Concrete implementation of deflate compression
/// </summary>
internal class DeflateCompression : ICompression
{ {
public async Task<byte[]> Compress(byte[] responseBody) public async Task<byte[]> Compress(byte[] responseBody)
{ {
......
...@@ -4,7 +4,10 @@ using System.Threading.Tasks; ...@@ -4,7 +4,10 @@ using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class GZipCompression : ICompression /// <summary>
/// concreate implementation of gzip compression
/// </summary>
internal class GZipCompression : ICompression
{ {
public async Task<byte[]> Compress(byte[] responseBody) public async Task<byte[]> Compress(byte[] responseBody)
{ {
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary>
/// An inteface for http compression
/// </summary>
interface ICompression interface ICompression
{ {
Task<byte[]> Compress(byte[] responseBody); Task<byte[]> Compress(byte[] responseBody);
......
...@@ -4,7 +4,10 @@ using System.Threading.Tasks; ...@@ -4,7 +4,10 @@ using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
class ZlibCompression : ICompression /// <summary>
/// concrete implementation of zlib compression
/// </summary>
internal class ZlibCompression : ICompression
{ {
public async Task<byte[]> Compress(byte[] responseBody) public async Task<byte[]> Compress(byte[] responseBody)
{ {
......
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary>
/// A factory to generate the de-compression methods based on the type of compression
/// </summary>
internal class DecompressionFactory internal class DecompressionFactory
{ {
internal IDecompression Create(string type) internal IDecompression Create(string type)
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary>
/// When no compression is specified just return the byte array
/// </summary>
internal class DefaultDecompression : IDecompression internal class DefaultDecompression : IDecompression
{ {
public Task<byte[]> Decompress(byte[] compressedArray) public Task<byte[]> Decompress(byte[] compressedArray)
......
...@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared; ...@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary>
/// concrete implementation of deflate de-compression
/// </summary>
internal class DeflateDecompression : IDecompression internal class DeflateDecompression : IDecompression
{ {
public async Task<byte[]> Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray)
...@@ -18,7 +21,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -18,7 +21,7 @@ namespace Titanium.Web.Proxy.Decompression
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length)) > 0)
{ {
await output.WriteAsync(buffer, 0, read); await output.WriteAsync(buffer, 0, read);
} }
......
...@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared; ...@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary>
/// concrete implementation of gzip de-compression
/// </summary>
internal class GZipDecompression : IDecompression internal class GZipDecompression : IDecompression
{ {
public async Task<byte[]> Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray)
...@@ -15,7 +18,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -15,7 +18,7 @@ namespace Titanium.Web.Proxy.Decompression
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length)) > 0)
{ {
await output.WriteAsync(buffer, 0, read); await output.WriteAsync(buffer, 0, read);
} }
......
using System.IO; using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary>
/// An interface for decompression
/// </summary>
internal interface IDecompression internal interface IDecompression
{ {
Task<byte[]> Decompress(byte[] compressedArray); Task<byte[]> Decompress(byte[] compressedArray);
......
...@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared; ...@@ -5,6 +5,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary>
/// concrete implemetation of zlib de-compression
/// </summary>
internal class ZlibDecompression : IDecompression internal class ZlibDecompression : IDecompression
{ {
public async Task<byte[]> Decompress(byte[] compressedArray) public async Task<byte[]> Decompress(byte[] compressedArray)
...@@ -17,7 +20,7 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -17,7 +20,7 @@ namespace Titanium.Web.Proxy.Decompression
using (var output = new MemoryStream()) using (var output = new MemoryStream())
{ {
int read; int read;
while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0) while ((read = await decompressor.ReadAsync(buffer, 0, buffer.Length)) > 0)
{ {
await output.WriteAsync(buffer, 0, read); await output.WriteAsync(buffer, 0, read);
} }
......
...@@ -3,6 +3,9 @@ using System.Security.Cryptography.X509Certificates; ...@@ -3,6 +3,9 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary>
/// An argument passed on to user for client certificate selection during mutual SSL authentication
/// </summary>
public class CertificateSelectionEventArgs : EventArgs, IDisposable public class CertificateSelectionEventArgs : EventArgs, IDisposable
{ {
public object sender { get; internal set; } public object sender { get; internal set; }
......
...@@ -4,6 +4,9 @@ using System.Security.Cryptography.X509Certificates; ...@@ -4,6 +4,9 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary>
/// An argument passed on to the user for validating the server certificate during SSL authentication
/// </summary>
public class CertificateValidationEventArgs : EventArgs, IDisposable public class CertificateValidationEventArgs : EventArgs, IDisposable
{ {
public X509Certificate Certificate { get; internal set; } public X509Certificate Certificate { get; internal set; }
......
...@@ -9,7 +9,6 @@ using Titanium.Web.Proxy.Extensions; ...@@ -9,7 +9,6 @@ using Titanium.Web.Proxy.Extensions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
using System.Net; using System.Net;
using System.Net.Sockets;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
......
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
......
using System; using System.Globalization;
using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -8,6 +7,9 @@ using Titanium.Web.Proxy.Shared; ...@@ -8,6 +7,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
/// <summary>
/// Extensions used for Stream and CustomBinaryReader objects
/// </summary>
internal static class StreamExtensions internal static class StreamExtensions
{ {
/// <summary> /// <summary>
...@@ -134,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -134,7 +136,7 @@ namespace Titanium.Web.Proxy.Extensions
var bytesRead = 0; var bytesRead = 0;
var totalBytesRead = 0; var totalBytesRead = 0;
while ((bytesRead += await inStreamReader.BaseStream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0) while ((bytesRead += await inStreamReader.BaseStream.ReadAsync(buffer, 0, bytesToRead)) > 0)
{ {
await outStream.WriteAsync(buffer, 0, bytesRead); await outStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
......
...@@ -18,9 +18,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -18,9 +18,12 @@ namespace Titanium.Web.Proxy.Helpers
{ {
private Stream stream; private Stream stream;
private Encoding encoding; private Encoding encoding;
internal CustomBinaryReader(Stream stream) internal CustomBinaryReader(Stream stream)
{ {
this.stream = stream; this.stream = stream;
//default to UTF-8
this.encoding = Encoding.UTF8; this.encoding = Encoding.UTF8;
} }
...@@ -41,16 +44,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -41,16 +44,21 @@ namespace Titanium.Web.Proxy.Helpers
while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0) while ((await this.stream.ReadAsync(buffer, 0, 1)) > 0)
{ {
//if new line
if (lastChar == '\r' && buffer[0] == '\n') if (lastChar == '\r' && buffer[0] == '\n')
{ {
var result = readBuffer.ToArray(); var result = readBuffer.ToArray();
return encoding.GetString(result.SubArray(0, result.Length - 1)); return encoding.GetString(result.SubArray(0, result.Length - 1));
} }
//end of stream
if (buffer[0] == '\0') if (buffer[0] == '\0')
{ {
return encoding.GetString(readBuffer.ToArray()); return encoding.GetString(readBuffer.ToArray());
} }
await readBuffer.WriteAsync(buffer,0,1); await readBuffer.WriteAsync(buffer,0,1);
//store last char for new line comparison
lastChar = (char)buffer[0]; lastChar = (char)buffer[0];
} }
...@@ -58,7 +66,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -58,7 +66,7 @@ namespace Titanium.Web.Proxy.Helpers
} }
catch (IOException) catch (IOException)
{ {
return encoding.GetString(readBuffer.ToArray()); throw;
} }
} }
} }
...@@ -71,13 +79,18 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -71,13 +79,18 @@ namespace Titanium.Web.Proxy.Helpers
{ {
string tmpLine; string tmpLine;
var requestLines = new List<string>(); var requestLines = new List<string>();
while (!string.IsNullOrEmpty(tmpLine = await ReadLineAsync().ConfigureAwait(false))) while (!string.IsNullOrEmpty(tmpLine = await ReadLineAsync()))
{ {
requestLines.Add(tmpLine); requestLines.Add(tmpLine);
} }
return requestLines; return requestLines;
} }
/// <summary>
/// Read the specified number of raw bytes from the base stream
/// </summary>
/// <param name="totalBytesToRead"></param>
/// <returns></returns>
internal async Task<byte[]> ReadBytesAsync(long totalBytesToRead) internal async Task<byte[]> ReadBytesAsync(long totalBytesToRead)
{ {
int bytesToRead = ProxyConstants.BUFFER_SIZE; int bytesToRead = ProxyConstants.BUFFER_SIZE;
...@@ -92,7 +105,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -92,7 +105,7 @@ namespace Titanium.Web.Proxy.Helpers
using (var outStream = new MemoryStream()) using (var outStream = new MemoryStream())
{ {
while ((bytesRead += await this.stream.ReadAsync(buffer, 0, bytesToRead).ConfigureAwait(false)) > 0) while ((bytesRead += await this.stream.ReadAsync(buffer, 0, bytesToRead)) > 0)
{ {
await outStream.WriteAsync(buffer, 0, bytesRead); await outStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
......
...@@ -5,8 +5,12 @@ using System.Text.RegularExpressions; ...@@ -5,8 +5,12 @@ using System.Text.RegularExpressions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
/// <summary>
/// Helper classes for setting system proxy settings
/// </summary>
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal static class NativeMethods internal static class NativeMethods
{ {
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
...@@ -59,14 +63,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -59,14 +63,16 @@ namespace Titanium.Web.Proxy.Helpers
Refresh(); Refresh();
} }
/// <summary>
/// Remove the http proxy setting from current machine
/// </summary>
internal static void RemoveHttpProxy() internal static void RemoveHttpProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true); "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", true);
if (reg != null) if (reg != null)
{ {
if (reg.GetValue("ProxyServer")!=null) if (reg.GetValue("ProxyServer") != null)
{ {
var exisitingContent = reg.GetValue("ProxyServer") as string; var exisitingContent = reg.GetValue("ProxyServer") as string;
...@@ -89,6 +95,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -89,6 +95,11 @@ namespace Titanium.Web.Proxy.Helpers
Refresh(); Refresh();
} }
/// <summary>
/// Set the HTTPS proxy server for current machine
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
internal static void SetHttpsProxy(string hostname, int port) internal static void SetHttpsProxy(string hostname, int port)
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
...@@ -116,6 +127,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -116,6 +127,9 @@ namespace Titanium.Web.Proxy.Helpers
Refresh(); Refresh();
} }
/// <summary>
/// Removes the https proxy setting to nothing
/// </summary>
internal static void RemoveHttpsProxy() internal static void RemoveHttpsProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
...@@ -146,6 +160,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -146,6 +160,9 @@ namespace Titanium.Web.Proxy.Helpers
Refresh(); Refresh();
} }
/// <summary>
/// Removes all types of proxy settings (both http & https)
/// </summary>
internal static void DisableAllProxy() internal static void DisableAllProxy()
{ {
var reg = Registry.CurrentUser.OpenSubKey( var reg = Registry.CurrentUser.OpenSubKey(
...@@ -159,6 +176,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -159,6 +176,12 @@ namespace Titanium.Web.Proxy.Helpers
Refresh(); Refresh();
} }
/// <summary>
/// Get the current system proxy setting values
/// </summary>
/// <param name="prevServerValue"></param>
/// <returns></returns>
private static List<HttpSystemProxyValue> GetSystemProxyValues(string prevServerValue) private static List<HttpSystemProxyValue> GetSystemProxyValues(string prevServerValue)
{ {
var result = new List<HttpSystemProxyValue>(); var result = new List<HttpSystemProxyValue>();
...@@ -187,6 +210,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -187,6 +210,11 @@ namespace Titanium.Web.Proxy.Helpers
return result; return result;
} }
/// <summary>
/// Parses the system proxy setting string
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static HttpSystemProxyValue parseProxyValue(string value) private static HttpSystemProxyValue parseProxyValue(string value)
{ {
var tmp = Regex.Replace(value, @"\s+", " ").Trim().ToLower(); var tmp = Regex.Replace(value, @"\s+", " ").Trim().ToLower();
...@@ -213,7 +241,10 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -213,7 +241,10 @@ namespace Titanium.Web.Proxy.Helpers
return null; return null;
} }
/// <summary>
/// Prepares the proxy server registry (create empty values if they don't exist)
/// </summary>
/// <param name="reg"></param>
private static void prepareRegistry(RegistryKey reg) private static void prepareRegistry(RegistryKey reg)
{ {
if (reg.GetValue("ProxyEnable") == null) if (reg.GetValue("ProxyEnable") == null)
...@@ -228,7 +259,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -228,7 +259,9 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary>
/// Refresh the settings so that the system know about a change in proxy setting
/// </summary>
private static void Refresh() private static void Refresh()
{ {
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0); NativeMethods.InternetSetOption(IntPtr.Zero, InternetOptionSettingsChanged, IntPtr.Zero, 0);
......
...@@ -12,11 +12,24 @@ using Titanium.Web.Proxy.Shared; ...@@ -12,11 +12,24 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
internal class TcpHelper internal class TcpHelper
{ {
/// <summary>
/// relays the input clientStream to the server at the specified host name & port with the given httpCmd & headers as prefix
/// Usefull for websocket requests
/// </summary>
/// <param name="clientStream"></param>
/// <param name="httpCmd"></param>
/// <param name="requestHeaders"></param>
/// <param name="hostName"></param>
/// <param name="tunnelPort"></param>
/// <param name="isHttps"></param>
/// <returns></returns>
internal async static Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName, internal async static Task SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName,
int tunnelPort, bool isHttps) int tunnelPort, bool isHttps)
{ {
//prepare the prefix content
StringBuilder sb = null; StringBuilder sb = null;
if (httpCmd != null || requestHeaders != null) if (httpCmd != null || requestHeaders != null)
{ {
...@@ -38,7 +51,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -38,7 +51,7 @@ namespace Titanium.Web.Proxy.Helpers
TcpClient tunnelClient = null; TcpClient tunnelClient = null;
Stream tunnelStream = null; Stream tunnelStream = null;
//create the TcpClient to the server
try try
{ {
tunnelClient = new TcpClient(hostName, tunnelPort); tunnelClient = new TcpClient(hostName, tunnelPort);
...@@ -64,6 +77,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -64,6 +77,7 @@ namespace Titanium.Web.Proxy.Helpers
Task sendRelay; Task sendRelay;
//Now async relay all server=>client & client=>server data
if (sb != null) if (sb != null)
sendRelay = clientStream.CopyToAsync(sb.ToString(), tunnelStream); sendRelay = clientStream.CopyToAsync(sb.ToString(), tunnelStream);
else else
......
...@@ -9,6 +9,9 @@ using Titanium.Web.Proxy.Shared; ...@@ -9,6 +9,9 @@ using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
/// <summary>
/// Used to communicate with the server over HTTP(S)
/// </summary>
public class HttpWebClient public class HttpWebClient
{ {
/// <summary> /// <summary>
...@@ -19,6 +22,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -19,6 +22,9 @@ namespace Titanium.Web.Proxy.Http
public Request Request { get; set; } public Request Request { get; set; }
public Response Response { get; set; } public Response Response { get; set; }
/// <summary>
/// Is Https?
/// </summary>
public bool IsHttps public bool IsHttps
{ {
get get
...@@ -27,6 +33,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -27,6 +33,10 @@ namespace Titanium.Web.Proxy.Http
} }
} }
/// <summary>
/// Set the tcp connection to server used by this webclient
/// </summary>
/// <param name="Connection"></param>
internal void SetConnection(TcpConnection Connection) internal void SetConnection(TcpConnection Connection)
{ {
Connection.LastAccess = DateTime.Now; Connection.LastAccess = DateTime.Now;
...@@ -39,19 +49,24 @@ namespace Titanium.Web.Proxy.Http ...@@ -39,19 +49,24 @@ namespace Titanium.Web.Proxy.Http
this.Response = new Response(); this.Response = new Response();
} }
/// <summary>
/// Prepare & send the http(s) request
/// </summary>
/// <returns></returns>
internal async Task SendRequest() internal async Task SendRequest()
{ {
Stream stream = ServerConnection.Stream; Stream stream = ServerConnection.Stream;
StringBuilder requestLines = new StringBuilder(); StringBuilder requestLines = new StringBuilder();
//prepare the request & headers
requestLines.AppendLine(string.Join(" ", new string[3] requestLines.AppendLine(string.Join(" ", new string[3]
{ {
this.Request.Method, this.Request.Method,
this.Request.RequestUri.PathAndQuery, this.Request.RequestUri.PathAndQuery,
string.Format("HTTP/{0}.{1}",this.Request.HttpVersion.Major, this.Request.HttpVersion.Minor) string.Format("HTTP/{0}.{1}",this.Request.HttpVersion.Major, this.Request.HttpVersion.Minor)
})); }));
//write request headers
foreach (HttpHeader httpHeader in this.Request.RequestHeaders) foreach (HttpHeader httpHeader in this.Request.RequestHeaders)
{ {
requestLines.AppendLine(httpHeader.Name + ':' + httpHeader.Value); requestLines.AppendLine(httpHeader.Name + ':' + httpHeader.Value);
...@@ -87,6 +102,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -87,6 +102,10 @@ namespace Titanium.Web.Proxy.Http
} }
} }
/// <summary>
/// Receive & parse the http response from server
/// </summary>
/// <returns></returns>
internal async Task ReceiveResponse() internal async Task ReceiveResponse()
{ {
//return if this is already read //return if this is already read
...@@ -130,6 +149,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -130,6 +149,7 @@ namespace Titanium.Web.Proxy.Http
return; return;
} }
//read response headers
List<string> responseLines = await ServerConnection.StreamReader.ReadAllLinesAsync(); List<string> responseLines = await ServerConnection.StreamReader.ReadAllLinesAsync();
for (int index = 0; index < responseLines.Count; ++index) for (int index = 0; index < responseLines.Count; ++index)
......
...@@ -7,6 +7,9 @@ using Titanium.Web.Proxy.Extensions; ...@@ -7,6 +7,9 @@ using Titanium.Web.Proxy.Extensions;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
/// <summary>
/// A HTTP(S) request object
/// </summary>
public class Request public class Request
{ {
public string Method { get; set; } public string Method { get; set; }
......
...@@ -8,7 +8,9 @@ using System; ...@@ -8,7 +8,9 @@ using System;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
/// <summary>
/// Http(s) response object
/// </summary>
public class Response public class Response
{ {
public string ResponseStatusCode { get; set; } public string ResponseStatusCode { get; set; }
......
using Titanium.Web.Proxy.Network; namespace Titanium.Web.Proxy.Http.Responses
namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary>
/// 200 Ok response
/// </summary>
public class OkResponse : Response public class OkResponse : Response
{ {
public OkResponse() public OkResponse()
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
namespace Titanium.Web.Proxy.Http.Responses namespace Titanium.Web.Proxy.Http.Responses
{ {
/// <summary>
/// Redirect response
/// </summary>
public class RedirectResponse : Response public class RedirectResponse : Response
{ {
public RedirectResponse() public RedirectResponse()
......
...@@ -4,6 +4,9 @@ using System.Net.Sockets; ...@@ -4,6 +4,9 @@ using System.Net.Sockets;
namespace Titanium.Web.Proxy.Models namespace Titanium.Web.Proxy.Models
{ {
/// <summary>
/// An abstract endpoint where the proxy listens
/// </summary>
public abstract class ProxyEndPoint public abstract class ProxyEndPoint
{ {
public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl) public ProxyEndPoint(IPAddress IpAddress, int Port, bool EnableSsl)
...@@ -20,6 +23,10 @@ namespace Titanium.Web.Proxy.Models ...@@ -20,6 +23,10 @@ namespace Titanium.Web.Proxy.Models
internal TcpListener listener { get; set; } internal TcpListener listener { get; set; }
} }
/// <summary>
/// A proxy endpoint that the client is aware of
/// So client application know that it is communicating with a proxy server
/// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint public class ExplicitProxyEndPoint : ProxyEndPoint
{ {
internal bool IsSystemHttpProxy { get; set; } internal bool IsSystemHttpProxy { get; set; }
...@@ -34,6 +41,10 @@ namespace Titanium.Web.Proxy.Models ...@@ -34,6 +41,10 @@ namespace Titanium.Web.Proxy.Models
} }
} }
/// <summary>
/// A proxy end point client is not aware of
/// Usefull when requests are redirected to this proxy end point through port forwarding
/// </summary>
public class TransparentProxyEndPoint : ProxyEndPoint public class TransparentProxyEndPoint : ProxyEndPoint
{ {
//Name of the Certificate need to be sent (same as the hostname we want to proxy) //Name of the Certificate need to be sent (same as the hostname we want to proxy)
......
using System; namespace Titanium.Web.Proxy.Models
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Models
{ {
/// <summary>
/// An upstream proxy this proxy uses if any
/// </summary>
public class ExternalProxy public class ExternalProxy
{ {
public string HostName { get; set; } public string HostName { get; set; }
......
using System;
using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.Network
{
/// <summary>
/// An object that holds the cached certificate
/// </summary>
internal class CachedCertificate
{
internal X509Certificate2 Certificate { get; set; }
/// <summary>
/// last time this certificate was used
/// Usefull in determining its cache lifetime
/// </summary>
internal DateTime LastAccess { get; set; }
internal CachedCertificate()
{
LastAccess = DateTime.Now;
}
}
}
...@@ -8,20 +8,11 @@ using System.Threading.Tasks; ...@@ -8,20 +8,11 @@ using System.Threading.Tasks;
using System.Threading; using System.Threading;
using System.Linq; using System.Linq;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Network
{ {
internal class CachedCertificate /// <summary>
{ /// A class to manage SSL certificates used by this proxy server
internal X509Certificate2 Certificate { get; set; } /// </summary>
internal DateTime LastAccess { get; set; }
internal CachedCertificate()
{
LastAccess = DateTime.Now;
}
}
internal class CertificateManager : IDisposable internal class CertificateManager : IDisposable
{ {
private const string CertCreateFormat = private const string CertCreateFormat =
...@@ -85,6 +76,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -85,6 +76,13 @@ namespace Titanium.Web.Proxy.Helpers
return await CreateCertificate(MyStore, certificateName, isRootCertificate); return await CreateCertificate(MyStore, certificateName, isRootCertificate);
} }
/// <summary>
/// Create an SSL certificate
/// </summary>
/// <param name="store"></param>
/// <param name="certificateName"></param>
/// <param name="isRootCertificate"></param>
/// <returns></returns>
protected async virtual Task<X509Certificate2> CreateCertificate(X509Store store, string certificateName, bool isRootCertificate) protected async virtual Task<X509Certificate2> CreateCertificate(X509Store store, string certificateName, bool isRootCertificate)
{ {
await semaphoreLock.WaitAsync(); await semaphoreLock.WaitAsync();
...@@ -141,6 +139,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -141,6 +139,11 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
/// <summary>
/// Create certificate using makecert.exe
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
protected virtual Task<int> CreateCertificate(string[] args) protected virtual Task<int> CreateCertificate(string[] args)
{ {
...@@ -178,12 +181,24 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -178,12 +181,24 @@ namespace Titanium.Web.Proxy.Helpers
return tcs.Task; return tcs.Task;
} }
/// <summary>
/// Destroy an SSL certificate from local store
/// </summary>
/// <param name="certificateName"></param>
/// <returns></returns>
internal bool DestroyCertificate(string certificateName) internal bool DestroyCertificate(string certificateName)
{ {
return DestroyCertificate(MyStore, certificateName, false); return DestroyCertificate(MyStore, certificateName, false);
} }
/// <summary>
/// Destroy certificate from the specified store
/// optionally also remove from proxy certificate cache
/// </summary>
/// <param name="store"></param>
/// <param name="certificateName"></param>
/// <param name="removeFromCache"></param>
/// <returns></returns>
protected virtual bool DestroyCertificate(X509Store store, string certificateName, bool removeFromCache) protected virtual bool DestroyCertificate(X509Store store, string certificateName, bool removeFromCache)
{ {
X509Certificate2Collection certificates = null; X509Certificate2Collection certificates = null;
...@@ -206,7 +221,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -206,7 +221,12 @@ namespace Titanium.Web.Proxy.Helpers
} }
return certificates == null; return certificates == null;
} }
/// <summary>
/// Create the neccessary arguments for makecert.exe to create the required certificate
/// </summary>
/// <param name="store"></param>
/// <param name="certificateName"></param>
/// <returns></returns>
protected virtual string GetCertificateCreateArgs(X509Store store, string certificateName) protected virtual string GetCertificateCreateArgs(X509Store store, string certificateName)
{ {
bool isRootCertificate = bool isRootCertificate =
...@@ -223,11 +243,17 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -223,11 +243,17 @@ namespace Titanium.Web.Proxy.Helpers
private static bool clearCertificates { get; set; } private static bool clearCertificates { get; set; }
/// <summary>
/// Stops the certificate cache clear process
/// </summary>
internal void StopClearIdleCertificates() internal void StopClearIdleCertificates()
{ {
clearCertificates = false; clearCertificates = false;
} }
/// <summary>
/// A method to clear outdated certificates
/// </summary>
internal async void ClearIdleCertificates() internal async void ClearIdleCertificates()
{ {
clearCertificates = true; clearCertificates = true;
...@@ -248,7 +274,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -248,7 +274,8 @@ namespace Titanium.Web.Proxy.Helpers
} }
finally { semaphoreLock.Release(); } finally { semaphoreLock.Release(); }
await Task.Delay(1000 * 60 * 3); //after a minute come back to check for outdated certificates in cache
await Task.Delay(1000 * 60);
} }
} }
......
using System;
using System.IO;
using System.Net.Sockets;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Network
{
/// <summary>
/// An object that holds TcpConnection to a particular server & port
/// </summary>
public class TcpConnection
{
internal string HostName { get; set; }
internal int port { get; set; }
internal bool IsHttps { get; set; }
/// <summary>
/// Http version
/// </summary>
internal Version Version { get; set; }
internal TcpClient TcpClient { get; set; }
/// <summary>
/// used to read lines from server
/// </summary>
internal CustomBinaryReader StreamReader { get; set; }
/// <summary>
/// Server stream
/// </summary>
internal Stream Stream { get; set; }
/// <summary>
/// Last time this connection was used
/// </summary>
internal DateTime LastAccess { get; set; }
internal TcpConnection()
{
LastAccess = DateTime.Now;
}
}
}
...@@ -10,44 +10,41 @@ using Titanium.Web.Proxy.Helpers; ...@@ -10,44 +10,41 @@ using Titanium.Web.Proxy.Helpers;
using System.Threading; using System.Threading;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
using System.Security.Cryptography.X509Certificates;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Network namespace Titanium.Web.Proxy.Network
{ {
public class TcpConnection /// <summary>
{ /// A class that manages Tcp Connection to server used by this proxy server
internal string HostName { get; set; } /// </summary>
internal int port { get; set; }
internal bool IsHttps { get; set; }
internal Version Version { get; set; }
internal TcpClient TcpClient { get; set; }
internal CustomBinaryReader StreamReader { get; set; }
internal Stream Stream { get; set; }
internal DateTime LastAccess { get; set; }
internal TcpConnection()
{
LastAccess = DateTime.Now;
}
}
internal class TcpConnectionManager internal class TcpConnectionManager
{ {
/// <summary>
/// Connection cache
/// </summary>
static Dictionary<string, List<TcpConnection>> connectionCache = new Dictionary<string, List<TcpConnection>>(); static Dictionary<string, List<TcpConnection>> connectionCache = new Dictionary<string, List<TcpConnection>>();
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
/// <summary>
/// A lock to manage concurrency
/// </summary>
static SemaphoreSlim connectionAccessLock = new SemaphoreSlim(1);
/// <summary>
/// Get a TcpConnection to the specified host, port optionally HTTPS and a particular HTTP version
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal static async Task<TcpConnection> GetClient(string hostname, int port, bool isHttps, Version version) internal static async Task<TcpConnection> GetClient(string hostname, int port, bool isHttps, Version version)
{ {
List<TcpConnection> cachedConnections = null; List<TcpConnection> cachedConnections = null;
TcpConnection cached = null; TcpConnection cached = null;
//Get a unique string to identify this connection
var key = GetConnectionKey(hostname, port, isHttps, version); var key = GetConnectionKey(hostname, port, isHttps, version);
while (true) while (true)
{ {
await connectionAccessLock.WaitAsync(); await connectionAccessLock.WaitAsync();
...@@ -76,6 +73,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -76,6 +73,7 @@ namespace Titanium.Web.Proxy.Network
if (cached == null) if (cached == null)
break; break;
} }
if (cached == null) if (cached == null)
...@@ -90,11 +88,27 @@ namespace Titanium.Web.Proxy.Network ...@@ -90,11 +88,27 @@ namespace Titanium.Web.Proxy.Network
return cached; return cached;
} }
/// <summary>
/// Get a string to identfiy the connection to a particular host, port
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
internal static string GetConnectionKey(string hostname, int port, bool isHttps, Version version) internal static string GetConnectionKey(string hostname, int port, bool isHttps, Version version)
{ {
return string.Format("{0}:{1}:{2}:{3}:{4}", hostname.ToLower(), port, isHttps, version.Major, version.Minor); return string.Format("{0}:{1}:{2}:{3}:{4}", hostname.ToLower(), port, isHttps, version.Major, version.Minor);
} }
/// <summary>
/// Create connection to a particular host/port optionally with SSL and a particular HTTP version
/// </summary>
/// <param name="hostname"></param>
/// <param name="port"></param>
/// <param name="isHttps"></param>
/// <param name="version"></param>
/// <returns></returns>
private static async Task<TcpConnection> CreateClient(string hostname, int port, bool isHttps, Version version) private static async Task<TcpConnection> CreateClient(string hostname, int port, bool isHttps, Version version)
{ {
TcpClient client; TcpClient client;
...@@ -104,6 +118,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -104,6 +118,7 @@ namespace Titanium.Web.Proxy.Network
{ {
SslStream sslStream = null; SslStream sslStream = null;
//If this proxy uses another external proxy then create a tunnel request for HTTPS connections
if (ProxyServer.UpStreamHttpsProxy != null) if (ProxyServer.UpStreamHttpsProxy != null)
{ {
client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port); client = new TcpClient(ProxyServer.UpStreamHttpsProxy.HostName, ProxyServer.UpStreamHttpsProxy.Port);
...@@ -175,7 +190,11 @@ namespace Titanium.Web.Proxy.Network ...@@ -175,7 +190,11 @@ namespace Titanium.Web.Proxy.Network
}; };
} }
/// <summary>
/// Returns a Tcp Connection back to cache for reuse by other requests
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
internal static async Task ReleaseClient(TcpConnection connection) internal static async Task ReleaseClient(TcpConnection connection)
{ {
...@@ -199,11 +218,17 @@ namespace Titanium.Web.Proxy.Network ...@@ -199,11 +218,17 @@ namespace Titanium.Web.Proxy.Network
private static bool clearConenctions { get; set; } private static bool clearConenctions { get; set; }
/// <summary>
/// Stop clearing idle connections
/// </summary>
internal static void StopClearIdleConnections() internal static void StopClearIdleConnections()
{ {
clearConenctions = false; clearConenctions = false;
} }
/// <summary>
/// A method to clear idle connections
/// </summary>
internal async static void ClearIdleConnections() internal async static void ClearIdleConnections()
{ {
clearConenctions = true; clearConenctions = true;
...@@ -224,6 +249,7 @@ namespace Titanium.Web.Proxy.Network ...@@ -224,6 +249,7 @@ namespace Titanium.Web.Proxy.Network
} }
finally { connectionAccessLock.Release(); } finally { connectionAccessLock.Release(); }
//every minute run this
await Task.Delay(1000 * 60); await Task.Delay(1000 * 60);
} }
......
...@@ -22,17 +22,41 @@ namespace Titanium.Web.Proxy ...@@ -22,17 +22,41 @@ namespace Titanium.Web.Proxy
static ProxyServer() static ProxyServer()
{ {
ProxyEndPoints = new List<ProxyEndPoint>(); ProxyEndPoints = new List<ProxyEndPoint>();
//default values
ConnectionCacheTimeOutMinutes = 3; ConnectionCacheTimeOutMinutes = 3;
CertificateCacheTimeOutMinutes = 60; CertificateCacheTimeOutMinutes = 60;
} }
/// <summary>
/// Manages certificates used by this proxy
/// </summary>
private static CertificateManager CertManager { get; set; } private static CertificateManager CertManager { get; set; }
/// <summary>
/// Does the root certificate used by this proxy is trusted by the machine?
/// </summary>
private static bool certTrusted { get; set; } private static bool certTrusted { get; set; }
/// <summary>
/// Is the proxy currently running
/// </summary>
private static bool proxyRunning { get; set; } private static bool proxyRunning { get; set; }
/// <summary>
/// Name of the root certificate issuer
/// </summary>
public static string RootCertificateIssuerName { get; set; } public static string RootCertificateIssuerName { get; set; }
/// <summary>
/// Name of the root certificate
/// </summary>
public static string RootCertificateName { get; set; } public static string RootCertificateName { get; set; }
/// <summary>
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Broken 100 contunue implementations on server/client may cause problems if enabled
/// </summary>
public static bool Enable100ContinueBehaviour { get; set; } public static bool Enable100ContinueBehaviour { get; set; }
/// <summary> /// <summary>
...@@ -45,13 +69,11 @@ namespace Titanium.Web.Proxy ...@@ -45,13 +69,11 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public static int CertificateCacheTimeOutMinutes { get; set; } public static int CertificateCacheTimeOutMinutes { get; set; }
/// <summary> /// <summary>
/// Intercept request to server /// Intercept request to server
/// </summary> /// </summary>
public static event Func<object, SessionEventArgs, Task> BeforeRequest; public static event Func<object, SessionEventArgs, Task> BeforeRequest;
/// <summary> /// <summary>
/// Intercept response from server /// Intercept response from server
/// </summary> /// </summary>
...@@ -77,20 +99,33 @@ namespace Titanium.Web.Proxy ...@@ -77,20 +99,33 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
public static event Func<object, CertificateSelectionEventArgs, Task> ClientCertificateSelectionCallback; public static event Func<object, CertificateSelectionEventArgs, Task> ClientCertificateSelectionCallback;
/// <summary>
/// A list of IpAddress & port this proxy is listening to
/// </summary>
public static List<ProxyEndPoint> ProxyEndPoints { get; set; } public static List<ProxyEndPoint> ProxyEndPoints { get; set; }
/// <summary>
/// Initialize the proxy
/// </summary>
public static void Initialize() public static void Initialize()
{ {
TcpConnectionManager.ClearIdleConnections(); TcpConnectionManager.ClearIdleConnections();
CertManager.ClearIdleCertificates(); CertManager.ClearIdleCertificates();
} }
/// <summary>
/// Quit the proxy
/// </summary>
public static void Quit() public static void Quit()
{ {
TcpConnectionManager.StopClearIdleConnections(); TcpConnectionManager.StopClearIdleConnections();
CertManager.StopClearIdleCertificates(); CertManager.StopClearIdleCertificates();
} }
/// <summary>
/// Add a proxy end point
/// </summary>
/// <param name="endPoint"></param>
public static void AddEndPoint(ProxyEndPoint endPoint) public static void AddEndPoint(ProxyEndPoint endPoint)
{ {
ProxyEndPoints.Add(endPoint); ProxyEndPoints.Add(endPoint);
...@@ -99,6 +134,11 @@ namespace Titanium.Web.Proxy ...@@ -99,6 +134,11 @@ namespace Titanium.Web.Proxy
Listen(endPoint); Listen(endPoint);
} }
/// <summary>
/// Remove a proxy end point
/// Will throw error if the end point does'nt exist
/// </summary>
/// <param name="endPoint"></param>
public static void RemoveEndPoint(ProxyEndPoint endPoint) public static void RemoveEndPoint(ProxyEndPoint endPoint)
{ {
...@@ -111,10 +151,13 @@ namespace Titanium.Web.Proxy ...@@ -111,10 +151,13 @@ namespace Titanium.Web.Proxy
QuitListen(endPoint); QuitListen(endPoint);
} }
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// <param name="endPoint"></param>
public static void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint) public static void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint)
{ {
VerifyProxy(endPoint); ValidateEndPointAsSystemProxy(endPoint);
//clear any settings previously added //clear any settings previously added
ProxyEndPoints.OfType<ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpProxy = false); ProxyEndPoints.OfType<ExplicitProxyEndPoint>().ToList().ForEach(x => x.IsSystemHttpProxy = false);
...@@ -130,14 +173,21 @@ namespace Titanium.Web.Proxy ...@@ -130,14 +173,21 @@ namespace Titanium.Web.Proxy
} }
/// <summary>
/// Remove any HTTP proxy setting of current machien
/// </summary>
public static void DisableSystemHttpProxy() public static void DisableSystemHttpProxy()
{ {
SystemProxyHelper.RemoveHttpProxy(); SystemProxyHelper.RemoveHttpProxy();
} }
/// <summary>
/// Set the given explicit end point as the default proxy server for current machine
/// </summary>
/// <param name="endPoint"></param>
public static void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint) public static void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint)
{ {
VerifyProxy(endPoint); ValidateEndPointAsSystemProxy(endPoint);
if (!endPoint.EnableSsl) if (!endPoint.EnableSsl)
{ {
...@@ -164,16 +214,25 @@ namespace Titanium.Web.Proxy ...@@ -164,16 +214,25 @@ namespace Titanium.Web.Proxy
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 {1} and port: {2} as System HTTPS Proxy", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
} }
/// <summary>
/// Remove any HTTPS proxy setting for current machine
/// </summary>
public static void DisableSystemHttpsProxy() public static void DisableSystemHttpsProxy()
{ {
SystemProxyHelper.RemoveHttpsProxy(); SystemProxyHelper.RemoveHttpsProxy();
} }
/// <summary>
/// Clear all proxy settings for current machine
/// </summary>
public static void DisableAllSystemProxies() public static void DisableAllSystemProxies()
{ {
SystemProxyHelper.DisableAllProxy(); SystemProxyHelper.DisableAllProxy();
} }
/// <summary>
/// Start this proxy server
/// </summary>
public static void Start() public static void Start()
{ {
if (proxyRunning) if (proxyRunning)
...@@ -197,6 +256,9 @@ namespace Titanium.Web.Proxy ...@@ -197,6 +256,9 @@ namespace Titanium.Web.Proxy
proxyRunning = true; proxyRunning = true;
} }
/// <summary>
/// Stop this proxy server
/// </summary>
public static void Stop() public static void Stop()
{ {
if (!proxyRunning) if (!proxyRunning)
...@@ -224,6 +286,10 @@ namespace Titanium.Web.Proxy ...@@ -224,6 +286,10 @@ namespace Titanium.Web.Proxy
proxyRunning = false; proxyRunning = false;
} }
/// <summary>
/// Listen on the given end point on local machine
/// </summary>
/// <param name="endPoint"></param>
private static void Listen(ProxyEndPoint endPoint) private static void Listen(ProxyEndPoint endPoint)
{ {
endPoint.listener = new TcpListener(endPoint.IpAddress, endPoint.Port); endPoint.listener = new TcpListener(endPoint.IpAddress, endPoint.Port);
...@@ -234,13 +300,20 @@ namespace Titanium.Web.Proxy ...@@ -234,13 +300,20 @@ namespace Titanium.Web.Proxy
endPoint.listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint); endPoint.listener.BeginAcceptTcpClient(OnAcceptConnection, endPoint);
} }
/// <summary>
/// Quit listening on the given end point
/// </summary>
/// <param name="endPoint"></param>
private static void QuitListen(ProxyEndPoint endPoint) private static void QuitListen(ProxyEndPoint endPoint)
{ {
endPoint.listener.Stop(); endPoint.listener.Stop();
} }
/// <summary>
private static void VerifyProxy(ExplicitProxyEndPoint endPoint) /// Verifiy if its safe to set this end point as System proxy
/// </summary>
/// <param name="endPoint"></param>
private static void ValidateEndPointAsSystemProxy(ExplicitProxyEndPoint endPoint)
{ {
if (ProxyEndPoints.Contains(endPoint) == false) if (ProxyEndPoints.Contains(endPoint) == false)
throw new Exception("Cannot set endPoints not added to proxy as system proxy"); throw new Exception("Cannot set endPoints not added to proxy as system proxy");
...@@ -249,12 +322,17 @@ namespace Titanium.Web.Proxy ...@@ -249,12 +322,17 @@ namespace Titanium.Web.Proxy
throw new Exception("Cannot set system proxy settings before proxy has been started."); throw new Exception("Cannot set system proxy settings before proxy has been started.");
} }
/// <summary>
/// When a connection is received from client act
/// </summary>
/// <param name="asyn"></param>
private static void OnAcceptConnection(IAsyncResult asyn) private static void OnAcceptConnection(IAsyncResult asyn)
{ {
var endPoint = (ProxyEndPoint)asyn.AsyncState; var endPoint = (ProxyEndPoint)asyn.AsyncState;
try try
{ {
//based on end point type call appropriate request handlers
var client = endPoint.listener.EndAcceptTcpClient(asyn); var client = endPoint.listener.EndAcceptTcpClient(asyn);
if (endPoint.GetType() == typeof(TransparentProxyEndPoint)) if (endPoint.GetType() == typeof(TransparentProxyEndPoint))
HandleClient(endPoint as TransparentProxyEndPoint, client); HandleClient(endPoint as TransparentProxyEndPoint, client);
...@@ -273,7 +351,7 @@ namespace Titanium.Web.Proxy ...@@ -273,7 +351,7 @@ namespace Titanium.Web.Proxy
} }
catch catch
{ {
//Other errors are discarded to keep the proxy running
} }
} }
......
...@@ -59,10 +59,10 @@ namespace Titanium.Web.Proxy ...@@ -59,10 +59,10 @@ namespace Titanium.Web.Proxy
{ {
version = new Version(1, 0); version = new Version(1, 0);
} }
} }
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)) : false;
//Client wants to create a secure tcp tunnel (its a HTTPS request) //Client wants to create a secure tcp tunnel (its a HTTPS request)
if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80) if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port != 80)
...@@ -217,7 +217,7 @@ namespace Titanium.Web.Proxy ...@@ -217,7 +217,7 @@ namespace Titanium.Web.Proxy
args.WebSession.Request.RequestHeaders = new List<HttpHeader>(); args.WebSession.Request.RequestHeaders = new List<HttpHeader>();
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync().ConfigureAwait(false))) while (!string.IsNullOrEmpty(tmpLine = await clientStreamReader.ReadLineAsync()))
{ {
var header = tmpLine.Split(ProxyConstants.ColonSplit, 2); var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);
args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1])); args.WebSession.Request.RequestHeaders.Add(new HttpHeader(header[0], header[1]));
......
...@@ -63,11 +63,12 @@ ...@@ -63,11 +63,12 @@
<Compile Include="EventArguments\CertificateSelectionEventArgs.cs" /> <Compile Include="EventArguments\CertificateSelectionEventArgs.cs" />
<Compile Include="EventArguments\CertificateValidationEventArgs.cs" /> <Compile Include="EventArguments\CertificateValidationEventArgs.cs" />
<Compile Include="Extensions\ByteArrayExtensions.cs" /> <Compile Include="Extensions\ByteArrayExtensions.cs" />
<Compile Include="Network\CachedCertificate.cs" />
<Compile Include="Network\ProxyClient.cs" /> <Compile Include="Network\ProxyClient.cs" />
<Compile Include="Exceptions\BodyNotFoundException.cs" /> <Compile Include="Exceptions\BodyNotFoundException.cs" />
<Compile Include="Extensions\HttpWebResponseExtensions.cs" /> <Compile Include="Extensions\HttpWebResponseExtensions.cs" />
<Compile Include="Extensions\HttpWebRequestExtensions.cs" /> <Compile Include="Extensions\HttpWebRequestExtensions.cs" />
<Compile Include="Helpers\CertificateManager.cs" /> <Compile Include="Network\CertificateManager.cs" />
<Compile Include="Helpers\Firefox.cs" /> <Compile Include="Helpers\Firefox.cs" />
<Compile Include="Helpers\SystemProxy.cs" /> <Compile Include="Helpers\SystemProxy.cs" />
<Compile Include="Models\EndPoint.cs" /> <Compile Include="Models\EndPoint.cs" />
...@@ -75,6 +76,7 @@ ...@@ -75,6 +76,7 @@
<Compile Include="Http\Request.cs" /> <Compile Include="Http\Request.cs" />
<Compile Include="Http\Response.cs" /> <Compile Include="Http\Response.cs" />
<Compile Include="Models\ExternalProxy.cs" /> <Compile Include="Models\ExternalProxy.cs" />
<Compile Include="Network\TcpConnection.cs" />
<Compile Include="Network\TcpConnectionManager.cs" /> <Compile Include="Network\TcpConnectionManager.cs" />
<Compile Include="Models\HttpHeader.cs" /> <Compile Include="Models\HttpHeader.cs" />
<Compile Include="Http\HttpWebClient.cs" /> <Compile Include="Http\HttpWebClient.cs" />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment