Commit 71b961b9 authored by Honfika's avatar Honfika

Upstream proxy tests + localhost bypass fix

parent 18ff30f2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Helpers.WinHttp;
namespace Titanium.Web.Proxy.UnitTests
{
[TestClass]
public class SystemProxyTest
{
[TestMethod]
public void CompareProxyAdddressReturendByWebProxyAndWinHttpProxyResolver()
{
var proxyManager = new SystemProxyManager();
try
{
CompareUrls();
proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.Http);
CompareUrls();
proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.Https);
CompareUrls();
proxyManager.SetProxy("127.0.0.1", 8000, ProxyProtocolType.AllHttp);
CompareUrls();
// for this test you need to add a proxy.pac file to a local webserver
//function FindProxyForURL(url, host)
//{
// if (shExpMatch(host, "google.com"))
// {
// return "PROXY 127.0.0.1:8888";
// }
// return "DIRECT";
//}
//proxyManager.SetAutoProxyUrl("http://localhost/proxy.pac");
//CompareUrls();
}
finally
{
proxyManager.RestoreOriginalSettings();
}
}
private void CompareUrls()
{
var webProxy = WebRequest.GetSystemWebProxy();
var resolver = new WinHttpWebProxyFinder();
resolver.LoadFromIE();
resolver.BypassOnLocal = WebProxy.GetDefaultProxy().BypassProxyOnLocal;
CompareProxy(webProxy, resolver, "http://localhost");
CompareProxy(webProxy, resolver, "https://localhost");
string hostName = null;
try
{
hostName = Dns.GetHostName();
}
catch{}
if (hostName != null)
{
CompareProxy(webProxy, resolver, "http://" + hostName);
CompareProxy(webProxy, resolver, "https://" + hostName);
}
CompareProxy(webProxy, resolver, "http://google.com");
CompareProxy(webProxy, resolver, "https://google.com");
CompareProxy(webProxy, resolver, "http://bing.com");
CompareProxy(webProxy, resolver, "https://bing.com");
}
private void CompareProxy(IWebProxy webProxy, WinHttpWebProxyFinder resolver, string url)
{
var uri = new Uri(url);
var expectedProxyUri = webProxy.GetProxy(uri);
var proxy = resolver.GetProxy(uri);
if (expectedProxyUri == uri)
{
// no proxy
Assert.AreEqual(proxy, null);
return;
}
Assert.AreEqual(expectedProxyUri.ToString(), $"http://{proxy.HostName}:{proxy.Port}/");
}
}
}
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
<Compile Include="CertificateManagerTests.cs" /> <Compile Include="CertificateManagerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ProxyServerTests.cs" /> <Compile Include="ProxyServerTests.cs" />
<Compile Include="SystemProxyTest.cs" />
<Compile Include="WinAuthTests.cs" /> <Compile Include="WinAuthTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Microsoft.Win32; using Microsoft.Win32;
// Helper classes for setting system proxy settings // Helper classes for setting system proxy settings
...@@ -212,6 +211,18 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -212,6 +211,18 @@ namespace Titanium.Web.Proxy.Helpers
} }
} }
internal void SetAutoProxyUrl(string url)
{
var reg = Registry.CurrentUser.OpenSubKey(regKeyInternetSettings, true);
if (reg != null)
{
SaveOriginalProxyConfiguration(reg);
reg.SetValue(regAutoConfigUrl, url);
Refresh();
}
}
internal void RestoreOriginalSettings() internal void RestoreOriginalSettings()
{ {
if (originalValues == null) if (originalValues == null)
...@@ -291,6 +302,11 @@ namespace Titanium.Web.Proxy.Helpers ...@@ -291,6 +302,11 @@ namespace Titanium.Web.Proxy.Helpers
private void SaveOriginalProxyConfiguration(RegistryKey reg) private void SaveOriginalProxyConfiguration(RegistryKey reg)
{ {
if (originalValues != null)
{
return;
}
originalValues = GetProxyInfoFromRegistry(reg); originalValues = GetProxyInfoFromRegistry(reg);
} }
......
...@@ -3,8 +3,8 @@ using System.Collections.Generic; ...@@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Net; using System.Net;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Policy;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Models;
namespace Titanium.Web.Proxy.Helpers.WinHttp namespace Titanium.Web.Proxy.Helpers.WinHttp
{ {
...@@ -18,6 +18,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -18,6 +18,8 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
public ProxyInfo ProxyInfo { get; internal set; } public ProxyInfo ProxyInfo { get; internal set; }
public bool BypassOnLocal { get; internal set; }
public Uri AutomaticConfigurationScript { get; internal set; } public Uri AutomaticConfigurationScript { get; internal set; }
public bool AutomaticallyDetectSettings { get; internal set; } public bool AutomaticallyDetectSettings { get; internal set; }
...@@ -38,16 +40,17 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -38,16 +40,17 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
} }
} }
public bool GetProxies(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;
if (AutomaticallyDetectSettings && !autoDetectFailed) if (AutomaticallyDetectSettings && !autoDetectFailed)
{ {
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetProxies(destination, null, out proxyListString); errorCode = (NativeMethods.WinHttp.ErrorCodes)GetAutoProxies(destination, null, out proxyListString);
autoDetectFailed = IsErrorFatalForAutoDetect(errorCode); autoDetectFailed = IsErrorFatalForAutoDetect(errorCode);
if (errorCode == NativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme) if (errorCode == NativeMethods.WinHttp.ErrorCodes.UnrecognizedScheme)
{ {
...@@ -55,11 +58,14 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -55,11 +58,14 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return false; return false;
} }
} }
if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode)) if (AutomaticConfigurationScript != null && IsRecoverableAutoProxyError(errorCode))
errorCode = (NativeMethods.WinHttp.ErrorCodes)GetProxies(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))
{ {
proxyListString = RemoveWhitespaces(proxyListString); proxyListString = RemoveWhitespaces(proxyListString);
...@@ -69,6 +75,57 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -69,6 +75,57 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
return true; return true;
} }
public ExternalProxy GetProxy(Uri destination)
{
IList<string> proxies;
if (GetAutoProxies(destination, out proxies))
{
if (proxies == null)
{
return null;
}
string proxy = proxies[0];
int port = 80;
if (proxy.Contains(":"))
{
var parts = proxy.Split(new[] { ':' }, 2);
proxy = parts[0];
port = int.Parse(parts[1]);
}
// TODO: Apply authorization
var systemProxy = new ExternalProxy
{
HostName = proxy,
Port = port,
};
return systemProxy;
}
if (IsBypassedManual(destination))
return null;
var protocolType = ProxyInfo.ParseProtocolType(destination.Scheme);
if (protocolType.HasValue)
{
HttpSystemProxyValue value = null;
if (ProxyInfo?.Proxies?.TryGetValue(protocolType.Value, out value) == true)
{
var systemProxy = new ExternalProxy
{
HostName = value.HostName,
Port = value.Port,
};
return systemProxy;
}
}
return null;
}
public void LoadFromIE() public void LoadFromIE()
{ {
var pi = GetProxyInfo(); var pi = GetProxyInfo();
...@@ -77,6 +134,44 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -77,6 +134,44 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
AutomaticConfigurationScript = pi.AutoConfigUrl == null ? null : new Uri(pi.AutoConfigUrl); AutomaticConfigurationScript = pi.AutoConfigUrl == null ? null : new Uri(pi.AutoConfigUrl);
} }
private bool IsBypassedManual(Uri host)
{
if (host.IsLoopback || BypassOnLocal && IsLocal(host))
return true;
return false;
}
private bool IsLocal(Uri host)
{
try
{
// get host IP addresses
IPAddress[] hostIPs = Dns.GetHostAddresses(host.Host);
// get local IP addresses
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
// test if any host IP equals to any local IP or to localhost
foreach (IPAddress hostIP in hostIPs)
{
// is localhost
if (IPAddress.IsLoopback(hostIP)) return true;
// is local address
foreach (IPAddress localIP in localIPs)
{
if (hostIP.Equals(localIP)) return true;
}
}
}
catch
{
}
return false;
}
private ProxyInfo GetProxyInfo() private ProxyInfo GetProxyInfo()
{ {
var proxyConfig = new NativeMethods.WinHttp.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG(); var proxyConfig = new NativeMethods.WinHttp.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG();
...@@ -129,7 +224,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -129,7 +224,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
session.Close(); session.Close();
} }
private int GetProxies(Uri destination, Uri scriptLocation, out string proxyListString) private int GetAutoProxies(Uri destination, Uri scriptLocation, out string proxyListString)
{ {
int num = 0; int num = 0;
var autoProxyOptions = new NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS(); var autoProxyOptions = new NativeMethods.WinHttp.WINHTTP_AUTOPROXY_OPTIONS();
...@@ -146,6 +241,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp ...@@ -146,6 +241,7 @@ namespace Titanium.Web.Proxy.Helpers.WinHttp
autoProxyOptions.AutoConfigUrl = scriptLocation.ToString(); autoProxyOptions.AutoConfigUrl = scriptLocation.ToString();
autoProxyOptions.AutoDetectFlags = NativeMethods.WinHttp.AutoDetectType.None; autoProxyOptions.AutoDetectFlags = NativeMethods.WinHttp.AutoDetectType.None;
} }
if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString)) if (!WinHttpGetProxyForUrl(destination.ToString(), ref autoProxyOptions, out proxyListString))
{ {
num = GetLastWin32Error(); num = GetLastWin32Error();
......
...@@ -613,46 +613,8 @@ namespace Titanium.Web.Proxy ...@@ -613,46 +613,8 @@ namespace Titanium.Web.Proxy
/// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns> /// <returns><see cref="ExternalProxy"/> instance containing valid proxy configuration from PAC/WAPD scripts if any exists.</returns>
private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgs sessionEventArgs) private Task<ExternalProxy> GetSystemUpStreamProxy(SessionEventArgs sessionEventArgs)
{ {
var uri = sessionEventArgs.WebSession.Request.RequestUri; var proxy = systemProxyResolver.GetProxy(sessionEventArgs.WebSession.Request.RequestUri);
IList<string> proxies; return Task.FromResult(proxy);
if (systemProxyResolver.GetProxies(uri, out proxies) && proxies != null)
{
string proxy = proxies[0];
int port = 80;
if (proxy.Contains(":"))
{
var parts = proxy.Split(new[] { ':' }, 2);
proxy = parts[0];
port = int.Parse(parts[1]);
}
// TODO: Apply authorization
var systemProxy = new ExternalProxy
{
HostName = proxy,
Port = port,
};
return Task.FromResult(systemProxy);
}
var protocolType = ProxyInfo.ParseProtocolType(uri.Scheme);
if (protocolType.HasValue)
{
HttpSystemProxyValue value = null;
if (systemProxyResolver.ProxyInfo?.Proxies?.TryGetValue(protocolType.Value, out value) == true)
{
var systemProxy = new ExternalProxy
{
HostName = value.HostName,
Port = value.Port,
};
return Task.FromResult(systemProxy);
}
}
return Task.FromResult((ExternalProxy)null);
} }
......
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