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" />
......
...@@ -9,19 +9,19 @@ namespace Titanium.Web.Proxy.Examples.Basic.Helpers ...@@ -9,19 +9,19 @@ namespace Titanium.Web.Proxy.Examples.Basic.Helpers
/// </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))
......
<?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
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
<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}"
SelectedItem="{Binding SelectedSession}"
KeyDown="ListViewSessions_OnKeyDown"> KeyDown="ListViewSessions_OnKeyDown">
<ListView.View> <ListView.View>
<GridView> <GridView>
......
...@@ -20,44 +20,18 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -20,44 +20,18 @@ namespace Titanium.Web.Proxy.Examples.Wpf
/// </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);
set => SetValue(ServerConnectionCountProperty, value);
}
private readonly Dictionary<HttpWebClient, SessionListItem> sessionDictionary = 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()
...@@ -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;
......
<?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,9 +68,11 @@ namespace Titanium.Web.Proxy.IntegrationTests ...@@ -68,9 +68,11 @@ 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()
{ {
......
...@@ -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>
......
...@@ -16,7 +16,8 @@ namespace Titanium.Web.Proxy ...@@ -16,7 +16,8 @@ namespace Titanium.Web.Proxy
/// <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)
...@@ -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;
......
...@@ -9,17 +9,17 @@ namespace Titanium.Web.Proxy.Compression ...@@ -9,17 +9,17 @@ namespace Titanium.Web.Proxy.Compression
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
{ {
......
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
{ {
......
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);
} }
......
...@@ -9,17 +9,18 @@ namespace Titanium.Web.Proxy.Decompression ...@@ -9,17 +9,18 @@ namespace Titanium.Web.Proxy.Decompression
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
{ {
......
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
{ {
......
using System.IO; using System.IO;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Decompression namespace Titanium.Web.Proxy.Decompression
{ {
......
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);
} }
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,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; }
} }
} }
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,14 +9,15 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -10,14 +9,15 @@ 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;
...@@ -29,6 +29,20 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -29,6 +29,20 @@ namespace Titanium.Web.Proxy.EventArguments
: 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; }
} }
} }
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;
...@@ -22,7 +14,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -22,7 +14,7 @@ namespace Titanium.Web.Proxy.EventArguments
/// 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
...@@ -31,6 +23,50 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -31,6 +23,50 @@ namespace Titanium.Web.Proxy.EventArguments
protected readonly ExceptionHandler ExceptionFunc; protected readonly ExceptionHandler ExceptionFunc;
internal readonly CancellationTokenSource CancellationTokenSource;
/// <summary>
/// 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> /// <summary>
/// Holds a reference to client /// Holds a reference to client
/// </summary> /// </summary>
...@@ -63,10 +99,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -63,10 +99,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// </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
{ {
...@@ -18,6 +12,6 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -18,6 +12,6 @@ namespace Titanium.Web.Proxy.EventArguments
/// <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;
} }
} }
} }
...@@ -14,10 +14,11 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -14,10 +14,11 @@ namespace Titanium.Web.Proxy.Exceptions
/// 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;
......
...@@ -13,8 +13,9 @@ namespace Titanium.Web.Proxy.Exceptions ...@@ -13,8 +13,9 @@ namespace Titanium.Web.Proxy.Exceptions
/// </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;
} }
......
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
} }
...@@ -18,7 +18,8 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -18,7 +18,8 @@ namespace Titanium.Web.Proxy.Extensions
/// <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);
} }
...@@ -31,16 +32,18 @@ namespace Titanium.Web.Proxy.Extensions ...@@ -31,16 +32,18 @@ namespace Titanium.Web.Proxy.Extensions
/// <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;
...@@ -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;
} }
...@@ -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;
} }
...@@ -121,9 +120,32 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -121,9 +120,32 @@ namespace Titanium.Web.Proxy.Helpers
/// </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)
{ {
...@@ -16,11 +17,14 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -16,11 +17,14 @@ namespace Titanium.Web.Proxy.Helpers
/// </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>
...@@ -29,10 +33,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -29,10 +33,11 @@ namespace Titanium.Web.Proxy.Helpers
/// <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;
}
} }
} }
...@@ -6,25 +6,6 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -6,25 +6,6 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal class NetworkHelper internal class NetworkHelper
{ {
private static int FindProcessIdFromLocalPort(int port, IpVersion ipVersion)
{
var tcpRow = TcpHelper.GetTcpRowByLocalPort(ipVersion, port);
return tcpRow?.ProcessId ?? 0;
}
internal static int GetProcessIdFromPort(int port, bool ipV6Enabled)
{
int processId = FindProcessIdFromLocalPort(port, IpVersion.Ipv4);
if (processId > 0 && !ipV6Enabled)
{
return processId;
}
return FindProcessIdFromLocalPort(port, IpVersion.Ipv6);
}
/// <summary> /// <summary>
/// Adapated from below link /// Adapated from below link
/// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost /// http://stackoverflow.com/questions/11834091/how-to-check-if-localhost
...@@ -33,10 +14,15 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -33,10 +14,15 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns></returns> /// <returns></returns>
internal static bool IsLocalIpAddress(IPAddress address) internal static bool IsLocalIpAddress(IPAddress address)
{ {
if (IPAddress.IsLoopback(address))
{
return true;
}
// get local IP addresses // get local IP addresses
var localIPs = Dns.GetHostAddresses(Dns.GetHostName()); var localIPs = Dns.GetHostAddresses(Dns.GetHostName());
// test if any host IP equals to any local IP or to localhost // test if any host IP equals to any local IP or to localhost
return IPAddress.IsLoopback(address) || localIPs.Contains(address); return localIPs.Contains(address);
} }
internal static bool IsLocalIpAddress(string hostName) internal static bool IsLocalIpAddress(string hostName)
...@@ -55,7 +41,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -55,7 +41,9 @@ namespace Titanium.Web.Proxy.Helpers
localhost = Dns.GetHostEntry(Dns.GetHostName()); localhost = Dns.GetHostEntry(Dns.GetHostName());
if (IPAddress.TryParse(hostName, out var ipAddress)) if (IPAddress.TryParse(hostName, out var ipAddress))
{
isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress)); isLocalhost = localhost.AddressList.Any(x => x.Equals(ipAddress));
}
if (!isLocalhost) if (!isLocalhost)
{ {
......
...@@ -8,25 +8,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -8,25 +8,8 @@ namespace Titanium.Web.Proxy.Helpers
{ {
internal class ProxyInfo internal class ProxyInfo
{ {
public bool? AutoDetect { get; } public ProxyInfo(bool? autoDetect, string autoConfigUrl, int? proxyEnable, string proxyServer,
string proxyOverride)
public string AutoConfigUrl { get; }
public int? ProxyEnable { get; }
public string ProxyServer { get; }
public string ProxyOverride { get; }
public bool BypassLoopback { get; }
public bool BypassOnLocal { get; }
public Dictionary<ProxyProtocolType, HttpSystemProxyValue> Proxies { get; }
public string[] BypassList { get; }
public ProxyInfo(bool? autoDetect, string autoConfigUrl, int? proxyEnable, string proxyServer, string proxyOverride)
{ {
AutoDetect = autoDetect; AutoDetect = autoDetect;
AutoConfigUrl = autoConfigUrl; AutoConfigUrl = autoConfigUrl;
...@@ -68,10 +51,29 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -68,10 +51,29 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
public bool? AutoDetect { get; }
public string AutoConfigUrl { get; }
public int? ProxyEnable { get; }
public string ProxyServer { get; }
public string ProxyOverride { get; }
public bool BypassLoopback { get; }
public bool BypassOnLocal { get; }
public Dictionary<ProxyProtocolType, HttpSystemProxyValue> Proxies { get; }
public string[] BypassList { get; }
private static string BypassStringEscape(string rawString) private static string BypassStringEscape(string rawString)
{ {
var match = var match =
new Regex("^(?<scheme>.*://)?(?<host>[^:]*)(?<port>:[0-9]{1,5})?$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Match(rawString); new Regex("^(?<scheme>.*://)?(?<host>[^:]*)(?<port>:[0-9]{1,5})?$",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant).Match(rawString);
string empty1; string empty1;
string rawString1; string rawString1;
string empty2; string empty2;
...@@ -92,10 +94,14 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -92,10 +94,14 @@ namespace Titanium.Web.Proxy.Helpers
string str2 = ConvertRegexReservedChars(rawString1); string str2 = ConvertRegexReservedChars(rawString1);
string str3 = ConvertRegexReservedChars(empty2); string str3 = ConvertRegexReservedChars(empty2);
if (str1 == string.Empty) if (str1 == string.Empty)
{
str1 = "(?:.*://)?"; str1 = "(?:.*://)?";
}
if (str3 == string.Empty) if (str3 == string.Empty)
{
str3 = "(?::[0-9]{1,5})?"; str3 = "(?::[0-9]{1,5})?";
}
return "^" + str1 + str2 + str3 + "$"; return "^" + str1 + str2 + str3 + "$";
} }
...@@ -103,15 +109,21 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -103,15 +109,21 @@ namespace Titanium.Web.Proxy.Helpers
private static string ConvertRegexReservedChars(string rawString) private static string ConvertRegexReservedChars(string rawString)
{ {
if (rawString.Length == 0) if (rawString.Length == 0)
{
return rawString; return rawString;
}
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
foreach (char ch in rawString) foreach (char ch in rawString)
{ {
if ("#$()+.?[\\^{|".IndexOf(ch) != -1) if ("#$()+.?[\\^{|".IndexOf(ch) != -1)
{
stringBuilder.Append('\\'); stringBuilder.Append('\\');
}
else if (ch == 42) else if (ch == 42)
{
stringBuilder.Append('.'); stringBuilder.Append('.');
}
stringBuilder.Append(ch); stringBuilder.Append(ch);
} }
...@@ -131,7 +143,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -131,7 +143,8 @@ namespace Titanium.Web.Proxy.Helpers
{ {
protocolType = ProxyProtocolType.Http; protocolType = ProxyProtocolType.Http;
} }
else if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttps, StringComparison.InvariantCultureIgnoreCase)) else if (protocolTypeStr.Equals(Proxy.ProxyServer.UriSchemeHttps,
StringComparison.InvariantCultureIgnoreCase))
{ {
protocolType = ProxyProtocolType.Https; protocolType = ProxyProtocolType.Https;
} }
...@@ -149,7 +162,9 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -149,7 +162,9 @@ namespace Titanium.Web.Proxy.Helpers
var result = new List<HttpSystemProxyValue>(); var result = new List<HttpSystemProxyValue>();
if (string.IsNullOrWhiteSpace(proxyServerValues)) if (string.IsNullOrWhiteSpace(proxyServerValues))
{
return result; return result;
}
var proxyValues = proxyServerValues.Split(';'); var proxyValues = proxyServerValues.Split(';');
...@@ -161,8 +176,10 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -161,8 +176,10 @@ namespace Titanium.Web.Proxy.Helpers
{ {
var parsedValue = ParseProxyValue(proxyServerValues); var parsedValue = ParseProxyValue(proxyServerValues);
if (parsedValue != null) if (parsedValue != null)
{
result.Add(parsedValue); result.Add(parsedValue);
} }
}
return result; return result;
} }
...@@ -189,7 +206,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -189,7 +206,7 @@ namespace Titanium.Web.Proxy.Helpers
{ {
HostName = endPointParts[0], HostName = endPointParts[0],
Port = int.Parse(endPointParts[1]), Port = int.Parse(endPointParts[1]),
ProtocolType = protocolType.Value, ProtocolType = protocolType.Value
}; };
} }
} }
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Helpers
{
public class Ref<T>
{
public Ref()
{
}
public Ref(T value)
{
Value = value;
}
public T Value { get; set; }
public override string ToString()
{
T value = Value;
return value == null ? string.Empty : value.ToString();
}
public static implicit operator T(Ref<T> r)
{
return r.Value;
}
public static implicit operator Ref<T>(T value)
{
return new Ref<T>(value);
}
}
}
...@@ -15,11 +15,12 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -15,11 +15,12 @@ namespace Titanium.Web.Proxy.Helpers
private static readonly Lazy<bool> isRunningOnMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null); private static readonly Lazy<bool> isRunningOnMono = new Lazy<bool>(() => Type.GetType("Mono.Runtime") != null);
#if NETSTANDARD2_0 #if NETSTANDARD2_0
/// <summary> /// <summary>
/// cache for Windows platform check /// cache for Windows platform check
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private static readonly Lazy<bool> isRunningOnWindows = new Lazy<bool>(() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); private static readonly Lazy<bool> isRunningOnWindows = new Lazy<bool>(() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
#endif #endif
/// <summary> /// <summary>
......
...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -26,7 +26,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <summary> /// <summary>
/// Both HTTP and HTTPS /// Both HTTP and HTTPS
/// </summary> /// </summary>
AllHttp = Http | Https, AllHttp = Http | Https
} }
internal class HttpSystemProxyValue internal class HttpSystemProxyValue
...@@ -133,7 +133,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -133,7 +133,8 @@ namespace Titanium.Web.Proxy.Helpers
reg.DeleteValue(regAutoConfigUrl, false); reg.DeleteValue(regAutoConfigUrl, false);
reg.SetValue(regProxyEnable, 1); reg.SetValue(regProxyEnable, 1);
reg.SetValue(regProxyServer, string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray())); reg.SetValue(regProxyServer,
string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
Refresh(); Refresh();
} }
...@@ -162,7 +163,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -162,7 +163,8 @@ namespace Titanium.Web.Proxy.Helpers
if (existingSystemProxyValues.Count != 0) if (existingSystemProxyValues.Count != 0)
{ {
reg.SetValue(regProxyEnable, 1); reg.SetValue(regProxyEnable, 1);
reg.SetValue(regProxyServer, string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray())); reg.SetValue(regProxyServer,
string.Join(";", existingSystemProxyValues.Select(x => x.ToString()).ToArray()));
} }
else else
{ {
...@@ -284,7 +286,8 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -284,7 +286,8 @@ namespace Titanium.Web.Proxy.Helpers
private ProxyInfo GetProxyInfoFromRegistry(RegistryKey reg) private ProxyInfo GetProxyInfoFromRegistry(RegistryKey reg)
{ {
var pi = new ProxyInfo(null, reg.GetValue(regAutoConfigUrl) as string, reg.GetValue(regProxyEnable) as int?, reg.GetValue(regProxyServer) as string, var pi = new ProxyInfo(null, reg.GetValue(regAutoConfigUrl) as string, reg.GetValue(regProxyEnable) as int?,
reg.GetValue(regProxyServer) as string,
reg.GetValue(regProxyOverride) as string); reg.GetValue(regProxyOverride) as string);
return pi; return pi;
......
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)]
......
...@@ -9,11 +9,11 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -9,11 +9,11 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
} }
public override bool IsInvalid => handle == IntPtr.Zero;
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {
return NativeMethods.WinHttp.WinHttpCloseHandle(handle); return NativeMethods.WinHttp.WinHttpCloseHandle(handle);
} }
public override bool IsInvalid => handle == IntPtr.Zero;
} }
} }
...@@ -14,6 +14,26 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -14,6 +14,26 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
private bool autoDetectFailed; private bool autoDetectFailed;
private AutoWebProxyState state; private AutoWebProxyState state;
public WinHttpWebProxyFinder()
{
session = NativeMethods.WinHttp.WinHttpOpen(null, NativeMethods.WinHttp.AccessType.NoProxy, null, null, 0);
if (session == null || session.IsInvalid)
{
int lastWin32Error = GetLastWin32Error();
}
else
{
int downloadTimeout = 60 * 1000;
if (NativeMethods.WinHttp.WinHttpSetTimeouts(session, downloadTimeout, downloadTimeout, downloadTimeout,
downloadTimeout))
{
return;
}
int lastWin32Error = GetLastWin32Error();
}
}
public ICredentials Credentials { get; set; } public ICredentials Credentials { get; set; }
public ProxyInfo ProxyInfo { get; internal set; } public ProxyInfo ProxyInfo { get; internal set; }
...@@ -28,27 +48,18 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -28,27 +48,18 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
private WebProxy proxy { get; set; } private WebProxy proxy { get; set; }
public WinHttpWebProxyFinder() public void Dispose()
{
session = NativeMethods.WinHttp.WinHttpOpen(null, NativeMethods.WinHttp.AccessType.NoProxy, null, null, 0);
if (session == null || session.IsInvalid)
{
int lastWin32Error = GetLastWin32Error();
}
else
{ {
int downloadTimeout = 60 * 1000; Dispose(true);
if (NativeMethods.WinHttp.WinHttpSetTimeouts(session, downloadTimeout, downloadTimeout, downloadTimeout, downloadTimeout))
return;
int lastWin32Error = GetLastWin32Error();
}
} }
public bool GetAutoProxies(Uri destination, out IList<string> proxyList) public bool GetAutoProxies(Uri destination, out IList<string> proxyList)
{ {
proxyList = null; proxyList = null;
if (session == null || session.IsInvalid || state == AutoWebProxyState.UnrecognizedScheme) if (session == null || session.IsInvalid || state == AutoWebProxyState.UnrecognizedScheme)
{
return false; return false;
}
string proxyListString = null; string proxyListString = null;
var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed; var errorCode = NativeMethods.WinHttp.ErrorCodes.AudodetectionFailed;
...@@ -64,11 +75,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -64,11 +75,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
} }
if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode)) if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode))
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, AutomaticConfigurationScript, out proxyListString); {
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, AutomaticConfigurationScript,
out proxyListString);
}
state = GetStateFromErrorCode(errorCode); state = GetStateFromErrorCode(errorCode);
if (state != AutoWebProxyState.Completed) if (state != AutoWebProxyState.Completed)
{
return false; return false;
}
if (!string.IsNullOrEmpty(proxyListString)) if (!string.IsNullOrEmpty(proxyListString))
{ {
...@@ -101,14 +117,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -101,14 +117,16 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
var systemProxy = new ExternalProxy var systemProxy = new ExternalProxy
{ {
HostName = proxyStr, HostName = proxyStr,
Port = port, Port = port
}; };
return systemProxy; return systemProxy;
} }
if (proxy?.IsBypassed(destination) == true) if (proxy?.IsBypassed(destination) == true)
{
return null; return null;
}
var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme); var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme);
if (protocolType.HasValue) if (protocolType.HasValue)
...@@ -119,7 +137,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -119,7 +137,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
var systemProxy = new ExternalProxy var systemProxy = new ExternalProxy
{ {
HostName = value.HostName, HostName = value.HostName,
Port = value.Port, Port = value.Port
}; };
return systemProxy; return systemProxy;
...@@ -159,7 +177,9 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -159,7 +177,9 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
else else
{ {
if (Marshal.GetLastWin32Error() == 8) if (Marshal.GetLastWin32Error() == 8)
{
throw new OutOfMemoryException(); throw new OutOfMemoryException();
}
result = new ProxyInfo(true, null, null, null, null); result = new ProxyInfo(true, null, null, null, null);
} }
...@@ -180,15 +200,13 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -180,15 +200,13 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
autoDetectFailed = false; autoDetectFailed = false;
} }
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
if (!disposing || session == null || session.IsInvalid) if (!disposing || session == null || session.IsInvalid)
{
return; return;
}
session.Close(); session.Close();
} }
...@@ -201,7 +219,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -201,7 +219,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
autoProxyOptions.Flags = NativeMethods.WinHttp.AutoProxyFlags.AutoDetect; autoProxyOptions.Flags = NativeMethods.WinHttp.AutoProxyFlags.AutoDetect;
autoProxyOptions.AutoConfigUrl = null; autoProxyOptions.AutoConfigUrl = null;
autoProxyOptions.AutoDetectFlags = NativeMethods.WinHttp.AutoDetectType.Dhcp | NativeMethods.WinHttp.AutoDetectType.DnsA; autoProxyOptions.AutoDetectFlags =
NativeMethods.WinHttp.AutoDetectType.Dhcp | NativeMethods.WinHttp.AutoDetectType.DnsA;
} }
else else
{ {
...@@ -218,14 +237,17 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -218,14 +237,17 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
autoProxyOptions.AutoLogonIfChallenged = true; autoProxyOptions.AutoLogonIfChallenged = true;
if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString)) if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
{
num = GetLastWin32Error(); num = GetLastWin32Error();
} }
} }
}
return num; return num;
} }
private bool WinHttpGetProxyForUrl(string destination, ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString) private bool WinHttpGetProxyForUrl(string destination,
ref NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions, out string proxyListString)
{ {
proxyListString = null; proxyListString = null;
bool flag; bool flag;
...@@ -233,15 +255,19 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -233,15 +255,19 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
flag = NativeMethods.WinHttp.WinHttpGetProxyForUrl(session, destination, ref autoProxyOptions, out proxyInfo); flag = NativeMethods.WinHttp.WinHttpGetProxyForUrl(session, destination, ref autoProxyOptions,
out proxyInfo);
if (flag) if (flag)
{
proxyListString = Marshal.PtrToStringUni(proxyInfo.Proxy); proxyListString = Marshal.PtrToStringUni(proxyInfo.Proxy);
} }
}
finally finally
{ {
Marshal.FreeHGlobal(proxyInfo.Proxy); Marshal.FreeHGlobal(proxyInfo.Proxy);
Marshal.FreeHGlobal(proxyInfo.ProxyBypass); Marshal.FreeHGlobal(proxyInfo.ProxyBypass);
} }
return flag; return flag;
} }
...@@ -249,7 +275,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -249,7 +275,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
int lastWin32Error = Marshal.GetLastWin32Error(); int lastWin32Error = Marshal.GetLastWin32Error();
if (lastWin32Error == 8) if (lastWin32Error == 8)
{
throw new OutOfMemoryException(); throw new OutOfMemoryException();
}
return lastWin32Error; return lastWin32Error;
} }
...@@ -274,7 +303,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -274,7 +303,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
private static AutoWebProxyState GetStateFromErrorCode(NativeMethods.WinHttp.ErrorCodes errorCode) private static AutoWebProxyState GetStateFromErrorCode(NativeMethods.WinHttp.ErrorCodes errorCode)
{ {
if (errorCode == 0L) if (errorCode == 0L)
{
return AutoWebProxyState.Completed; return AutoWebProxyState.Completed;
}
switch (errorCode) switch (errorCode)
{ {
case NativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript: case NativeMethods.WinHttp.ErrorCodes.UnableToDownloadScript:
...@@ -298,8 +330,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -298,8 +330,10 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
foreach (char c in value) foreach (char c in value)
{ {
if (!char.IsWhiteSpace(c)) if (!char.IsWhiteSpace(c))
{
stringBuilder.Append(c); stringBuilder.Append(c);
} }
}
return stringBuilder.ToString(); return stringBuilder.ToString();
} }
...@@ -325,7 +359,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -325,7 +359,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
DownloadFailure, DownloadFailure,
CompilationFailure, CompilationFailure,
UnrecognizedScheme, UnrecognizedScheme,
Completed, Completed
} }
} }
} }
...@@ -4,11 +4,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -4,11 +4,11 @@ namespace Titanium.Web.Proxy.Http
{ {
public class ConnectRequest : Request public class ConnectRequest : Request
{ {
public ClientHelloInfo ClientHelloInfo { get; set; }
public ConnectRequest() public ConnectRequest()
{ {
Method = "CONNECT"; Method = "CONNECT";
} }
public ClientHelloInfo ClientHelloInfo { get; set; }
} }
} }
using StreamExtended; using System;
using System;
using System.Net; using System.Net;
using StreamExtended;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
......
...@@ -15,6 +15,17 @@ namespace Titanium.Web.Proxy.Http ...@@ -15,6 +15,17 @@ namespace Titanium.Web.Proxy.Http
private readonly Dictionary<string, List<HttpHeader>> nonUniqueHeaders; private readonly Dictionary<string, List<HttpHeader>> nonUniqueHeaders;
/// <summary>
/// Initializes a new instance of the <see cref="HeaderCollection" /> class.
/// </summary>
public HeaderCollection()
{
headers = new Dictionary<string, HttpHeader>(StringComparer.OrdinalIgnoreCase);
nonUniqueHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase);
Headers = new ReadOnlyDictionary<string, HttpHeader>(headers);
NonUniqueHeaders = new ReadOnlyDictionary<string, List<HttpHeader>>(nonUniqueHeaders);
}
/// <summary> /// <summary>
/// Unique Request header collection /// Unique Request header collection
/// </summary> /// </summary>
...@@ -26,14 +37,19 @@ namespace Titanium.Web.Proxy.Http ...@@ -26,14 +37,19 @@ namespace Titanium.Web.Proxy.Http
public ReadOnlyDictionary<string, List<HttpHeader>> NonUniqueHeaders { get; } public ReadOnlyDictionary<string, List<HttpHeader>> NonUniqueHeaders { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HeaderCollection"/> class. /// Returns an enumerator that iterates through the collection.
/// </summary> /// </summary>
public HeaderCollection() /// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<HttpHeader> GetEnumerator()
{ {
headers = new Dictionary<string, HttpHeader>(StringComparer.OrdinalIgnoreCase); return headers.Values.Concat(nonUniqueHeaders.Values.SelectMany(x => x)).GetEnumerator();
nonUniqueHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase); }
Headers = new ReadOnlyDictionary<string, HttpHeader>(headers);
NonUniqueHeaders = new ReadOnlyDictionary<string, List<HttpHeader>>(nonUniqueHeaders); IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
} }
/// <summary> /// <summary>
...@@ -190,7 +206,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -190,7 +206,8 @@ namespace Titanium.Web.Proxy.Http
{ {
if (header.Key != header.Value.Name) if (header.Key != header.Value.Name)
{ {
throw new Exception("Header name mismatch. Key and the name of the HttpHeader object should be the same."); throw new Exception(
"Header name mismatch. Key and the name of the HttpHeader object should be the same.");
} }
AddHeader(header.Value); AddHeader(header.Value);
...@@ -201,8 +218,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -201,8 +218,10 @@ namespace Titanium.Web.Proxy.Http
/// removes all headers with given name /// removes all headers with given name
/// </summary> /// </summary>
/// <param name="headerName"></param> /// <param name="headerName"></param>
/// <returns>True if header was removed /// <returns>
/// False if no header exists with given name</returns> /// True if header was removed
/// False if no header exists with given name
/// </returns>
public bool RemoveHeader(string headerName) public bool RemoveHeader(string headerName)
{ {
bool result = headers.Remove(headerName); bool result = headers.Remove(headerName);
...@@ -286,21 +305,5 @@ namespace Titanium.Web.Proxy.Http ...@@ -286,21 +305,5 @@ namespace Titanium.Web.Proxy.Http
SetOrAddHeaderValue(KnownHeaders.Connection, proxyHeader); SetOrAddHeaderValue(KnownHeaders.Connection, proxyHeader);
} }
} }
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<HttpHeader> GetEnumerator()
{
return headers.Values.Concat(nonUniqueHeaders.Values.SelectMany(x => x)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} }
} }
using System; using System;
using System.Collections.Generic; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using StreamExtended.Network; using StreamExtended.Network;
using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Shared; using Titanium.Web.Proxy.Shared;
namespace Titanium.Web.Proxy.Http namespace Titanium.Web.Proxy.Http
{ {
internal static class HeaderParser internal static class HeaderParser
{ {
internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection) internal static async Task ReadHeaders(CustomBinaryReader reader, HeaderCollection headerCollection, CancellationToken cancellationToken)
{ {
string tmpLine; string tmpLine;
while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync())) while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync(cancellationToken)))
{ {
var header = tmpLine.Split(ProxyConstants.ColonSplit, 2); var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);
headerCollection.AddHeader(header[0], header[1]); headerCollection.AddHeader(header[0], header[1]);
......
using System; using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
...@@ -15,6 +16,15 @@ namespace Titanium.Web.Proxy.Http ...@@ -15,6 +16,15 @@ namespace Titanium.Web.Proxy.Http
{ {
private readonly int bufferSize; private readonly int bufferSize;
internal HttpWebClient(int bufferSize, Request request = null, Response response = null)
{
this.bufferSize = bufferSize;
RequestId = Guid.NewGuid();
Request = request ?? new Request();
Response = response ?? new Response();
}
/// <summary> /// <summary>
/// Connection to server /// Connection to server
/// </summary> /// </summary>
...@@ -56,19 +66,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -56,19 +66,10 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public bool IsHttps => Request.IsHttps; public bool IsHttps => Request.IsHttps;
internal HttpWebClient(int bufferSize, Request request = null, Response response = null)
{
this.bufferSize = bufferSize;
RequestId = Guid.NewGuid();
Request = request ?? new Request();
Response = response ?? new Response();
}
/// <summary> /// <summary>
/// Set the tcp connection to server used by this webclient /// Set the tcp connection to server used by this webclient
/// </summary> /// </summary>
/// <param name="connection">Instance of <see cref="TcpConnection"/></param> /// <param name="connection">Instance of <see cref="TcpConnection" /></param>
internal void SetConnection(TcpConnection connection) internal void SetConnection(TcpConnection connection)
{ {
connection.LastAccess = DateTime.Now; connection.LastAccess = DateTime.Now;
...@@ -79,7 +80,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,7 +80,7 @@ namespace Titanium.Web.Proxy.Http
/// Prepare and send the http(s) request /// Prepare and send the http(s) request
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent) internal async Task SendRequest(bool enable100ContinueBehaviour, bool isTransparent, CancellationToken cancellationToken)
{ {
var upstreamProxy = ServerConnection.UpStreamProxy; var upstreamProxy = ServerConnection.UpStreamProxy;
...@@ -90,7 +91,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -90,7 +91,7 @@ namespace Titanium.Web.Proxy.Http
//prepare the request & headers //prepare the request & headers
await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method, await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery, useUpstreamProxy || isTransparent ? Request.OriginalUrl : Request.RequestUri.PathAndQuery,
Request.HttpVersion)); Request.HttpVersion), cancellationToken);
//Send Authentication to Upstream proxy if needed //Send Authentication to Upstream proxy if needed
...@@ -99,8 +100,9 @@ namespace Titanium.Web.Proxy.Http ...@@ -99,8 +100,9 @@ namespace Titanium.Web.Proxy.Http
&& !string.IsNullOrEmpty(upstreamProxy.UserName) && !string.IsNullOrEmpty(upstreamProxy.UserName)
&& upstreamProxy.Password != null) && upstreamProxy.Password != null)
{ {
await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer); await HttpHeader.ProxyConnectionKeepAlive.WriteToStreamAsync(writer, cancellationToken);
await HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password).WriteToStreamAsync(writer); await HttpHeader.GetProxyAuthorizationHeader(upstreamProxy.UserName, upstreamProxy.Password)
.WriteToStreamAsync(writer, cancellationToken);
} }
//write request headers //write request headers
...@@ -108,32 +110,33 @@ namespace Titanium.Web.Proxy.Http ...@@ -108,32 +110,33 @@ namespace Titanium.Web.Proxy.Http
{ {
if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization) if (isTransparent || header.Name != KnownHeaders.ProxyAuthorization)
{ {
await header.WriteToStreamAsync(writer); await header.WriteToStreamAsync(writer, cancellationToken);
} }
} }
await writer.WriteLineAsync(); await writer.WriteLineAsync(cancellationToken);
if (enable100ContinueBehaviour) if (enable100ContinueBehaviour)
{ {
if (Request.ExpectContinue) if (Request.ExpectContinue)
{ {
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode, out string responseStatusDescription); Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
out string responseStatusDescription);
//find if server is willing for expect continue //find if server is willing for expect continue
if (responseStatusCode == (int)HttpStatusCode.Continue if (responseStatusCode == (int)HttpStatusCode.Continue
&& responseStatusDescription.EqualsIgnoreCase("continue")) && responseStatusDescription.EqualsIgnoreCase("continue"))
{ {
Request.Is100Continue = true; Request.Is100Continue = true;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
} }
else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed
&& responseStatusDescription.EqualsIgnoreCase("expectation failed")) && responseStatusDescription.EqualsIgnoreCase("expectation failed"))
{ {
Request.ExpectationFailed = true; Request.ExpectationFailed = true;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
} }
} }
} }
...@@ -143,13 +146,15 @@ namespace Titanium.Web.Proxy.Http ...@@ -143,13 +146,15 @@ namespace Titanium.Web.Proxy.Http
/// Receive and parse the http response from server /// Receive and parse the http response from server
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
internal async Task ReceiveResponse() internal async Task ReceiveResponse(CancellationToken cancellationToken)
{ {
//return if this is already read //return if this is already read
if (Response.StatusCode != 0) if (Response.StatusCode != 0)
{
return; return;
}
string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(); string httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
if (httpStatus == null) if (httpStatus == null)
{ {
throw new IOException(); throw new IOException();
...@@ -157,8 +162,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -157,8 +162,7 @@ namespace Titanium.Web.Proxy.Http
if (httpStatus == string.Empty) if (httpStatus == string.Empty)
{ {
//Empty content in first-line, try again httpStatus = await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
httpStatus = await ServerConnection.StreamReader.ReadLineAsync();
} }
Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription); Response.ParseResponseLine(httpStatus, out var version, out int statusCode, out string statusDescription);
...@@ -174,10 +178,10 @@ namespace Titanium.Web.Proxy.Http ...@@ -174,10 +178,10 @@ namespace Titanium.Web.Proxy.Http
//Read the next line after 100-continue //Read the next line after 100-continue
Response.Is100Continue = true; Response.Is100Continue = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
//now receive response //now receive response
await ReceiveResponse(); await ReceiveResponse(cancellationToken);
return; return;
} }
...@@ -187,15 +191,15 @@ namespace Titanium.Web.Proxy.Http ...@@ -187,15 +191,15 @@ namespace Titanium.Web.Proxy.Http
//read next line after expectation failed response //read next line after expectation failed response
Response.ExpectationFailed = true; Response.ExpectationFailed = true;
Response.StatusCode = 0; Response.StatusCode = 0;
await ServerConnection.StreamReader.ReadLineAsync(); await ServerConnection.StreamReader.ReadLineAsync(cancellationToken);
//now receive response //now receive response
await ReceiveResponse(); await ReceiveResponse(cancellationToken);
return; return;
} }
//Read the response headers in to unique and non-unique header collections //Read the response headers in to unique and non-unique header collections
await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.Headers); await HeaderParser.ReadHeaders(ServerConnection.StreamReader, Response.Headers, cancellationToken);
} }
/// <summary> /// <summary>
......
using System; namespace Titanium.Web.Proxy.Http
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Titanium.Web.Proxy.Http
{ {
public static class KnownHeaders public static class KnownHeaders
{ {
......
...@@ -100,36 +100,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -100,36 +100,6 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
internal bool CancelRequest { get; set; } internal bool CancelRequest { get; set; }
internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
{
if (BodyInternal != null)
{
return;
}
//GET request don't have a request body to read
if (!HasBody)
{
throw new BodyNotFoundException("Request don't have a body. " + "Please verify that this request is a Http POST/PUT/PATCH and request " +
"content length is greater than zero before accessing the body.");
}
if (!IsBodyRead)
{
if (Locked)
{
throw new Exception("You cannot get the request body after request is made to server.");
}
if (throwWhenNotReadYet)
{
throw new Exception("Request body is not read yet. " +
"Use SessionEventArgs.GetRequestBody() or SessionEventArgs.GetRequestBodyAsString() " +
"method to read the request body.");
}
}
}
/// <summary> /// <summary>
/// Does this request has an upgrade to websocket header? /// Does this request has an upgrade to websocket header?
/// </summary> /// </summary>
...@@ -177,12 +147,44 @@ namespace Titanium.Web.Proxy.Http ...@@ -177,12 +147,44 @@ namespace Titanium.Web.Proxy.Http
} }
} }
internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
{
if (BodyInternal != null)
{
return;
}
//GET request don't have a request body to read
if (!HasBody)
{
throw new BodyNotFoundException("Request don't have a body. " +
"Please verify that this request is a Http POST/PUT/PATCH and request " +
"content length is greater than zero before accessing the body.");
}
if (!IsBodyRead)
{
if (Locked)
{
throw new Exception("You cannot get the request body after request is made to server.");
}
if (throwWhenNotReadYet)
{
throw new Exception("Request body is not read yet. " +
"Use SessionEventArgs.GetRequestBody() or SessionEventArgs.GetRequestBodyAsString() " +
"method to read the request body.");
}
}
}
internal static string CreateRequestLine(string httpMethod, string httpUrl, Version version) internal static string CreateRequestLine(string httpMethod, string httpUrl, Version version)
{ {
return $"{httpMethod} {httpUrl} HTTP/{version.Major}.{version.Minor}"; return $"{httpMethod} {httpUrl} HTTP/{version.Major}.{version.Minor}";
} }
internal static void ParseRequestLine(string httpCmd, out string httpMethod, out string httpUrl, out Version version) internal static void ParseRequestLine(string httpCmd, out string httpMethod, out string httpUrl,
out Version version)
{ {
//break up the line into three components (method, remote URL & Http Version) //break up the line into three components (method, remote URL & Http Version)
var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3); var httpCmdSplit = httpCmd.Split(ProxyConstants.SpaceSplit, 3);
...@@ -196,11 +198,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -196,11 +198,6 @@ namespace Titanium.Web.Proxy.Http
httpMethod = httpCmdSplit[0]; httpMethod = httpCmdSplit[0];
if (!IsAllUpper(httpMethod)) if (!IsAllUpper(httpMethod))
{ {
//method should be upper cased: https://tools.ietf.org/html/rfc7231#section-4
//todo: create protocol violation message
//fix it
httpMethod = httpMethod.ToUpper(); httpMethod = httpMethod.ToUpper();
} }
......
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Compression; using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -23,6 +21,11 @@ namespace Titanium.Web.Proxy.Http ...@@ -23,6 +21,11 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
private string bodyString; private string bodyString;
/// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters
/// </summary>
internal bool OriginalHasBody;
/// <summary> /// <summary>
/// Keeps the body data after the session is finished /// Keeps the body data after the session is finished
/// </summary> /// </summary>
...@@ -145,9 +148,21 @@ namespace Titanium.Web.Proxy.Http ...@@ -145,9 +148,21 @@ namespace Titanium.Web.Proxy.Http
public abstract bool HasBody { get; } public abstract bool HasBody { get; }
/// <summary> /// <summary>
/// Store weather the original request/response has body or not, since the user may change the parameters /// Body as string
/// Use the encoding specified to decode the byte[] data to string
/// </summary> /// </summary>
internal bool OriginalHasBody; [Browsable(false)]
public string BodyString => bodyString ?? (bodyString = Encoding.GetString(Body));
/// <summary>
/// Was the body read by user?
/// </summary>
public bool IsBodyRead { get; internal set; }
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// </summary>
internal bool Locked { get; set; }
internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true); internal abstract void EnsureBodyAvailable(bool throwWhenNotReadYet = true);
...@@ -205,23 +220,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -205,23 +220,6 @@ namespace Titanium.Web.Proxy.Http
return null; return null;
} }
/// <summary>
/// Body as string
/// Use the encoding specified to decode the byte[] data to string
/// </summary>
[Browsable(false)]
public string BodyString => bodyString ?? (bodyString = Encoding.GetString(Body));
/// <summary>
/// Was the body read by user?
/// </summary>
public bool IsBodyRead { get; internal set; }
/// <summary>
/// Is the request/response no more modifyable by user (user callbacks complete?)
/// </summary>
internal bool Locked { get; set; }
internal void UpdateContentLength() internal void UpdateContentLength()
{ {
ContentLength = IsChunked ? -1 : BodyInternal?.Length ?? 0; ContentLength = IsChunked ? -1 : BodyInternal?.Length ?? 0;
......
...@@ -13,6 +13,21 @@ namespace Titanium.Web.Proxy.Http ...@@ -13,6 +13,21 @@ namespace Titanium.Web.Proxy.Http
[TypeConverter(typeof(ExpandableObjectConverter))] [TypeConverter(typeof(ExpandableObjectConverter))]
public class Response : RequestResponseBase public class Response : RequestResponseBase
{ {
/// <summary>
/// Constructor.
/// </summary>
public Response()
{
}
/// <summary>
/// Constructor.
/// </summary>
public Response(byte[] body)
{
Body = body;
}
/// <summary> /// <summary>
/// Response Status Code. /// Response Status Code.
/// </summary> /// </summary>
...@@ -79,21 +94,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -79,21 +94,6 @@ namespace Titanium.Web.Proxy.Http
internal bool TerminateResponse { get; set; } internal bool TerminateResponse { get; set; }
internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
{
if (BodyInternal != null)
{
return;
}
if (!IsBodyRead && throwWhenNotReadYet)
{
throw new Exception("Response body is not read yet. " +
"Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() " +
"method to read the response body.");
}
}
/// <summary> /// <summary>
/// Is response 100-continue /// Is response 100-continue
/// </summary> /// </summary>
...@@ -104,11 +104,6 @@ namespace Titanium.Web.Proxy.Http ...@@ -104,11 +104,6 @@ namespace Titanium.Web.Proxy.Http
/// </summary> /// </summary>
public bool ExpectationFailed { get; internal set; } public bool ExpectationFailed { get; internal set; }
/// <summary>
/// Gets the resposne status.
/// </summary>
public string Status => CreateResponseLine(HttpVersion, StatusCode, StatusDescription);
/// <summary> /// <summary>
/// Gets the header text. /// Gets the header text.
/// </summary> /// </summary>
...@@ -117,7 +112,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -117,7 +112,7 @@ namespace Titanium.Web.Proxy.Http
get get
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine(Status); sb.AppendLine(CreateResponseLine(HttpVersion, StatusCode, StatusDescription));
foreach (var header in Headers) foreach (var header in Headers)
{ {
sb.AppendLine(header.ToString()); sb.AppendLine(header.ToString());
...@@ -128,19 +123,19 @@ namespace Titanium.Web.Proxy.Http ...@@ -128,19 +123,19 @@ namespace Titanium.Web.Proxy.Http
} }
} }
/// <summary> internal override void EnsureBodyAvailable(bool throwWhenNotReadYet = true)
/// Constructor.
/// </summary>
public Response()
{ {
if (BodyInternal != null)
{
return;
} }
/// <summary> if (!IsBodyRead && throwWhenNotReadYet)
/// Constructor.
/// </summary>
public Response(byte[] body)
{ {
Body = body; throw new Exception("Response body is not read yet. " +
"Use SessionEventArgs.GetResponseBody() or SessionEventArgs.GetResponseBodyAsString() " +
"method to read the response body.");
}
} }
internal static string CreateResponseLine(Version version, int statusCode, string statusDescription) internal static string CreateResponseLine(Version version, int statusCode, string statusDescription)
...@@ -148,7 +143,8 @@ namespace Titanium.Web.Proxy.Http ...@@ -148,7 +143,8 @@ namespace Titanium.Web.Proxy.Http
return $"HTTP/{version.Major}.{version.Minor} {statusCode} {statusDescription}"; return $"HTTP/{version.Major}.{version.Minor} {statusCode} {statusDescription}";
} }
internal static void ParseResponseLine(string httpStatus, out Version version, out int statusCode, out string statusDescription) internal static void ParseResponseLine(string httpStatus, out Version version, out int statusCode,
out string statusDescription)
{ {
var httpResult = httpStatus.Split(ProxyConstants.SpaceSplit, 3); var httpResult = httpStatus.Split(ProxyConstants.SpaceSplit, 3);
if (httpResult.Length != 3) if (httpResult.Length != 3)
......
using System.Net; using System.Net;
using System.Web;
namespace Titanium.Web.Proxy.Http.Responses namespace Titanium.Web.Proxy.Http.Responses
{ {
...@@ -15,9 +16,13 @@ namespace Titanium.Web.Proxy.Http.Responses ...@@ -15,9 +16,13 @@ namespace Titanium.Web.Proxy.Http.Responses
{ {
StatusCode = (int)status; StatusCode = (int)status;
#if NET45
StatusDescription = HttpWorkerRequest.GetStatusDescription(StatusCode);
#else
//todo: this is not really correct, status description should contain spaces, too //todo: this is not really correct, status description should contain spaces, too
//see: https://tools.ietf.org/html/rfc7231#section-6.1 //see: https://tools.ietf.org/html/rfc7231#section-6.1
StatusDescription = status.ToString(); StatusDescription = status.ToString();
#endif
} }
/// <summary> /// <summary>
......
using System; using System.Net;
using System.Net;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
...@@ -13,6 +12,17 @@ namespace Titanium.Web.Proxy.Models ...@@ -13,6 +12,17 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class ExplicitProxyEndPoint : ProxyEndPoint public class ExplicitProxyEndPoint : ProxyEndPoint
{ {
/// <summary>
/// Constructor.
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="decryptSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port,
decryptSsl)
{
}
internal bool IsSystemHttpProxy { get; set; } internal bool IsSystemHttpProxy { get; set; }
internal bool IsSystemHttpsProxy { get; set; } internal bool IsSystemHttpsProxy { get; set; }
...@@ -25,7 +35,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -25,7 +35,8 @@ namespace Titanium.Web.Proxy.Models
/// <summary> /// <summary>
/// Intercept tunnel connect request /// Intercept tunnel connect request
/// Valid only for explicit endpoints /// Valid only for explicit endpoints
/// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl"/> property to false if this HTTP connect request should'nt be decrypted and instead be relayed /// Set the <see cref="TunnelConnectSessionEventArgs.DecryptSsl" /> property to false if this HTTP connect request
/// should'nt be decrypted and instead be relayed
/// </summary> /// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest; public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectRequest;
...@@ -35,17 +46,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -35,17 +46,8 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectResponse; public event AsyncEventHandler<TunnelConnectSessionEventArgs> BeforeTunnelConnectResponse;
/// <summary> internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer,
/// Constructor. TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
/// </summary>
/// <param name="ipAddress"></param>
/// <param name="port"></param>
/// <param name="decryptSsl"></param>
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port, decryptSsl)
{
}
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)
{ {
if (BeforeTunnelConnectRequest != null) if (BeforeTunnelConnectRequest != null)
{ {
...@@ -53,7 +55,8 @@ namespace Titanium.Web.Proxy.Models ...@@ -53,7 +55,8 @@ namespace Titanium.Web.Proxy.Models
} }
} }
internal async Task InvokeBeforeTunnectConnectResponse(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false) internal async Task InvokeBeforeTunnectConnectResponse(ProxyServer proxyServer,
TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc, bool isClientHello = false)
{ {
if (BeforeTunnelConnectResponse != null) if (BeforeTunnelConnectResponse != null)
{ {
......
...@@ -8,11 +8,13 @@ namespace Titanium.Web.Proxy.Models ...@@ -8,11 +8,13 @@ namespace Titanium.Web.Proxy.Models
/// </summary> /// </summary>
public class ExternalProxy public class ExternalProxy
{ {
private static readonly Lazy<NetworkCredential> defaultCredentials = new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials); private static readonly Lazy<NetworkCredential> defaultCredentials =
new Lazy<NetworkCredential>(() => CredentialCache.DefaultNetworkCredentials);
private string userName;
private string password; private string password;
private string userName;
/// <summary> /// <summary>
/// Use default windows credentials? /// Use default windows credentials?
/// </summary> /// </summary>
......
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