Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ private HttpWindowsProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle? sess
{
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(proxyHelper, $"ManualSettingsUsed, {proxyHelper.Proxy}");

_secureProxy = MultiProxy.Parse(_failedProxies, proxyHelper.Proxy, true);
_insecureProxy = MultiProxy.Parse(_failedProxies, proxyHelper.Proxy, false);
_secureProxy = MultiProxy.ParseManualSettings(_failedProxies, proxyHelper.Proxy, true);
_insecureProxy = MultiProxy.ParseManualSettings(_failedProxies, proxyHelper.Proxy, false);

if (!string.IsNullOrWhiteSpace(proxyHelper.ProxyBypass))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ private MultiProxy(FailedProxyCache failedProxyCache, string proxyConfig, bool s
/// <param name="failedProxyCache">The cache of failed proxy requests to employ.</param>
/// <param name="proxyConfig">The WinHTTP proxy config to parse.</param>
/// <param name="secure">If true, return proxies suitable for use with a secure connection. If false, return proxies suitable for an insecure connection.</param>
public static MultiProxy Parse(FailedProxyCache failedProxyCache, string? proxyConfig, bool secure)
public static MultiProxy ParseManualSettings(FailedProxyCache failedProxyCache, string? proxyConfig, bool secure)
{
Debug.Assert(failedProxyCache != null);

Uri[] uris = Array.Empty<Uri>();

ReadOnlySpan<char> span = proxyConfig;
while (TryParseProxyConfigPart(span, secure, out Uri? uri, out int charactersConsumed))
while (TryParseProxyConfigPart(span, secure, manualSettingsUsed: true, out Uri? uri, out int charactersConsumed))
{
int idx = uris.Length;

Expand Down Expand Up @@ -171,7 +171,7 @@ private bool ReadNextHelper([NotNullWhen(true)] out Uri? uri, out bool isFinalPr
Debug.Assert(_proxyConfig != null);
if (_currentIndex < _proxyConfig.Length)
{
bool hasProxy = TryParseProxyConfigPart(_proxyConfig.AsSpan(_currentIndex), _secure, out uri!, out int charactersConsumed);
bool hasProxy = TryParseProxyConfigPart(_proxyConfig.AsSpan(_currentIndex), _secure, manualSettingsUsed: false, out uri!, out int charactersConsumed);

_currentIndex += charactersConsumed;
Debug.Assert(_currentIndex <= _proxyConfig.Length);
Expand All @@ -193,7 +193,7 @@ private bool ReadNextHelper([NotNullWhen(true)] out Uri? uri, out bool isFinalPr
/// The strings are a semicolon or whitespace separated list, with each entry in the following format:
/// ([&lt;scheme&gt;=][&lt;scheme&gt;"://"]&lt;server&gt;[":"&lt;port&gt;])
/// </remarks>
private static bool TryParseProxyConfigPart(ReadOnlySpan<char> proxyString, bool secure, [NotNullWhen(true)] out Uri? uri, out int charactersConsumed)
private static bool TryParseProxyConfigPart(ReadOnlySpan<char> proxyString, bool secure, bool manualSettingsUsed, [NotNullWhen(true)] out Uri? uri, out int charactersConsumed)
{
const int SECURE_FLAG = 1;
const int INSECURE_FLAG = 2;
Expand Down Expand Up @@ -235,12 +235,18 @@ private static bool TryParseProxyConfigPart(ReadOnlySpan<char> proxyString, bool

if (proxyString.StartsWith("http://"))
{
proxyType = INSECURE_FLAG;
if (!manualSettingsUsed)
{
proxyType = INSECURE_FLAG;
}
proxyString = proxyString.Slice("http://".Length);
}
else if (proxyString.StartsWith("https://"))
{
proxyType = SECURE_FLAG;
if (!manualSettingsUsed)
{
proxyType = SECURE_FLAG;
}
proxyString = proxyString.Slice("https://".Length);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,23 @@ await RemoteExecutor.Invoke((proxyString, insecureProxy, secureProxy) =>
}, rawProxyString, rawInsecureUri ?? string.Empty, rawSecureUri ?? string.Empty).DisposeAsync();
}

public static TheoryData<string, string, string> ProxyParsingData =>
new TheoryData<string, string, string>
{
{ "http://proxy.secure-and-insecure.com", secureAndInsecureProxyUri, secureAndInsecureProxyUri },
{ "http=http://proxy.insecure.com", insecureProxyUri, null },
{ "http=proxy.insecure.com", insecureProxyUri, null },
{ "http=http://proxy.insecure.com", insecureProxyUri, null },
{ "https://proxy.secure.com", secureProxyUri, secureProxyUri },
{ "https=proxy.secure.com", null, secureProxyUri },
{ "https=https://proxy.secure.com", null, secureProxyUri },
{ "http=https://proxy.secure.com", secureProxyUri, null },
{ "https=http://proxy.insecure.com", null, insecureProxyUri },
{ "proxy.secure-and-insecure.com", secureAndInsecureProxyUri, secureAndInsecureProxyUri },
};

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(nameof(ProxyParsingData))]
[MemberData(nameof(ProxyPacParsingData))]
public async Task HttpProxy_WindowsProxy_PAC_Loaded(string rawProxyString, string rawInsecureUri, string rawSecureUri)
{
await RemoteExecutor.Invoke((proxyString, insecureProxy, secureProxy) =>
Expand Down Expand Up @@ -91,7 +106,7 @@ await RemoteExecutor.Invoke((proxyString, insecureProxy, secureProxy) =>
}, rawProxyString, rawInsecureUri ?? string.Empty, rawSecureUri ?? string.Empty).DisposeAsync();
}

public static TheoryData<string, string, string> ProxyParsingData =>
public static TheoryData<string, string, string> ProxyPacParsingData =>
new TheoryData<string, string, string>
{
{ "http://proxy.insecure.com", insecureProxyUri, null },
Expand Down Expand Up @@ -237,34 +252,22 @@ await RemoteExecutor.Invoke((proxyString) =>

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[MemberData(nameof(HttpProxy_Multi_Data))]
public async Task HttpProxy_Multi_Success(bool manualConfig, string proxyConfig, string url, string expected)
public async Task HttpProxy_Multi_Success(string proxyConfig, string url, string expected)
{
await RemoteExecutor.Invoke((manualConfigValue, proxyConfigValue, urlValue, expectedValue) =>
await RemoteExecutor.Invoke((proxyConfigValue, urlValue, expectedValue) =>
{
bool manual = bool.Parse(manualConfigValue);
Uri requestUri = new Uri(urlValue);
string[] expectedUris = expectedValue.Split(';', StringSplitOptions.RemoveEmptyEntries);

TestControl.ResetAll();

if (manual)
{
FakeRegistry.WinInetProxySettings.Proxy = proxyConfigValue;
}
else
{
FakeRegistry.WinInetProxySettings.AutoConfigUrl = "http://dummy.com";
}
FakeRegistry.WinInetProxySettings.AutoConfigUrl = "http://dummy.com";

Assert.True(HttpWindowsProxy.TryCreate(out IWebProxy p));
HttpWindowsProxy wp = Assert.IsType<HttpWindowsProxy>(p);

if (!manual)
{
// Now that HttpWindowsProxy has been constructed to use autoconfig,
// set Proxy which will be used by Fakes for all the per-URL calls.
FakeRegistry.WinInetProxySettings.Proxy = proxyConfigValue;
}
// Now that HttpWindowsProxy has been constructed to use autoconfig,
// set Proxy which will be used by Fakes for all the per-URL calls.
FakeRegistry.WinInetProxySettings.Proxy = proxyConfigValue;

MultiProxy multi = wp.GetMultiProxy(requestUri);

Expand All @@ -277,19 +280,16 @@ await RemoteExecutor.Invoke((manualConfigValue, proxyConfigValue, urlValue, expe
}

Assert.False(multi.ReadNext(out _, out _));
}, manualConfig.ToString(), proxyConfig, url, expected).DisposeAsync();
}, proxyConfig, url, expected).DisposeAsync();
}

public static IEnumerable<object[]> HttpProxy_Multi_Data()
{
for (int i = 0; i < 2; ++i)
{
yield return new object[] { i == 0, "http://proxy.com", "http://request.com", "http://proxy.com" };
yield return new object[] { i == 0, "http://proxy.com https://secure-proxy.com", "http://request.com", "http://proxy.com" };
yield return new object[] { i == 0, "http://proxy-a.com https://secure-proxy.com http://proxy-b.com", "http://request.com", "http://proxy-a.com;http://proxy-b.com" };
yield return new object[] { i == 0, "http://proxy-a.com https://secure-proxy.com http://proxy-b.com", "https://request.com", "http://secure-proxy.com" };
yield return new object[] { i == 0, "http://proxy-a.com https://secure-proxy-a.com http://proxy-b.com https://secure-proxy-b.com https://secure-proxy-c.com", "https://request.com", "http://secure-proxy-a.com;http://secure-proxy-b.com;http://secure-proxy-c.com" };
}
yield return new object[] { "http://proxy.com", "http://request.com", "http://proxy.com" };
yield return new object[] { "http://proxy.com https://secure-proxy.com", "http://request.com", "http://proxy.com" };
yield return new object[] { "http://proxy-a.com https://secure-proxy.com http://proxy-b.com", "http://request.com", "http://proxy-a.com;http://proxy-b.com" };
yield return new object[] { "http://proxy-a.com https://secure-proxy.com http://proxy-b.com", "https://request.com", "http://secure-proxy.com" };
yield return new object[] { "http://proxy-a.com https://secure-proxy-a.com http://proxy-b.com https://secure-proxy-b.com https://secure-proxy-c.com", "https://request.com", "http://secure-proxy-a.com;http://secure-proxy-b.com;http://secure-proxy-c.com" };
}

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
Expand Down