Unverified Commit b69506ef authored by honfika's avatar honfika Committed by GitHub

Merge pull request #416 from justcoding121/develop

merge to beta
parents d3829eab 498e9644
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup> </startup>
</configuration> </configuration>
\ No newline at end of file
...@@ -4,24 +4,24 @@ using System.Runtime.InteropServices; ...@@ -4,24 +4,24 @@ using System.Runtime.InteropServices;
namespace Titanium.Web.Proxy.Examples.Basic.Helpers namespace Titanium.Web.Proxy.Examples.Basic.Helpers
{ {
/// <summary> /// <summary>
/// Adapated from /// Adapated from
/// http://stackoverflow.com/questions/13656846/how-to-programmatic-disable-c-sharp-console-applications-quick-edit-mode /// http://stackoverflow.com/questions/13656846/how-to-programmatic-disable-c-sharp-console-applications-quick-edit-mode
/// </summary> /// </summary>
internal static class ConsoleHelper internal static class ConsoleHelper
{ {
const uint ENABLE_QUICK_EDIT = 0x0040; private const uint ENABLE_QUICK_EDIT = 0x0040;
// STD_INPUT_HANDLE (DWORD): -10 is the standard input device. // STD_INPUT_HANDLE (DWORD): -10 is the standard input device.
const int STD_INPUT_HANDLE = -10; private const int STD_INPUT_HANDLE = -10;
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle); private static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
internal static bool DisableQuickEditMode() internal static bool DisableQuickEditMode()
{ {
......
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
......
...@@ -17,13 +17,16 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -17,13 +17,16 @@ namespace Titanium.Web.Proxy.Examples.Basic
private readonly object lockObj = new object(); private readonly object lockObj = new object();
private readonly ProxyServer proxyServer; private readonly ProxyServer proxyServer;
private ExplicitProxyEndPoint explicitEndPoint;
//keep track of request headers //keep track of request headers
private readonly IDictionary<Guid, HeaderCollection> requestHeaderHistory = new ConcurrentDictionary<Guid, HeaderCollection>(); private readonly IDictionary<Guid, HeaderCollection> requestHeaderHistory =
new ConcurrentDictionary<Guid, HeaderCollection>();
//keep track of response headers //keep track of response headers
private readonly IDictionary<Guid, HeaderCollection> responseHeaderHistory = new ConcurrentDictionary<Guid, HeaderCollection>(); private readonly IDictionary<Guid, HeaderCollection> responseHeaderHistory =
new ConcurrentDictionary<Guid, HeaderCollection>();
private ExplicitProxyEndPoint explicitEndPoint;
//share requestBody outside handlers //share requestBody outside handlers
//Using a dictionary is not a good idea since it can cause memory overflow //Using a dictionary is not a good idea since it can cause memory overflow
...@@ -78,13 +81,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -78,13 +81,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
//proxyServer.EnableWinAuth = true; //proxyServer.EnableWinAuth = true;
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000) explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000);
{
//Use self-issued generic certificate on all https requests
//Optimizes performance by not creating a certificate for each https-enabled domain
//Useful when certificate trust is not required by proxy clients
//GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "genericcert.pfx"), "password")
};
//Fired when a CONNECT request is received //Fired when a CONNECT request is received
explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest;
...@@ -111,7 +108,10 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -111,7 +108,10 @@ namespace Titanium.Web.Proxy.Examples.Basic
//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 }; //proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = "localhost", Port = 8888 };
foreach (var endPoint in proxyServer.ProxyEndPoints) foreach (var endPoint in proxyServer.ProxyEndPoints)
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); {
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", endPoint.GetType().Name,
endPoint.IpAddress, endPoint.Port);
}
#if NETSTANDARD2_0 #if NETSTANDARD2_0
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
...@@ -251,7 +251,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -251,7 +251,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
} }
/// <summary> /// <summary>
/// Allows overriding default certificate validation logic /// Allows overriding default certificate validation logic
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
...@@ -267,7 +267,7 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -267,7 +267,7 @@ namespace Titanium.Web.Proxy.Examples.Basic
} }
/// <summary> /// <summary>
/// Allows overriding default client certificate selection logic during mutual authentication /// Allows overriding default client certificate selection logic during mutual authentication
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup> </startup>
</configuration> </configuration>
\ No newline at end of file
...@@ -4,6 +4,6 @@ ...@@ -4,6 +4,6 @@
xmlns:local="clr-namespace:Titanium.Web.Proxy.Examples.Wpf" xmlns:local="clr-namespace:Titanium.Web.Proxy.Examples.Wpf"
StartupUri="MainWindow.xaml"> StartupUri="MainWindow.xaml">
<Application.Resources> <Application.Resources>
</Application.Resources> </Application.Resources>
</Application> </Application>
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Titanium.Web.Proxy.Examples.Wpf namespace Titanium.Web.Proxy.Examples.Wpf
{ {
/// <summary> /// <summary>
/// Interaction logic for App.xaml /// Interaction logic for App.xaml
/// </summary> /// </summary>
public partial class App : Application public partial class App : Application
{ {
......
...@@ -6,50 +6,51 @@ ...@@ -6,50 +6,51 @@
xmlns:local="clr-namespace:Titanium.Web.Proxy.Examples.Wpf" xmlns:local="clr-namespace:Titanium.Web.Proxy.Examples.Wpf"
mc:Ignorable="d" mc:Ignorable="d"
Title="MainWindow" Height="500" Width="1000" WindowState="Maximized" Title="MainWindow" Height="500" Width="1000" WindowState="Maximized"
DataContext="{Binding RelativeSource={RelativeSource Self}}"> DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="500" /> <ColumnDefinition Width="500" />
<ColumnDefinition Width="3" /> <ColumnDefinition Width="3" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<GridSplitter Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" />
<ListView Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" ItemsSource="{Binding Sessions}" SelectedItem="{Binding SelectedSession}" <ListView Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" ItemsSource="{Binding Sessions}"
KeyDown="ListViewSessions_OnKeyDown"> SelectedItem="{Binding SelectedSession}"
<ListView.View> KeyDown="ListViewSessions_OnKeyDown">
<GridView> <ListView.View>
<GridViewColumn Header="Result" DisplayMemberBinding="{Binding StatusCode}" /> <GridView>
<GridViewColumn Header="Protocol" DisplayMemberBinding="{Binding Protocol}" /> <GridViewColumn Header="Result" DisplayMemberBinding="{Binding StatusCode}" />
<GridViewColumn Header="Host" DisplayMemberBinding="{Binding Host}" /> <GridViewColumn Header="Protocol" DisplayMemberBinding="{Binding Protocol}" />
<GridViewColumn Header="Url" DisplayMemberBinding="{Binding Url}" /> <GridViewColumn Header="Host" DisplayMemberBinding="{Binding Host}" />
<GridViewColumn Header="BodySize" DisplayMemberBinding="{Binding BodySize}" /> <GridViewColumn Header="Url" DisplayMemberBinding="{Binding Url}" />
<GridViewColumn Header="Process" DisplayMemberBinding="{Binding Process}" /> <GridViewColumn Header="BodySize" DisplayMemberBinding="{Binding BodySize}" />
<GridViewColumn Header="SentBytes" DisplayMemberBinding="{Binding SentDataCount}" /> <GridViewColumn Header="Process" DisplayMemberBinding="{Binding Process}" />
<GridViewColumn Header="ReceivedBytes" DisplayMemberBinding="{Binding ReceivedDataCount}" /> <GridViewColumn Header="SentBytes" DisplayMemberBinding="{Binding SentDataCount}" />
</GridView> <GridViewColumn Header="ReceivedBytes" DisplayMemberBinding="{Binding ReceivedDataCount}" />
</ListView.View> </GridView>
</ListView> </ListView.View>
<TabControl Grid.Column="2" Grid.Row="0"> </ListView>
<TabItem Header="Session"> <TabControl Grid.Column="2" Grid.Row="0">
<Grid Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <TabItem Header="Session">
<Grid.RowDefinitions> <Grid Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RowDefinition /> <Grid.RowDefinitions>
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> <RowDefinition />
<TextBox x:Name="TextBoxRequest" Grid.Row="0" /> </Grid.RowDefinitions>
<TextBox x:Name="TextBoxResponse" Grid.Row="1" /> <TextBox x:Name="TextBoxRequest" Grid.Row="0" />
</Grid> <TextBox x:Name="TextBoxResponse" Grid.Row="1" />
</TabItem> </Grid>
</TabControl> </TabItem>
<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal"> </TabControl>
<TextBlock Text="ClientConnectionCount:" /> <StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
<TextBlock Text="{Binding ClientConnectionCount}" Margin="10,0,20,0" /> <TextBlock Text="ClientConnectionCount:" />
<TextBlock Text="ServerConnectionCount:" /> <TextBlock Text="{Binding ClientConnectionCount}" Margin="10,0,20,0" />
<TextBlock Text="{Binding ServerConnectionCount}" Margin="10,0,20,0" /> <TextBlock Text="ServerConnectionCount:" />
</StackPanel> <TextBlock Text="{Binding ServerConnectionCount}" Margin="10,0,20,0" />
</StackPanel>
</Grid> </Grid>
</Window> </Window>
\ No newline at end of file
...@@ -16,48 +16,22 @@ using Titanium.Web.Proxy.Models; ...@@ -16,48 +16,22 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Examples.Wpf namespace Titanium.Web.Proxy.Examples.Wpf
{ {
/// <summary> /// <summary>
/// Interaction logic for MainWindow.xaml /// Interaction logic for MainWindow.xaml
/// </summary> /// </summary>
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
private readonly ProxyServer proxyServer;
private int lastSessionNumber;
public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public SessionListItem SelectedSession
{
get => selectedSession;
set
{
if (value != selectedSession)
{
selectedSession = value;
SelectedSessionChanged();
}
}
}
public static readonly DependencyProperty ClientConnectionCountProperty = DependencyProperty.Register( public static readonly DependencyProperty ClientConnectionCountProperty = DependencyProperty.Register(
nameof(ClientConnectionCount), typeof(int), typeof(MainWindow), new PropertyMetadata(default(int))); nameof(ClientConnectionCount), typeof(int), typeof(MainWindow), new PropertyMetadata(default(int)));
public int ClientConnectionCount
{
get => (int)GetValue(ClientConnectionCountProperty);
set => SetValue(ClientConnectionCountProperty, value);
}
public static readonly DependencyProperty ServerConnectionCountProperty = DependencyProperty.Register( public static readonly DependencyProperty ServerConnectionCountProperty = DependencyProperty.Register(
nameof(ServerConnectionCount), typeof(int), typeof(MainWindow), new PropertyMetadata(default(int))); nameof(ServerConnectionCount), typeof(int), typeof(MainWindow), new PropertyMetadata(default(int)));
public int ServerConnectionCount private readonly ProxyServer proxyServer;
{
get => (int)GetValue(ServerConnectionCountProperty); private readonly Dictionary<HttpWebClient, SessionListItem> sessionDictionary =
set => SetValue(ServerConnectionCountProperty, value); new Dictionary<HttpWebClient, SessionListItem>();
}
private readonly Dictionary<HttpWebClient, SessionListItem> sessionDictionary = new Dictionary<HttpWebClient, SessionListItem>(); private int lastSessionNumber;
private SessionListItem selectedSession; private SessionListItem selectedSession;
public MainWindow() public MainWindow()
...@@ -90,7 +64,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -90,7 +64,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
//proxyServer.CertificateManager.LoadRootCertificate(@"C:\NameFolder\rootCert.pfx", "PfxPassword"); //proxyServer.CertificateManager.LoadRootCertificate(@"C:\NameFolder\rootCert.pfx", "PfxPassword");
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true); var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);
proxyServer.AddEndPoint(explicitEndPoint); proxyServer.AddEndPoint(explicitEndPoint);
//proxyServer.UpStreamHttpProxy = new ExternalProxy //proxyServer.UpStreamHttpProxy = new ExternalProxy
//{ //{
...@@ -105,8 +79,14 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -105,8 +79,14 @@ namespace Titanium.Web.Proxy.Examples.Wpf
proxyServer.AfterResponse += ProxyServer_AfterResponse; proxyServer.AfterResponse += ProxyServer_AfterResponse;
explicitEndPoint.BeforeTunnelConnectRequest += ProxyServer_BeforeTunnelConnectRequest; explicitEndPoint.BeforeTunnelConnectRequest += ProxyServer_BeforeTunnelConnectRequest;
explicitEndPoint.BeforeTunnelConnectResponse += ProxyServer_BeforeTunnelConnectResponse; explicitEndPoint.BeforeTunnelConnectResponse += ProxyServer_BeforeTunnelConnectResponse;
proxyServer.ClientConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; }); }; proxyServer.ClientConnectionCountChanged += delegate
proxyServer.ServerConnectionCountChanged += delegate { Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; }); }; {
Dispatcher.Invoke(() => { ClientConnectionCount = proxyServer.ClientConnectionCount; });
};
proxyServer.ServerConnectionCountChanged += delegate
{
Dispatcher.Invoke(() => { ServerConnectionCount = proxyServer.ServerConnectionCount; });
};
proxyServer.Start(); proxyServer.Start();
proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp); proxyServer.SetAsSystemProxy(explicitEndPoint, ProxyProtocolType.AllHttp);
...@@ -114,6 +94,33 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -114,6 +94,33 @@ namespace Titanium.Web.Proxy.Examples.Wpf
InitializeComponent(); InitializeComponent();
} }
public ObservableCollection<SessionListItem> Sessions { get; } = new ObservableCollection<SessionListItem>();
public SessionListItem SelectedSession
{
get => selectedSession;
set
{
if (value != selectedSession)
{
selectedSession = value;
SelectedSessionChanged();
}
}
}
public int ClientConnectionCount
{
get => (int)GetValue(ClientConnectionCountProperty);
set => SetValue(ClientConnectionCountProperty, value);
}
public int ServerConnectionCount
{
get => (int)GetValue(ServerConnectionCountProperty);
set => SetValue(ServerConnectionCountProperty, value);
}
private async Task ProxyServer_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e) private async Task ProxyServer_BeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)
{ {
string hostname = e.WebSession.Request.RequestUri.Host; string hostname = e.WebSession.Request.RequestUri.Host;
...@@ -122,10 +129,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -122,10 +129,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
e.DecryptSsl = false; e.DecryptSsl = false;
} }
await Dispatcher.InvokeAsync(() => await Dispatcher.InvokeAsync(() => { AddSession(e); });
{
AddSession(e);
});
} }
private async Task ProxyServer_BeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e) private async Task ProxyServer_BeforeTunnelConnectResponse(object sender, TunnelConnectSessionEventArgs e)
...@@ -142,10 +146,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -142,10 +146,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e) private async Task ProxyServer_BeforeRequest(object sender, SessionEventArgs e)
{ {
SessionListItem item = null; SessionListItem item = null;
await Dispatcher.InvokeAsync(() => await Dispatcher.InvokeAsync(() => { item = AddSession(e); });
{
item = AddSession(e);
});
if (e.WebSession.Request.HasBody) if (e.WebSession.Request.HasBody)
{ {
...@@ -172,10 +173,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -172,10 +173,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
e.WebSession.Response.KeepBody = true; e.WebSession.Response.KeepBody = true;
await e.GetResponseBody(); await e.GetResponseBody();
await Dispatcher.InvokeAsync(() => await Dispatcher.InvokeAsync(() => { item.Update(); });
{
item.Update();
});
} }
} }
} }
...@@ -207,7 +205,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -207,7 +205,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{ {
Number = lastSessionNumber, Number = lastSessionNumber,
WebSession = e.WebSession, WebSession = e.WebSession,
IsTunnelConnect = isTunnelConnect, IsTunnelConnect = isTunnelConnect
}; };
if (isTunnelConnect || e.WebSession.Request.UpgradeToWebSocket) if (isTunnelConnect || e.WebSession.Request.UpgradeToWebSocket)
......
using System.Reflection; using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Windows; using System.Windows;
...@@ -33,11 +31,11 @@ using System.Windows; ...@@ -33,11 +31,11 @@ using System.Windows;
[assembly: ThemeInfo( [assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page, //(used if a resource is not found in the page,
// or application resource dictionaries) // or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page, //(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries) // app, or any theme specific resource dictionaries)
)] )]
......
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> <SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles> <Profiles>
<Profile Name="(Default)" /> <Profile Name="(Default)" />
......
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Examples.Wpf.Annotations; using Titanium.Web.Proxy.Examples.Wpf.Annotations;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
...@@ -9,15 +8,15 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -9,15 +8,15 @@ namespace Titanium.Web.Proxy.Examples.Wpf
{ {
public class SessionListItem : INotifyPropertyChanged public class SessionListItem : INotifyPropertyChanged
{ {
private string statusCode;
private string protocol;
private string host;
private string url;
private long? bodySize; private long? bodySize;
private Exception exception;
private string host;
private string process; private string process;
private string protocol;
private long receivedDataCount; private long receivedDataCount;
private long sentDataCount; private long sentDataCount;
private Exception exception; private string statusCode;
private string url;
public int Number { get; set; } public int Number { get; set; }
...@@ -81,7 +80,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -81,7 +80,7 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected void SetField<T>(ref T field, T value,[CallerMemberName] string propertyName = null) protected void SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{ {
if (!Equals(field, value)) if (!Equals(field, value))
{ {
......
...@@ -51,8 +51,8 @@ ...@@ -51,8 +51,8 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="StreamExtended, Version=1.0.141.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL"> <Reference Include="StreamExtended, Version=1.0.147.0, Culture=neutral, PublicKeyToken=bbfa0f1d54f50043, processorArchitecture=MSIL">
<HintPath>..\..\packages\StreamExtended.1.0.141-beta\lib\net45\StreamExtended.dll</HintPath> <HintPath>..\..\packages\StreamExtended.1.0.147-beta\lib\net45\StreamExtended.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="StreamExtended" version="1.0.141-beta" targetFramework="net45" /> <package id="StreamExtended" version="1.0.147-beta" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
var handler = new HttpClientHandler var handler = new HttpClientHandler
{ {
Proxy = new WebProxy($"http://localhost:{localProxyPort}", false), Proxy = new WebProxy($"http://localhost:{localProxyPort}", false),
UseProxy = true, UseProxy = true
}; };
var client = new HttpClient(handler); var client = new HttpClient(handler);
...@@ -68,8 +68,10 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -68,8 +68,10 @@ namespace Titanium.Web.Proxy.IntegrationTests
proxyServer.Start(); proxyServer.Start();
foreach (var endPoint in proxyServer.ProxyEndPoints) foreach (var endPoint in proxyServer.ProxyEndPoints)
{
Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ", Console.WriteLine("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port); endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);
}
} }
public void Stop() public void Stop()
...@@ -96,7 +98,7 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -96,7 +98,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
} }
/// <summary> /// <summary>
/// Allows overriding default certificate validation logic /// Allows overriding default certificate validation logic
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
...@@ -112,7 +114,7 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -112,7 +114,7 @@ namespace Titanium.Web.Proxy.IntegrationTests
} }
/// <summary> /// <summary>
/// Allows overriding default client certificate selection logic during mutual authentication /// Allows overriding default client certificate selection logic during mutual authentication
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
......
...@@ -27,6 +27,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -27,6 +27,7 @@ namespace Titanium.Web.Proxy.UnitTests
mgr.CertificateEngine = CertificateEngine.BouncyCastle; mgr.CertificateEngine = CertificateEngine.BouncyCastle;
mgr.ClearIdleCertificates(); mgr.ClearIdleCertificates();
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{
foreach (string host in hostNames) foreach (string host in hostNames)
{ {
tasks.Add(Task.Run(() => tasks.Add(Task.Run(() =>
...@@ -36,6 +37,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -36,6 +37,7 @@ namespace Titanium.Web.Proxy.UnitTests
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
})); }));
} }
}
await Task.WhenAll(tasks.ToArray()); await Task.WhenAll(tasks.ToArray());
...@@ -59,6 +61,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -59,6 +61,7 @@ namespace Titanium.Web.Proxy.UnitTests
mgr.ClearIdleCertificates(); mgr.ClearIdleCertificates();
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{
foreach (string host in hostNames) foreach (string host in hostNames)
{ {
tasks.Add(Task.Run(() => tasks.Add(Task.Run(() =>
...@@ -68,6 +71,7 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -68,6 +71,7 @@ namespace Titanium.Web.Proxy.UnitTests
Assert.IsNotNull(certificate); Assert.IsNotNull(certificate);
})); }));
} }
}
await Task.WhenAll(tasks.ToArray()); await Task.WhenAll(tasks.ToArray());
mgr.RemoveTrustedRootCertificate(true); mgr.RemoveTrustedRootCertificate(true);
......
...@@ -9,7 +9,8 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -9,7 +9,8 @@ namespace Titanium.Web.Proxy.UnitTests
public class ProxyServerTests public class ProxyServerTests
{ {
[TestMethod] [TestMethod]
public void GivenOneEndpointIsAlreadyAddedToAddress_WhenAddingNewEndpointToExistingAddress_ThenExceptionIsThrown() public void
GivenOneEndpointIsAlreadyAddedToAddress_WhenAddingNewEndpointToExistingAddress_ThenExceptionIsThrown()
{ {
// Arrange // Arrange
var proxy = new ProxyServer(); var proxy = new ProxyServer();
...@@ -34,7 +35,8 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -34,7 +35,8 @@ namespace Titanium.Web.Proxy.UnitTests
} }
[TestMethod] [TestMethod]
public void GivenOneEndpointIsAlreadyAddedToAddress_WhenAddingNewEndpointToExistingAddress_ThenTwoEndpointsExists() public void
GivenOneEndpointIsAlreadyAddedToAddress_WhenAddingNewEndpointToExistingAddress_ThenTwoEndpointsExists()
{ {
// Arrange // Arrange
var proxy = new ProxyServer(); var proxy = new ProxyServer();
...@@ -74,7 +76,8 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -74,7 +76,8 @@ namespace Titanium.Web.Proxy.UnitTests
} }
[TestMethod] [TestMethod]
public void GivenOneEndpointIsAlreadyAddedToZeroPort_WhenAddingNewEndpointToExistingPort_ThenTwoEndpointsExists() public void
GivenOneEndpointIsAlreadyAddedToZeroPort_WhenAddingNewEndpointToExistingPort_ThenTwoEndpointsExists()
{ {
// Arrange // Arrange
var proxy = new ProxyServer(); var proxy = new ProxyServer();
......
...@@ -85,7 +85,9 @@ namespace Titanium.Web.Proxy.UnitTests ...@@ -85,7 +85,9 @@ namespace Titanium.Web.Proxy.UnitTests
{ {
hostName = Dns.GetHostName(); hostName = Dns.GetHostName();
} }
catch{} catch
{
}
if (hostName != null) if (hostName != null)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">160</s:Int64> <s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">120</s:Int64>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVar</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseVar</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BC/@EntryIndexedValue">BC</s:String>
......
...@@ -9,14 +9,15 @@ namespace Titanium.Web.Proxy ...@@ -9,14 +9,15 @@ namespace Titanium.Web.Proxy
public partial class ProxyServer public partial class ProxyServer
{ {
/// <summary> /// <summary>
/// Call back to override server certificate validation /// Call back to override server certificate validation
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="certificate"></param> /// <param name="certificate"></param>
/// <param name="chain"></param> /// <param name="chain"></param>
/// <param name="sslPolicyErrors"></param> /// <param name="sslPolicyErrors"></param>
/// <returns></returns> /// <returns></returns>
internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) internal bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{ {
//if user callback is registered then do it //if user callback is registered then do it
if (ServerCertificateValidationCallback != null) if (ServerCertificateValidationCallback != null)
...@@ -44,7 +45,7 @@ namespace Titanium.Web.Proxy ...@@ -44,7 +45,7 @@ namespace Titanium.Web.Proxy
} }
/// <summary> /// <summary>
/// Call back to select client certificate used for mutual authentication /// Call back to select client certificate used for mutual authentication
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="targetHost"></param> /// <param name="targetHost"></param>
...@@ -52,14 +53,15 @@ namespace Titanium.Web.Proxy ...@@ -52,14 +53,15 @@ namespace Titanium.Web.Proxy
/// <param name="remoteCertificate"></param> /// <param name="remoteCertificate"></param>
/// <param name="acceptableIssuers"></param> /// <param name="acceptableIssuers"></param>
/// <returns></returns> /// <returns></returns>
internal X509Certificate SelectClientCertificate(object sender, string targetHost, X509CertificateCollection localCertificates, internal X509Certificate SelectClientCertificate(object sender, string targetHost,
X509CertificateCollection localCertificates,
X509Certificate remoteCertificate, string[] acceptableIssuers) X509Certificate remoteCertificate, string[] acceptableIssuers)
{ {
X509Certificate clientCertificate = null; X509Certificate clientCertificate = null;
if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null && localCertificates.Count > 0) if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null &&
localCertificates.Count > 0)
{ {
// Use the first certificate that is from an acceptable issuer.
foreach (var certificate in localCertificates) foreach (var certificate in localCertificates)
{ {
string issuer = certificate.Issuer; string issuer = certificate.Issuer;
......
...@@ -4,22 +4,22 @@ using Titanium.Web.Proxy.Http; ...@@ -4,22 +4,22 @@ using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// A factory to generate the compression methods based on the type of compression /// A factory to generate the compression methods based on the type of compression
/// </summary> /// </summary>
internal static class CompressionFactory internal static class CompressionFactory
{ {
//cache //cache
private static readonly Lazy<ICompression> gzip = new Lazy<ICompression>(() => new GZipCompression()); private static readonly ICompression gzip = new GZipCompression();
private static readonly Lazy<ICompression> deflate = new Lazy<ICompression>(() => new DeflateCompression()); private static readonly ICompression deflate = new DeflateCompression();
public static ICompression GetCompression(string type) public static ICompression GetCompression(string type)
{ {
switch (type) switch (type)
{ {
case KnownHeaders.ContentEncodingGzip: case KnownHeaders.ContentEncodingGzip:
return gzip.Value; return gzip;
case KnownHeaders.ContentEncodingDeflate: case KnownHeaders.ContentEncodingDeflate:
return deflate.Value; return deflate;
default: default:
throw new Exception($"Unsupported compression mode: {type}"); throw new Exception($"Unsupported compression mode: {type}");
} }
......
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// Concrete implementation of deflate compression /// Concrete implementation of deflate compression
/// </summary> /// </summary>
internal class DeflateCompression : ICompression internal class DeflateCompression : ICompression
{ {
......
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// concreate implementation of gzip compression /// concreate implementation of gzip compression
/// </summary> /// </summary>
internal class GZipCompression : ICompression internal class GZipCompression : ICompression
{ {
......
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Compression namespace Titanium.Web.Proxy.Compression
{ {
/// <summary> /// <summary>
/// An inteface for http compression /// An inteface for http compression
/// </summary> /// </summary>
interface ICompression internal interface ICompression
{ {
Stream GetStream(Stream stream); Stream GetStream(Stream stream);
} }
......
...@@ -4,22 +4,23 @@ using Titanium.Web.Proxy.Http; ...@@ -4,22 +4,23 @@ using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// A factory to generate the de-compression methods based on the type of compression /// A factory to generate the de-compression methods based on the type of compression
/// </summary> /// </summary>
internal class DecompressionFactory internal class DecompressionFactory
{ {
//cache //cache
private static readonly Lazy<IDecompression> gzip = new Lazy<IDecompression>(() => new GZipDecompression()); private static readonly IDecompression gzip = new GZipDecompression();
private static readonly Lazy<IDecompression> deflate = new Lazy<IDecompression>(() => new DeflateDecompression());
private static readonly IDecompression deflate = new DeflateDecompression();
public static IDecompression Create(string type) public static IDecompression Create(string type)
{ {
switch (type) switch (type)
{ {
case KnownHeaders.ContentEncodingGzip: case KnownHeaders.ContentEncodingGzip:
return gzip.Value; return gzip;
case KnownHeaders.ContentEncodingDeflate: case KnownHeaders.ContentEncodingDeflate:
return deflate.Value; return deflate;
default: default:
throw new Exception($"Unsupported decompression mode: {type}"); throw new Exception($"Unsupported decompression mode: {type}");
} }
......
using StreamExtended.Helpers; using System.IO;
using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// concrete implementation of deflate de-compression /// concrete implementation of deflate de-compression
/// </summary> /// </summary>
internal class DeflateDecompression : IDecompression internal class DeflateDecompression : IDecompression
{ {
......
using StreamExtended.Helpers; using System.IO;
using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// concrete implementation of gzip de-compression /// concrete implementation of gzip de-compression
/// </summary> /// </summary>
internal class GZipDecompression : IDecompression internal class GZipDecompression : IDecompression
{ {
......
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
/// <summary> /// <summary>
/// An interface for decompression /// An interface for decompression
/// </summary> /// </summary>
internal interface IDecompression internal interface IDecompression
{ {
......
using System; using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e); public delegate Task AsyncEventHandler<in TEventArgs>(object sender, TEventArgs e);
} }
\ No newline at end of file
using System;
using System.Threading;
namespace Titanium.Web.Proxy.EventArguments
{
public class BeforeSslAuthenticateEventArgs : EventArgs
{
internal readonly CancellationTokenSource TaskCancellationSource;
internal BeforeSslAuthenticateEventArgs(CancellationTokenSource taskCancellationSource)
{
TaskCancellationSource = taskCancellationSource;
}
public string SniHostName { get; internal set; }
public bool DecryptSsl { get; set; } = true;
public void TerminateSession()
{
TaskCancellationSource.Cancel();
}
}
}
...@@ -4,37 +4,37 @@ using System.Security.Cryptography.X509Certificates; ...@@ -4,37 +4,37 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary> /// <summary>
/// An argument passed on to user for client certificate selection during mutual SSL authentication /// An argument passed on to user for client certificate selection during mutual SSL authentication
/// </summary> /// </summary>
public class CertificateSelectionEventArgs : EventArgs public class CertificateSelectionEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Sender object. /// Sender object.
/// </summary> /// </summary>
public object Sender { get; internal set; } public object Sender { get; internal set; }
/// <summary> /// <summary>
/// Target host. /// Target host.
/// </summary> /// </summary>
public string TargetHost { get; internal set; } public string TargetHost { get; internal set; }
/// <summary> /// <summary>
/// Local certificates. /// Local certificates.
/// </summary> /// </summary>
public X509CertificateCollection LocalCertificates { get; internal set; } public X509CertificateCollection LocalCertificates { get; internal set; }
/// <summary> /// <summary>
/// Remote certificate. /// Remote certificate.
/// </summary> /// </summary>
public X509Certificate RemoteCertificate { get; internal set; } public X509Certificate RemoteCertificate { get; internal set; }
/// <summary> /// <summary>
/// Acceptable issuers. /// Acceptable issuers.
/// </summary> /// </summary>
public string[] AcceptableIssuers { get; internal set; } public string[] AcceptableIssuers { get; internal set; }
/// <summary> /// <summary>
/// Client Certificate. /// Client Certificate.
/// </summary> /// </summary>
public X509Certificate ClientCertificate { get; set; } public X509Certificate ClientCertificate { get; set; }
} }
......
...@@ -5,27 +5,27 @@ using System.Security.Cryptography.X509Certificates; ...@@ -5,27 +5,27 @@ using System.Security.Cryptography.X509Certificates;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary> /// <summary>
/// An argument passed on to the user for validating the server certificate during SSL authentication /// An argument passed on to the user for validating the server certificate during SSL authentication
/// </summary> /// </summary>
public class CertificateValidationEventArgs : EventArgs public class CertificateValidationEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Certificate /// Certificate
/// </summary> /// </summary>
public X509Certificate Certificate { get; internal set; } public X509Certificate Certificate { get; internal set; }
/// <summary> /// <summary>
/// Certificate chain /// Certificate chain
/// </summary> /// </summary>
public X509Chain Chain { get; internal set; } public X509Chain Chain { get; internal set; }
/// <summary> /// <summary>
/// SSL policy errors. /// SSL policy errors.
/// </summary> /// </summary>
public SslPolicyErrors SslPolicyErrors { get; internal set; } public SslPolicyErrors SslPolicyErrors { get; internal set; }
/// <summary> /// <summary>
/// is a valid certificate? /// is a valid certificate?
/// </summary> /// </summary>
public bool IsValid { get; set; } public bool IsValid { get; set; }
} }
......
...@@ -4,17 +4,17 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -4,17 +4,17 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class DataEventArgs : EventArgs public class DataEventArgs : EventArgs
{ {
public byte[] Buffer { get; } internal DataEventArgs(byte[] buffer, int offset, int count)
public int Offset { get; }
public int Count { get; }
public DataEventArgs(byte[] buffer, int offset, int count)
{ {
Buffer = buffer; Buffer = buffer;
Offset = offset; Offset = offset;
Count = count; Count = count;
} }
public byte[] Buffer { get; }
public int Offset { get; }
public int Count { get; }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -10,25 +9,40 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -10,25 +9,40 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
internal class LimitedStream : Stream internal class LimitedStream : Stream
{ {
private readonly CustomBufferedStream baseStream;
private readonly CustomBinaryReader baseReader; private readonly CustomBinaryReader baseReader;
private readonly CustomBufferedStream baseStream;
private readonly bool isChunked; private readonly bool isChunked;
private long bytesRemaining;
private bool readChunkTrail; private bool readChunkTrail;
private long bytesRemaining;
public LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked, long contentLength) internal LimitedStream(CustomBufferedStream baseStream, CustomBinaryReader baseReader, bool isChunked,
long contentLength)
{ {
this.baseStream = baseStream; this.baseStream = baseStream;
this.baseReader = baseReader; this.baseReader = baseReader;
this.isChunked = isChunked; this.isChunked = isChunked;
bytesRemaining = isChunked bytesRemaining = isChunked
? 0 ? 0
: contentLength == -1 : contentLength == -1
? long.MaxValue ? long.MaxValue
: contentLength; : contentLength;
} }
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
private void GetNextChunk() private void GetNextChunk()
{ {
if (readChunkTrail) if (readChunkTrail)
...@@ -43,7 +57,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -43,7 +57,6 @@ namespace Titanium.Web.Proxy.EventArguments
int idx = chunkHead.IndexOf(";"); int idx = chunkHead.IndexOf(";");
if (idx >= 0) if (idx >= 0)
{ {
// remove chunk extension
chunkHead = chunkHead.Substring(0, idx); chunkHead = chunkHead.Substring(0, idx);
} }
...@@ -134,19 +147,5 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -134,19 +147,5 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
} }
} }
...@@ -5,14 +5,14 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -5,14 +5,14 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class MultipartRequestPartSentEventArgs : EventArgs public class MultipartRequestPartSentEventArgs : EventArgs
{ {
public string Boundary { get; }
public HeaderCollection Headers { get; }
public MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers) public MultipartRequestPartSentEventArgs(string boundary, HeaderCollection headers)
{ {
Boundary = boundary; Boundary = boundary;
Headers = headers; Headers = headers;
} }
public string Boundary { get; }
public HeaderCollection Headers { get; }
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net; using System.Net;
using System.Reflection; using System.Threading;
using System.Threading.Tasks;
using StreamExtended.Helpers;
using StreamExtended.Network;
using Titanium.Web.Proxy.Decompression;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Http.Responses;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network; using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.EventArguments namespace Titanium.Web.Proxy.EventArguments
{ {
/// <summary> /// <summary>
/// Holds info related to a single proxy session (single request/response sequence) /// Holds info related to a single proxy session (single request/response sequence)
/// A proxy session is bounded to a single connection from client /// A proxy session is bounded to a single connection from client
/// A proxy session ends when client terminates connection to proxy /// A proxy session ends when client terminates connection to proxy
/// or when server terminates connection from proxy /// or when server terminates connection from proxy
/// </summary> /// </summary>
public class SessionEventArgsBase : EventArgs, IDisposable public abstract class SessionEventArgsBase : EventArgs, IDisposable
{ {
/// <summary> /// <summary>
/// Size of Buffers used by this object /// Size of Buffers used by this object
/// </summary> /// </summary>
protected readonly int BufferSize; protected readonly int BufferSize;
protected readonly ExceptionHandler ExceptionFunc; protected readonly ExceptionHandler ExceptionFunc;
internal readonly CancellationTokenSource CancellationTokenSource;
/// <summary> /// <summary>
/// Holds a reference to client /// Constructor to initialize the proxy
/// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: this(bufferSize, endPoint, cancellationTokenSource, null, exceptionFunc)
{
}
protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint,
CancellationTokenSource cancellationTokenSource,
Request request, ExceptionHandler exceptionFunc)
{
BufferSize = bufferSize;
ExceptionFunc = exceptionFunc;
CancellationTokenSource = cancellationTokenSource;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() =>
{
if (RunTime.IsWindows)
{
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address))
{
var ipVersion = endPoint.IpV6Enabled ? IpVersion.Ipv6 : IpVersion.Ipv4;
return TcpHelper.GetProcessIdByLocalPort(ipVersion, remoteEndPoint.Port);
}
//can't access process Id of remote request from remote machine
return -1;
}
throw new PlatformNotSupportedException();
});
}
/// <summary>
/// Holds a reference to client
/// </summary> /// </summary>
internal ProxyClient ProxyClient { get; } internal ProxyClient ProxyClient { get; }
/// <summary> /// <summary>
/// Returns a unique Id for this request/response session /// Returns a unique Id for this request/response session
/// same as RequestId of WebSession /// same as RequestId of WebSession
/// </summary> /// </summary>
public Guid Id => WebSession.RequestId; public Guid Id => WebSession.RequestId;
/// <summary> /// <summary>
/// Does this session uses SSL /// Does this session uses SSL
/// </summary> /// </summary>
public bool IsHttps => WebSession.Request.IsHttps; public bool IsHttps => WebSession.Request.IsHttps;
/// <summary> /// <summary>
/// Client End Point. /// Client End Point.
/// </summary> /// </summary>
public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint; public IPEndPoint ClientEndPoint => (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
/// <summary> /// <summary>
/// A web session corresponding to a single request/response sequence /// A web session corresponding to a single request/response sequence
/// within a proxy connection /// within a proxy connection
/// </summary> /// </summary>
public HttpWebClient WebSession { get; } public HttpWebClient WebSession { get; }
/// <summary> /// <summary>
/// Are we using a custom upstream HTTP(S) proxy? /// Are we using a custom upstream HTTP(S) proxy?
/// </summary> /// </summary>
public ExternalProxy CustomUpStreamProxyUsed { get; internal set; } public ExternalProxy CustomUpStreamProxyUsed { get; internal set; }
public event EventHandler<DataEventArgs> DataSent;
public event EventHandler<DataEventArgs> DataReceived;
public ProxyEndPoint LocalEndPoint { get; } public ProxyEndPoint LocalEndPoint { get; }
public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint; public bool IsTransparent => LocalEndPoint is TransparentProxyEndPoint;
...@@ -74,41 +106,22 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -74,41 +106,22 @@ namespace Titanium.Web.Proxy.EventArguments
public Exception Exception { get; internal set; } public Exception Exception { get; internal set; }
/// <summary> /// <summary>
/// Constructor to initialize the proxy /// implement any cleanup here
/// </summary> /// </summary>
internal SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, ExceptionHandler exceptionFunc) public virtual void Dispose()
: this(bufferSize, endPoint, exceptionFunc, null)
{
}
protected SessionEventArgsBase(int bufferSize, ProxyEndPoint endPoint, ExceptionHandler exceptionFunc, Request request)
{ {
this.BufferSize = bufferSize; CustomUpStreamProxyUsed = null;
this.ExceptionFunc = exceptionFunc;
ProxyClient = new ProxyClient();
WebSession = new HttpWebClient(bufferSize, request);
LocalEndPoint = endPoint;
WebSession.ProcessId = new Lazy<int>(() => DataSent = null;
{ DataReceived = null;
if (RunTime.IsWindows) Exception = null;
{
var remoteEndPoint = (IPEndPoint)ProxyClient.TcpClient.Client.RemoteEndPoint;
//If client is localhost get the process id WebSession.FinishSession();
if (NetworkHelper.IsLocalIpAddress(remoteEndPoint.Address)) }
{
return NetworkHelper.GetProcessIdFromPort(remoteEndPoint.Port, endPoint.IpV6Enabled);
}
//can't access process Id of remote request from remote machine public event EventHandler<DataEventArgs> DataSent;
return -1;
}
throw new PlatformNotSupportedException(); public event EventHandler<DataEventArgs> DataReceived;
});
}
internal void OnDataSent(byte[] buffer, int offset, int count) internal void OnDataSent(byte[] buffer, int offset, int count)
{ {
...@@ -135,17 +148,11 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -135,17 +148,11 @@ namespace Titanium.Web.Proxy.EventArguments
} }
/// <summary> /// <summary>
/// implement any cleanup here /// Terminates the session abruptly by terminating client/server connections
/// </summary> /// </summary>
public virtual void Dispose() public void TerminateSession()
{ {
CustomUpStreamProxyUsed = null; CancellationTokenSource.Cancel();
DataSent = null;
DataReceived = null;
Exception = null;
WebSession.FinishSession();
} }
} }
} }
using System; namespace Titanium.Web.Proxy.EventArguments
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.EventArguments
{ {
internal enum TransformationMode internal enum TransformationMode
{ {
None, None,
/// <summary> /// <summary>
/// Removes the chunked encoding /// Removes the chunked encoding
/// </summary> /// </summary>
RemoveChunked, RemoveChunked,
/// <summary> /// <summary>
/// Uncompress the body (this also removes the chunked encoding if exists) /// Uncompress the body (this also removes the chunked encoding if exists)
/// </summary> /// </summary>
Uncompress, Uncompress
} }
} }
using System; using System;
using System.Threading;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -6,15 +7,26 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -6,15 +7,26 @@ namespace Titanium.Web.Proxy.EventArguments
{ {
public class TunnelConnectSessionEventArgs : SessionEventArgsBase public class TunnelConnectSessionEventArgs : SessionEventArgsBase
{ {
public bool DecryptSsl { get; set; } = true; private bool? isHttpsConnect;
public bool BlockConnect { get; set; } internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest,
CancellationTokenSource cancellationTokenSource, ExceptionHandler exceptionFunc)
: base(bufferSize, endPoint, cancellationTokenSource, connectRequest, exceptionFunc)
{
WebSession.ConnectRequest = connectRequest;
}
public bool DecryptSsl { get; set; } = true;
public bool IsHttpsConnect { get; internal set; } /// <summary>
/// Denies the connect request with a Forbidden status
/// </summary>
public bool DenyConnect { get; set; }
internal TunnelConnectSessionEventArgs(int bufferSize, ProxyEndPoint endPoint, ConnectRequest connectRequest, ExceptionHandler exceptionFunc) public bool IsHttpsConnect
: base(bufferSize, endPoint, exceptionFunc, connectRequest)
{ {
get => isHttpsConnect ?? throw new Exception("The value of this property is known in the BeforeTunnectConnectResponse event");
internal set => isHttpsConnect = value;
} }
} }
} }
...@@ -3,4 +3,4 @@ using System; ...@@ -3,4 +3,4 @@ using System;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
public delegate void ExceptionHandler(Exception exception); public delegate void ExceptionHandler(Exception exception);
} }
\ No newline at end of file
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// An expception thrown when body is unexpectedly empty /// An expception thrown when body is unexpectedly empty
/// </summary> /// </summary>
public class BodyNotFoundException : ProxyException public class BodyNotFoundException : ProxyException
{ {
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="message"></param> /// <param name="message"></param>
internal BodyNotFoundException(string message) : base(message) internal BodyNotFoundException(string message) : base(message)
......
...@@ -6,18 +6,19 @@ using Titanium.Web.Proxy.Models; ...@@ -6,18 +6,19 @@ using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// Proxy authorization exception /// Proxy authorization exception
/// </summary> /// </summary>
public class ProxyAuthorizationException : ProxyException public class ProxyAuthorizationException : ProxyException
{ {
/// <summary> /// <summary>
/// Instantiate new instance /// Instantiate new instance
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
/// <param name="session">The <see cref="SessionEventArgs"/> instance containing the event data.</param> /// <param name="session">The <see cref="SessionEventArgs" /> instance containing the event data.</param>
/// <param name="innerException">Inner exception associated to upstream proxy authorization</param> /// <param name="innerException">Inner exception associated to upstream proxy authorization</param>
/// <param name="headers">Http's headers associated</param> /// <param name="headers">Http's headers associated</param>
internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException, IEnumerable<HttpHeader> headers) : base(message, innerException) internal ProxyAuthorizationException(string message, SessionEventArgsBase session, Exception innerException,
IEnumerable<HttpHeader> headers) : base(message, innerException)
{ {
Session = session; Session = session;
Headers = headers; Headers = headers;
...@@ -26,7 +27,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -26,7 +27,7 @@ namespace Titanium.Web.Proxy.Exceptions
public SessionEventArgsBase Session { get; } public SessionEventArgsBase Session { get; }
/// <summary> /// <summary>
/// Headers associated with the authorization exception /// Headers associated with the authorization exception
/// </summary> /// </summary>
public IEnumerable<HttpHeader> Headers { get; } public IEnumerable<HttpHeader> Headers { get; }
} }
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// Base class exception associated with this proxy implementation /// Base class exception associated with this proxy implementation
/// </summary> /// </summary>
public abstract class ProxyException : Exception public abstract class ProxyException : Exception
{ {
/// <summary> /// <summary>
/// Instantiate a new instance of this exception - must be invoked by derived classes' constructors /// Instantiate a new instance of this exception - must be invoked by derived classes' constructors
/// </summary> /// </summary>
/// <param name="message">Exception message</param> /// <param name="message">Exception message</param>
protected ProxyException(string message) : base(message) protected ProxyException(string message) : base(message)
...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -16,7 +16,7 @@ namespace Titanium.Web.Proxy.Exceptions
} }
/// <summary> /// <summary>
/// Instantiate this exception - must be invoked by derived classes' constructors /// Instantiate this exception - must be invoked by derived classes' constructors
/// </summary> /// </summary>
/// <param name="message">Excception message</param> /// <param name="message">Excception message</param>
/// <param name="innerException">Inner exception associated</param> /// <param name="innerException">Inner exception associated</param>
......
...@@ -4,26 +4,27 @@ using Titanium.Web.Proxy.EventArguments; ...@@ -4,26 +4,27 @@ using Titanium.Web.Proxy.EventArguments;
namespace Titanium.Web.Proxy.Exceptions namespace Titanium.Web.Proxy.Exceptions
{ {
/// <summary> /// <summary>
/// Proxy HTTP exception /// Proxy HTTP exception
/// </summary> /// </summary>
public class ProxyHttpException : ProxyException public class ProxyHttpException : ProxyException
{ {
/// <summary> /// <summary>
/// Instantiate new instance /// Instantiate new instance
/// </summary> /// </summary>
/// <param name="message">Message for this exception</param> /// <param name="message">Message for this exception</param>
/// <param name="innerException">Associated inner exception</param> /// <param name="innerException">Associated inner exception</param>
/// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs"/> associated to the exception</param> /// <param name="sessionEventArgs">Instance of <see cref="EventArguments.SessionEventArgs" /> associated to the exception</param>
internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(message, innerException) internal ProxyHttpException(string message, Exception innerException, SessionEventArgs sessionEventArgs) : base(
message, innerException)
{ {
SessionEventArgs = sessionEventArgs; SessionEventArgs = sessionEventArgs;
} }
/// <summary> /// <summary>
/// Gets session info associated to the exception /// Gets session info associated to the exception
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This object should not be edited /// This object should not be edited
/// </remarks> /// </remarks>
public SessionEventArgs SessionEventArgs { get; } public SessionEventArgs SessionEventArgs { get; }
} }
......
This diff is collapsed.
using System;
namespace Titanium.Web.Proxy.Extensions
{
/// <summary>
/// Extension methods for Byte Arrays.
/// </summary>
internal static class ByteArrayExtensions
{
/// <summary>
/// Get the sub array from byte of data
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
internal static T[] SubArray<T>(this T[] data, int index, int length)
{
var result = new T[length];
Array.Copy(data, index, result, 0, length);
return result;
}
}
}
...@@ -6,8 +6,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -6,8 +6,8 @@ namespace Titanium.Web.Proxy.Extensions
{ {
internal static class FuncExtensions internal static class FuncExtensions
{ {
public static async Task InvokeAsync<T>(this AsyncEventHandler<T> callback, object sender, T args,
public static async Task InvokeAsync<T>(this AsyncEventHandler<T> callback, object sender, T args, ExceptionHandler exceptionFunc) ExceptionHandler exceptionFunc)
{ {
var invocationList = callback.GetInvocationList(); var invocationList = callback.GetInvocationList();
...@@ -17,7 +17,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -17,7 +17,8 @@ namespace Titanium.Web.Proxy.Extensions
} }
} }
private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args, ExceptionHandler exceptionFunc) private static async Task InternalInvokeAsync<T>(AsyncEventHandler<T> callback, object sender, T args,
ExceptionHandler exceptionFunc)
{ {
try try
{ {
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended; using StreamExtended;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
static class SslExtensions internal static class SslExtensions
{ {
public static readonly List<SslApplicationProtocol> Http11ProtocolAsList = new List<SslApplicationProtocol> { SslApplicationProtocol.Http11 };
public static string GetServerName(this ClientHelloInfo clientHelloInfo) public static string GetServerName(this ClientHelloInfo clientHelloInfo)
{ {
if (clientHelloInfo.Extensions != null && clientHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension)) if (clientHelloInfo.Extensions != null &&
clientHelloInfo.Extensions.TryGetValue("server_name", out var serverNameExtension))
{ {
return serverNameExtension.Data; return serverNameExtension.Data;
} }
return null; return null;
} }
#if NETCOREAPP2_1
public static List<SslApplicationProtocol> GetAlpn(this ClientHelloInfo clientHelloInfo)
{
if (clientHelloInfo.Extensions != null && clientHelloInfo.Extensions.TryGetValue("ALPN", out var alpnExtension))
{
var alpn = alpnExtension.Data.Split(',');
if (alpn.Length != 0)
{
var result = new List<SslApplicationProtocol>(alpn.Length);
foreach (string p in alpn)
{
string protocol = p.Trim();
if (protocol.Equals("http/1.1"))
{
result.Add(SslApplicationProtocol.Http11);
}
else if (protocol.Equals("h2"))
{
result.Add(SslApplicationProtocol.Http2);
}
}
return result;
}
}
return null;
}
#else
public static List<SslApplicationProtocol> GetAlpn(this ClientHelloInfo clientHelloInfo)
{
return Http11ProtocolAsList;
}
public static Task AuthenticateAsClientAsync(this SslStream sslStream, SslClientAuthenticationOptions option, CancellationToken token)
{
return sslStream.AuthenticateAsClientAsync(option.TargetHost, option.ClientCertificates, option.EnabledSslProtocols, option.CertificateRevocationCheckMode != X509RevocationMode.NoCheck);
}
public static Task AuthenticateAsServerAsync(this SslStream sslStream, SslServerAuthenticationOptions options, CancellationToken token)
{
return sslStream.AuthenticateAsServerAsync(options.ServerCertificate, options.ClientCertificateRequired, options.EnabledSslProtocols, options.CertificateRevocationCheckMode != X509RevocationMode.NoCheck);
}
#endif
}
#if !NETCOREAPP2_1
public enum SslApplicationProtocol
{
Http11, Http2
}
public class SslClientAuthenticationOptions
{
public bool AllowRenegotiation { get; set; }
public string TargetHost { get; set; }
public X509CertificateCollection ClientCertificates { get; set; }
public LocalCertificateSelectionCallback LocalCertificateSelectionCallback { get; set; }
public SslProtocols EnabledSslProtocols { get; set; }
public X509RevocationMode CertificateRevocationCheckMode { get; set; }
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
public EncryptionPolicy EncryptionPolicy { get; set; }
}
public class SslServerAuthenticationOptions
{
public bool AllowRenegotiation { get; set; }
public X509Certificate ServerCertificate { get; set; }
public bool ClientCertificateRequired { get; set; }
public SslProtocols EnabledSslProtocols { get; set; }
public X509RevocationMode CertificateRevocationCheckMode { get; set; }
public List<SslApplicationProtocol> ApplicationProtocols { get; set; }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
public EncryptionPolicy EncryptionPolicy { get; set; }
} }
#endif
} }
...@@ -7,40 +7,43 @@ using StreamExtended.Helpers; ...@@ -7,40 +7,43 @@ using StreamExtended.Helpers;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
/// <summary> /// <summary>
/// Extensions used for Stream and CustomBinaryReader objects /// Extensions used for Stream and CustomBinaryReader objects
/// </summary> /// </summary>
internal static class StreamExtensions internal static class StreamExtensions
{ {
/// <summary> /// <summary>
/// Copy streams asynchronously /// Copy streams asynchronously
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="bufferSize"></param> /// <param name="bufferSize"></param>
internal static Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy, int bufferSize) internal static Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize)
{ {
return CopyToAsync(input, output, onCopy, bufferSize, CancellationToken.None); return CopyToAsync(input, output, onCopy, bufferSize, CancellationToken.None);
} }
/// <summary> /// <summary>
/// Copy streams asynchronously /// Copy streams asynchronously
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="input"></param>
/// <param name="output"></param> /// <param name="output"></param>
/// <param name="onCopy"></param> /// <param name="onCopy"></param>
/// <param name="bufferSize"></param> /// <param name="bufferSize"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy, int bufferSize, CancellationToken cancellationToken) internal static async Task CopyToAsync(this Stream input, Stream output, Action<byte[], int, int> onCopy,
int bufferSize, CancellationToken cancellationToken)
{ {
byte[] buffer = BufferPool.GetBuffer(bufferSize); var buffer = BufferPool.GetBuffer(bufferSize);
try try
{ {
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
// cancellation is not working on Socket ReadAsync // cancellation is not working on Socket ReadAsync
// https://github.com/dotnet/corefx/issues/15033 // https://github.com/dotnet/corefx/issues/15033
int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None).WithCancellation(cancellationToken); int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None)
.WithCancellation(cancellationToken);
int bytesRead; int bytesRead;
if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested) if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested)
{ {
...@@ -66,7 +69,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -66,7 +69,7 @@ namespace Titanium.Web.Proxy.Extensions
{ {
if (task != await Task.WhenAny(task, tcs.Task)) if (task != await Task.WhenAny(task, tcs.Task))
{ {
return default(T); return default;
} }
} }
......
using System; using System;
using System.Net.Sockets; using System.Net.Sockets;
using System.Reflection; using System.Reflection;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy.Extensions namespace Titanium.Web.Proxy.Extensions
{ {
...@@ -17,31 +16,12 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -17,31 +16,12 @@ namespace Titanium.Web.Proxy.Extensions
var method = property.GetMethod; var method = property.GetMethod;
if (method != null && method.ReturnType == typeof(bool)) if (method != null && method.ReturnType == typeof(bool))
{ {
socketCleanedUpGetter = (Func<Socket, bool>)Delegate.CreateDelegate(typeof(Func<Socket, bool>), method); socketCleanedUpGetter =
(Func<Socket, bool>)Delegate.CreateDelegate(typeof(Func<Socket, bool>), method);
} }
} }
} }
/// <summary>
/// Gets the local port from a native TCP row object.
/// </summary>
/// <param name="tcpRow">The TCP row.</param>
/// <returns>The local port</returns>
internal static int GetLocalPort(this NativeMethods.TcpRow tcpRow)
{
return (tcpRow.localPort1 << 8) + tcpRow.localPort2 + (tcpRow.localPort3 << 24) + (tcpRow.localPort4 << 16);
}
/// <summary>
/// Gets the remote port from a native TCP row object.
/// </summary>
/// <param name="tcpRow">The TCP row.</param>
/// <returns>The remote port</returns>
internal static int GetRemotePort(this NativeMethods.TcpRow tcpRow)
{
return (tcpRow.remotePort1 << 8) + tcpRow.remotePort2 + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
}
internal static void CloseSocket(this TcpClient tcpClient) internal static void CloseSocket(this TcpClient tcpClient)
{ {
if (tcpClient == null) if (tcpClient == null)
...@@ -64,6 +44,7 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -64,6 +44,7 @@ namespace Titanium.Web.Proxy.Extensions
} }
catch catch
{ {
// ignored
} }
} }
} }
......
using StreamExtended.Network; using System;
using System;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -13,7 +13,7 @@ namespace Titanium.Web.Proxy.Helpers
private static readonly Encoding defaultEncoding = Encoding.GetEncoding("ISO-8859-1"); private static readonly Encoding defaultEncoding = Encoding.GetEncoding("ISO-8859-1");
/// <summary> /// <summary>
/// Gets the character encoding of request/response from content-type header /// Gets the character encoding of request/response from content-type header
/// </summary> /// </summary>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <returns></returns> /// <returns></returns>
...@@ -37,7 +37,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -37,7 +37,6 @@ namespace Titanium.Web.Proxy.Helpers
string value = split[1]; string value = split[1];
if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase)) if (value.Equals("x-user-defined", StringComparison.OrdinalIgnoreCase))
{ {
//todo: what is this?
continue; continue;
} }
...@@ -87,9 +86,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -87,9 +86,9 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Tries to get root domain from a given hostname /// Tries to get root domain from a given hostname
/// Adapted from below answer /// Adapted from below answer
/// https://stackoverflow.com/questions/16473838/get-domain-name-of-a-url-in-c-sharp-net /// https://stackoverflow.com/questions/16473838/get-domain-name-of-a-url-in-c-sharp-net
/// </summary> /// </summary>
/// <param name="hostname"></param> /// <param name="hostname"></param>
/// <returns></returns> /// <returns></returns>
...@@ -103,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -103,7 +102,7 @@ namespace Titanium.Web.Proxy.Helpers
int idx = hostname.IndexOf(ProxyConstants.DotSplit); int idx = hostname.IndexOf(ProxyConstants.DotSplit);
//issue #352 //issue #352
if(hostname.Substring(0, idx).Contains("-")) if (hostname.Substring(0, idx).Contains("-"))
{ {
return hostname; return hostname;
} }
...@@ -117,13 +116,36 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -117,13 +116,36 @@ namespace Titanium.Web.Proxy.Helpers
} }
/// <summary> /// <summary>
/// Determines whether is connect method. /// Determines whether is connect method.
/// </summary> /// </summary>
/// <param name="clientStream">The client stream.</param> /// <param name="clientStream">The client stream.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns> /// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal static async Task<int> IsConnectMethod(CustomBufferedStream clientStream) internal static Task<int> IsConnectMethod(CustomBufferedStream clientStream)
{ {
bool isConnect = true; return StartsWith(clientStream, "CONNECT");
}
/// <summary>
/// Determines whether is pri method (HTTP/2).
/// </summary>
/// <param name="clientStream">The client stream.</param>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal static Task<int> IsPriMethod(CustomBufferedStream clientStream)
{
return StartsWith(clientStream, "PRI");
}
/// <summary>
/// Determines whether the stream starts with the given string.
/// </summary>
/// <param name="clientStream">The client stream.</param>
/// <param name="expectedStart">The expected start.</param>
/// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns>
private static async Task<int> StartsWith(CustomBufferedStream clientStream, string expectedStart)
{
bool isExpected = true;
int legthToCheck = 10; int legthToCheck = 10;
for (int i = 0; i < legthToCheck; i++) for (int i = 0; i < legthToCheck; i++)
{ {
...@@ -135,25 +157,23 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -135,25 +157,23 @@ namespace Titanium.Web.Proxy.Helpers
if (b == ' ' && i > 2) if (b == ' ' && i > 2)
{ {
// at least 3 letters and a space return isExpected ? 1 : 0;
return isConnect ? 1 : 0;
} }
char ch = (char)b; char ch = (char)b;
if (!char.IsLetter(ch)) if (!char.IsLetter(ch))
{ {
// non letter or too short
return -1; return -1;
} }
if (i > 6 || ch != "CONNECT"[i]) if (i >= expectedStart.Length || ch != expectedStart[i])
{ {
isConnect = false; isExpected = false;
} }
} }
// only letters // only letters
return isConnect ? 1 : 0; return isExpected ? 1 : 0;
} }
} }
} }
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
sealed class HttpRequestWriter : HttpWriter internal sealed class HttpRequestWriter : HttpWriter
{ {
public HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize) public HttpRequestWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
{ {
} }
/// <summary>
/// Writes the request.
/// </summary>
/// <param name="request"></param>
/// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task WriteRequestAsync(Request request, bool flush = true,
CancellationToken cancellationToken = default)
{
await WriteLineAsync(Request.CreateRequestLine(request.Method, request.OriginalUrl, request.HttpVersion),
cancellationToken);
await WriteAsync(request, flush, cancellationToken);
}
} }
} }
using System; using System;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
namespace Titanium.Web.Proxy.Helpers namespace Titanium.Web.Proxy.Helpers
{ {
sealed class HttpResponseWriter : HttpWriter internal sealed class HttpResponseWriter : HttpWriter
{ {
public HttpResponseWriter(Stream stream, int bufferSize) : base(stream, bufferSize) public HttpResponseWriter(Stream stream, int bufferSize) : base(stream, bufferSize)
{ {
} }
/// <summary> /// <summary>
/// Writes the response. /// Writes the response.
/// </summary> /// </summary>
/// <param name="response"></param> /// <param name="response"></param>
/// <param name="flush"></param> /// <param name="flush"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task WriteResponseAsync(Response response, bool flush = true) public async Task WriteResponseAsync(Response response, bool flush = true,
CancellationToken cancellationToken = default)
{ {
await WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, response.StatusDescription); await WriteResponseStatusAsync(response.HttpVersion, response.StatusCode, response.StatusDescription,
await WriteAsync(response, flush); cancellationToken);
await WriteAsync(response, flush, cancellationToken);
} }
/// <summary> /// <summary>
/// Write response status /// Write response status
/// </summary> /// </summary>
/// <param name="version"></param> /// <param name="version"></param>
/// <param name="code"></param> /// <param name="code"></param>
/// <param name="description"></param> /// <param name="description"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public Task WriteResponseStatusAsync(Version version, int code, string description) public Task WriteResponseStatusAsync(Version version, int code, string description, CancellationToken cancellationToken)
{ {
return WriteLineAsync(Response.CreateResponseLine(version, code, description)); return WriteLineAsync(Response.CreateResponseLine(version, code, description), cancellationToken);
} }
} }
} }
This diff is collapsed.
...@@ -5,15 +5,16 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -5,15 +5,16 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal partial class NativeMethods internal partial class NativeMethods
{ {
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("wininet.dll")] [DllImport("wininet.dll")]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
int dwBufferLength);
[DllImport("kernel32.dll")] [DllImport("kernel32.dll")]
internal static extern IntPtr GetConsoleWindow(); internal static extern IntPtr GetConsoleWindow();
// Keeps it from getting garbage collected
internal static ConsoleEventDelegate Handler;
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add); internal static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
......
...@@ -9,6 +9,13 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -9,6 +9,13 @@ namespace Titanium.Web.Proxy.Helpers
internal const int AfInet = 2; internal const int AfInet = 2;
internal const int AfInet6 = 23; internal const int AfInet6 = 23;
/// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa365928.aspx" />
/// </summary>
[DllImport("iphlpapi.dll", SetLastError = true)]
internal static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int size, bool sort, int ipVersion,
int tableClass, int reserved);
internal enum TcpTableType internal enum TcpTableType
{ {
BasicListener, BasicListener,
...@@ -19,43 +26,37 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -19,43 +26,37 @@ namespace Titanium.Web.Proxy.Helpers
OwnerPidAll, OwnerPidAll,
OwnerModuleListener, OwnerModuleListener,
OwnerModuleConnections, OwnerModuleConnections,
OwnerModuleAll, OwnerModuleAll
}
/// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct TcpTable
{
public uint length;
public TcpRow row;
} }
/// <summary> /// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/> /// <see href="http://msdn2.microsoft.com/en-us/library/aa366913.aspx" />
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct TcpRow internal struct TcpRow
{ {
public TcpState state; public TcpState state;
public uint localAddr; public uint localAddr;
public byte localPort1; public uint localPort; // in network byte order (order of bytes - 1,0,3,2)
public byte localPort2;
public byte localPort3;
public byte localPort4;
public uint remoteAddr; public uint remoteAddr;
public byte remotePort1; public uint remotePort; // in network byte order (order of bytes - 1,0,3,2)
public byte remotePort2;
public byte remotePort3;
public byte remotePort4;
public int owningPid; public int owningPid;
} }
/// <summary> /// <summary>
/// <see href="http://msdn2.microsoft.com/en-us/library/aa365928.aspx"/> /// <see href="https://msdn.microsoft.com/en-us/library/aa366896.aspx"/>
/// </summary> /// </summary>
[DllImport("iphlpapi.dll", SetLastError = true)] [StructLayout(LayoutKind.Sequential)]
internal static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int size, bool sort, int ipVersion, int tableClass, int reserved); internal unsafe struct Tcp6Row
{
public fixed byte localAddr[16];
public uint localScopeId;
public uint localPort; // in network byte order (order of bytes - 1,0,3,2)
public fixed byte remoteAddr[16];
public uint remoteScopeId;
public uint remotePort; // in network byte order (order of bytes - 1,0,3,2)
public TcpState state;
public int owningPid;
}
} }
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -4,21 +4,25 @@ using System.Runtime.InteropServices; ...@@ -4,21 +4,25 @@ using System.Runtime.InteropServices;
// Helper classes for setting system proxy settings // Helper classes for setting system proxy settings
namespace Titanium.Web.Proxy.Helpers.WinHttp namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
internal partial class NativeMethods internal class NativeMethods
{ {
internal static class WinHttp internal static class WinHttp
{ {
[DllImport("winhttp.dll", SetLastError = true)] [DllImport("winhttp.dll", SetLastError = true)]
internal static extern bool WinHttpGetIEProxyConfigForCurrentUser(ref WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig); internal static extern bool WinHttpGetIEProxyConfigForCurrentUser(
ref WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern WinHttpHandle WinHttpOpen(string userAgent, AccessType accessType, string proxyName, string proxyBypass, int dwFlags); internal static extern WinHttpHandle WinHttpOpen(string userAgent, AccessType accessType, string proxyName,
string proxyBypass, int dwFlags);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool WinHttpSetTimeouts(WinHttpHandle session, int resolveTimeout, int connectTimeout, int sendTimeout, int receiveTimeout); internal static extern bool WinHttpSetTimeouts(WinHttpHandle session, int resolveTimeout,
int connectTimeout, int sendTimeout, int receiveTimeout);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool WinHttpGetProxyForUrl(WinHttpHandle session, string url, [In] ref WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, internal static extern bool WinHttpGetProxyForUrl(WinHttpHandle session, string url,
[In] ref WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions,
out WINHTTP_PROXY_INFO proxyInfo); out WINHTTP_PROXY_INFO proxyInfo);
[DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)] [DllImport("winhttp.dll", CharSet = CharSet.Unicode, SetLastError = true)]
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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