Bug 1392272 - P1: [windows] Monitor system proxy changes, r=necko-reviewers,dragana

Differential Revision: https://phabricator.services.mozilla.com/D127724
This commit is contained in:
Kershaw Chang 2021-11-08 09:00:26 +00:00
parent 0992acc367
commit 1b01ccfacd
5 changed files with 593 additions and 95 deletions

View file

@ -72,6 +72,7 @@ SpinEventLoop
StressRunner
SuicideManager
SuicideThread
System Proxy
TEQ AwaitIdle
TelemetryModule
Test Thread

View file

@ -9673,6 +9673,11 @@
value: false
mirror: always
- name: network.proxy.detect_system_proxy_changes
type: RelaxedAtomicBool
value: false
mirror: always
# Some requests during a page load are marked as "tail", mainly trackers, but not only.
# This pref controls whether such requests are put to the tail, behind other requests
# emerging during page loading process.

199
netwerk/base/ProxyConfig.h Normal file
View file

@ -0,0 +1,199 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_netwerk_base_proxy_config_h
#define mozilla_netwerk_base_proxy_config_h
#include <map>
#include "nsCRT.h"
#include "nsString.h"
#include "nsTArray.h"
// NOTE: This file is inspired by Chromium's code.
// https://source.chromium.org/chromium/chromium/src/+/main:net/proxy_resolution/proxy_config.h.
namespace mozilla {
namespace net {
// ProxyServer stores the {type, host, port} of a proxy server.
// ProxyServer is immutable.
class ProxyServer final {
public:
enum class ProxyType {
DIRECT = 0,
HTTP,
HTTPS,
SOCKS,
SOCKS4,
SOCKS5,
FTP,
// DEFAULT is a special type used on windows only.
DEFAULT
};
ProxyServer() = default;
ProxyServer(ProxyType aType, const nsACString& aHost, int32_t aPort)
: mType(aType), mHost(aHost), mPort(aPort) {}
const nsCString& Host() const { return mHost; }
int32_t Port() const { return mPort; }
ProxyType Type() const { return mType; }
void ToHostAndPortStr(nsACString& aOutput) {
aOutput.Truncate();
if (mType == ProxyType::DIRECT) {
return;
}
aOutput.Assign(mHost);
if (mPort != -1) {
aOutput.Append(':');
aOutput.AppendInt(mPort);
}
}
bool operator==(const ProxyServer& aOther) const {
return mType == aOther.mType && mHost == aOther.mHost &&
mPort == aOther.mPort;
}
bool operator!=(const ProxyServer& aOther) const {
return !(*this == aOther);
}
private:
ProxyType mType{ProxyType::DIRECT};
nsCString mHost;
int32_t mPort{-1};
};
// This class includes the information about proxy configuration.
// It contains enabled proxy servers, exception list, and the url of PAC
// script.
class ProxyConfig {
public:
struct ProxyRules {
ProxyRules() = default;
~ProxyRules() = default;
std::map<ProxyServer::ProxyType, ProxyServer> mProxyServers;
};
struct ProxyBypassRules {
ProxyBypassRules() = default;
~ProxyBypassRules() = default;
CopyableTArray<nsCString> mExceptions;
};
ProxyConfig() = default;
ProxyConfig(const ProxyConfig& config);
~ProxyConfig() = default;
ProxyRules& Rules() { return mRules; }
const ProxyRules& Rules() const { return mRules; }
ProxyBypassRules& ByPassRules() { return mBypassRules; }
const ProxyBypassRules& ByPassRules() const { return mBypassRules; }
void SetPACUrl(const nsACString& aUrl) { mPACUrl = aUrl; }
const nsCString& PACUrl() const { return mPACUrl; }
static ProxyServer::ProxyType ToProxyType(const char* aType) {
if (!aType) {
return ProxyServer::ProxyType::DIRECT;
}
if (nsCRT::strcasecmp(aType, "http") == 0) {
return ProxyServer::ProxyType::HTTP;
}
if (nsCRT::strcasecmp(aType, "https") == 0) {
return ProxyServer::ProxyType::HTTPS;
}
if (nsCRT::strcasecmp(aType, "socks") == 0) {
return ProxyServer::ProxyType::SOCKS;
}
if (nsCRT::strcasecmp(aType, "socks4") == 0) {
return ProxyServer::ProxyType::SOCKS4;
}
if (nsCRT::strcasecmp(aType, "socks5") == 0) {
return ProxyServer::ProxyType::SOCKS5;
}
if (nsCRT::strcasecmp(aType, "ftp") == 0) {
return ProxyServer::ProxyType::FTP;
}
return ProxyServer::ProxyType::DIRECT;
}
static void SetProxyResult(const char* aType, const nsACString& aHostPort,
nsACString& aResult) {
aResult.AssignASCII(aType);
aResult.Append(' ');
aResult.Append(aHostPort);
}
static void SetProxyResultDirect(nsACString& aResult) {
// For whatever reason, a proxy is not to be used.
aResult.AssignLiteral("DIRECT");
}
static void ProxyStrToResult(const nsACString& aSpecificProxy,
const nsACString& aDefaultProxy,
const nsACString& aSocksProxy,
nsACString& aResult) {
if (!aSpecificProxy.IsEmpty()) {
SetProxyResult("PROXY", aSpecificProxy,
aResult); // Protocol-specific proxy.
} else if (!aDefaultProxy.IsEmpty()) {
SetProxyResult("PROXY", aDefaultProxy, aResult); // Default proxy.
} else if (!aSocksProxy.IsEmpty()) {
SetProxyResult("SOCKS", aSocksProxy, aResult); // SOCKS proxy.
} else {
SetProxyResultDirect(aResult); // Direct connection.
}
}
void GetProxyString(const nsACString& aScheme, nsACString& aResult) {
SetProxyResultDirect(aResult);
nsAutoCString specificProxy;
nsAutoCString defaultProxy;
nsAutoCString socksProxy;
nsAutoCString prefix;
ToLowerCase(aScheme, prefix);
ProxyServer::ProxyType type = ProxyConfig::ToProxyType(prefix.get());
for (auto& [key, value] : mRules.mProxyServers) {
// Break the loop if we found a specific proxy.
if (key == type) {
value.ToHostAndPortStr(specificProxy);
break;
} else if (key == ProxyServer::ProxyType::DEFAULT) {
value.ToHostAndPortStr(defaultProxy);
} else if (key == ProxyServer::ProxyType::SOCKS) {
value.ToHostAndPortStr(socksProxy);
}
}
ProxyStrToResult(specificProxy, defaultProxy, socksProxy, aResult);
}
private:
nsCString mPACUrl;
ProxyRules mRules;
ProxyBypassRules mBypassRules;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_netwerk_base_proxy_config_h

View file

@ -16,3 +16,7 @@ XPCOM_MANIFESTS += [
]
FINAL_LIBRARY = "xul"
LOCAL_INCLUDES += [
"/netwerk/base",
]

View file

@ -6,30 +6,52 @@
#include <windows.h>
#include <ras.h>
#include <wininet.h>
#include <functional>
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/Atomics.h"
#include "nsISystemProxySettings.h"
#include "mozilla/Components.h"
#include "mozilla/Mutex.h"
#include "mozilla/Services.h"
#include "mozilla/ProfilerLabels.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/Tokenizer.h"
#include "mozilla/Unused.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIWindowsRegKey.h"
#include "nsPrintfCString.h"
#include "nsNetCID.h"
#include "nsThreadUtils.h"
#include "prnetdb.h"
#include "ProxyUtils.h"
#include "ProxyConfig.h"
class nsWindowsSystemProxySettings final : public nsISystemProxySettings {
using namespace mozilla::net;
class nsWindowsSystemProxySettings : public nsISystemProxySettings {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSISYSTEMPROXYSETTINGS
nsWindowsSystemProxySettings(){};
virtual nsresult Init() { return NS_OK; }
private:
~nsWindowsSystemProxySettings(){};
protected:
virtual ~nsWindowsSystemProxySettings() = default;
bool MatchOverride(const nsACString& aHost);
bool MatchOverrideInternal(const nsACString& aHost,
const nsACString& aOverrideRule);
bool PatternMatch(const nsACString& aHost, const nsACString& aOverride);
nsresult ReadProxyRules(
uint32_t aOptions,
const std::function<bool(uint32_t aFlags)>& aFlagsHandler,
const std::function<void(const nsACString& aRule, bool& aContinue)>&
aRuleHandler);
};
NS_IMPL_ISUPPORTS(nsWindowsSystemProxySettings, nsISystemProxySettings)
@ -43,18 +65,6 @@ nsWindowsSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) {
return NS_OK;
}
static void SetProxyResult(const char* aType, const nsACString& aHostPort,
nsACString& aResult) {
aResult.AssignASCII(aType);
aResult.Append(' ');
aResult.Append(aHostPort);
}
static void SetProxyResultDirect(nsACString& aResult) {
// For whatever reason, a proxy is not to be used.
aResult.AssignLiteral("DIRECT");
}
static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags,
nsAString& aValue) {
// Bug 1366133: InternetGetConnectedStateExW() may cause hangs
@ -93,20 +103,8 @@ static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags,
return NS_OK;
}
bool nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost) {
nsresult rv;
uint32_t flags = 0;
nsAutoString buf;
rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf);
if (NS_FAILED(rv)) return false;
NS_ConvertUTF16toUTF8 cbuf(buf);
nsAutoCString host(aHost);
int32_t start = 0;
int32_t end = cbuf.Length();
bool nsWindowsSystemProxySettings::MatchOverrideInternal(
const nsACString& aHost, const nsACString& aOverrideRule) {
// Windows formats its proxy override list in the form:
// server;server;server where 'server' is a server name pattern or IP
// address, or "<local>". "<local>" must be translated to
@ -114,26 +112,73 @@ bool nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost) {
// In a server name pattern, a '*' character matches any substring and
// all other characters must match themselves; the whole pattern must match
// the whole hostname.
nsAutoCString host(aHost);
if (aOverrideRule.EqualsLiteral("<local>")) {
PRNetAddr addr;
bool isIpAddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS);
// Don't use proxy for local hosts (plain hostname, no dots)
if (!isIpAddr && !host.Contains('.')) {
return true;
}
if (host.EqualsLiteral("127.0.0.1") || host.EqualsLiteral("::1")) {
return true;
}
} else if (PatternMatch(host, aOverrideRule)) {
return true;
}
return false;
}
bool nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost) {
nsAutoCString host(aHost);
bool foundMatch = false;
auto flagHandler = [](uint32_t aFlags) { return true; };
auto ruleHandler = [&](const nsACString& aOverrideRule, bool& aContinue) {
foundMatch = MatchOverrideInternal(aHost, aOverrideRule);
if (foundMatch) {
aContinue = false;
}
};
ReadProxyRules(INTERNET_PER_CONN_PROXY_BYPASS, flagHandler, ruleHandler);
return foundMatch;
}
nsresult nsWindowsSystemProxySettings::ReadProxyRules(
uint32_t aOptions,
const std::function<bool(uint32_t aFlags)>& aFlagsHandler,
const std::function<void(const nsACString& aRule, bool& aContinue)>&
aRuleHandler) {
uint32_t flags = 0;
nsAutoString buf;
nsresult rv = ReadInternetOption(aOptions, flags, buf);
if (NS_FAILED(rv)) {
return rv;
}
if (!aFlagsHandler(flags)) {
return NS_ERROR_FAILURE;
}
NS_ConvertUTF16toUTF8 cbuf(buf);
int32_t start = 0;
int32_t end = cbuf.Length();
while (true) {
int32_t delimiter = cbuf.FindCharInSet(" ;", start);
if (delimiter == -1) delimiter = end;
if (delimiter != start) {
const nsAutoCString override(Substring(cbuf, start, delimiter - start));
if (override.EqualsLiteral("<local>")) {
PRNetAddr addr;
bool isIpAddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS);
// Don't use proxy for local hosts (plain hostname, no dots)
if (!isIpAddr && !host.Contains('.')) {
return true;
}
if (host.EqualsLiteral("127.0.0.1") || host.EqualsLiteral("::1")) {
return true;
}
} else if (PatternMatch(host, override)) {
return true;
const nsAutoCString rule(Substring(cbuf, start, delimiter - start));
bool continueProcessing = false;
aRuleHandler(rule, continueProcessing);
if (!continueProcessing) {
return NS_OK;
}
}
@ -141,7 +186,7 @@ bool nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost) {
start = ++delimiter;
}
return false;
return NS_OK;
}
bool nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost,
@ -170,78 +215,322 @@ nsresult nsWindowsSystemProxySettings::GetProxyForURI(const nsACString& aSpec,
const nsACString& aHost,
const int32_t aPort,
nsACString& aResult) {
nsresult rv;
uint32_t flags = 0;
nsAutoString buf;
auto flagHandler = [&](uint32_t aFlags) {
if (!(aFlags & PROXY_TYPE_PROXY)) {
ProxyConfig::SetProxyResultDirect(aResult);
return false;
}
rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf);
if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) {
SetProxyResultDirect(aResult);
return NS_OK;
}
if (MatchOverride(aHost)) {
ProxyConfig::SetProxyResultDirect(aResult);
return false;
}
if (MatchOverride(aHost)) {
SetProxyResultDirect(aResult);
return NS_OK;
}
NS_ConvertUTF16toUTF8 cbuf(buf);
return true;
};
constexpr auto kSocksPrefix = "socks="_ns;
nsAutoCString prefix;
ToLowerCase(aScheme, prefix);
prefix.Append('=');
nsAutoCString specificProxy;
nsAutoCString defaultProxy;
nsAutoCString socksProxy;
int32_t start = 0;
int32_t end = cbuf.Length();
while (true) {
int32_t delimiter = cbuf.FindCharInSet(" ;", start);
if (delimiter == -1) delimiter = end;
auto ruleHandler = [&](const nsACString& aRule, bool& aContinue) {
const nsCString proxy(aRule);
aContinue = true;
if (proxy.FindChar('=') == -1) {
// If a proxy name is listed by itself, it is used as the
// default proxy for any protocols that do not have a specific
// proxy specified.
// (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
defaultProxy = proxy;
} else if (proxy.Find(prefix) == 0) {
// To list a proxy for a specific protocol, the string must
// follow the format "<protocol>=<protocol>://<proxy_name>".
// (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
specificProxy = Substring(proxy, prefix.Length());
aContinue = false;
} else if (proxy.Find(kSocksPrefix) == 0) {
// SOCKS proxy.
socksProxy = Substring(proxy, kSocksPrefix.Length()); // "socks=" length.
}
};
if (delimiter != start) {
const nsAutoCString proxy(Substring(cbuf, start, delimiter - start));
if (proxy.FindChar('=') == -1) {
// If a proxy name is listed by itself, it is used as the
// default proxy for any protocols that do not have a specific
// proxy specified.
// (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
defaultProxy = proxy;
} else if (proxy.Find(prefix) == 0) {
// To list a proxy for a specific protocol, the string must
// follow the format "<protocol>=<protocol>://<proxy_name>".
// (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
specificProxy = Substring(proxy, prefix.Length());
nsresult rv =
ReadProxyRules(INTERNET_PER_CONN_PROXY_SERVER, flagHandler, ruleHandler);
if (NS_FAILED(rv)) {
ProxyConfig::SetProxyResultDirect(aResult);
return rv;
}
ProxyConfig::ProxyStrToResult(specificProxy, defaultProxy, socksProxy,
aResult);
return NS_OK;
}
class WindowsSystemProxySettingsAsync final
: public nsWindowsSystemProxySettings,
public nsIObserver {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSISYSTEMPROXYSETTINGS
NS_DECL_NSIOBSERVER
WindowsSystemProxySettingsAsync();
nsresult Init() override;
private:
virtual ~WindowsSystemProxySettingsAsync();
void ThreadFunc();
void OnProxyConfigChangedInternal();
ProxyConfig mConfig;
nsCOMPtr<nsIThread> mBackgroundThread;
mozilla::Mutex mLock{"WindowsSystemProxySettingsAsync"};
mozilla::Atomic<bool> mInited{false};
mozilla::Atomic<bool> mTerminated{false};
};
NS_IMPL_ISUPPORTS_INHERITED(WindowsSystemProxySettingsAsync,
nsWindowsSystemProxySettings, nsIObserver);
WindowsSystemProxySettingsAsync::WindowsSystemProxySettingsAsync() = default;
WindowsSystemProxySettingsAsync::~WindowsSystemProxySettingsAsync() = default;
nsresult WindowsSystemProxySettingsAsync::Init() {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (!observerService) {
return NS_ERROR_FAILURE;
}
observerService->AddObserver(this, "xpcom-shutdown-threads", false);
nsCOMPtr<nsIThread> thread;
if (NS_FAILED(NS_NewNamedThread("System Proxy", getter_AddRefs(thread)))) {
NS_WARNING("NS_NewNamedThread failed!");
return NS_ERROR_FAILURE;
}
mBackgroundThread = std::move(thread);
nsCOMPtr<nsIRunnable> event = mozilla::NewRunnableMethod(
"WindowsSystemProxySettingsAsync::ThreadFunc", this,
&WindowsSystemProxySettingsAsync::ThreadFunc);
return mBackgroundThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
}
NS_IMETHODIMP
WindowsSystemProxySettingsAsync::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) {
if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
if (mBackgroundThread) {
mTerminated = true;
nsCOMPtr<nsIThread> thread;
{
mozilla::MutexAutoLock lock(mLock);
thread = mBackgroundThread.get();
mBackgroundThread = nullptr;
}
MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
}
}
return NS_OK;
}
void WindowsSystemProxySettingsAsync::ThreadFunc() {
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
if (NS_FAILED(rv)) {
return;
}
rv = regKey->Open(
nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
u"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"_ns,
nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv)) {
return;
}
OnProxyConfigChangedInternal();
rv = regKey->StartWatching(true);
if (NS_FAILED(rv)) {
return;
}
mInited = true;
while (!mTerminated) {
bool changed = false;
regKey->HasChanged(&changed);
if (changed) {
OnProxyConfigChangedInternal();
}
}
}
void WindowsSystemProxySettingsAsync::OnProxyConfigChangedInternal() {
ProxyConfig config;
// PAC
nsAutoCString pacUrl;
if (NS_SUCCEEDED(GetPACURI(pacUrl))) {
config.SetPACUrl(pacUrl);
}
// proxies
auto flagHandler = [&](uint32_t aFlags) {
if (!(aFlags & PROXY_TYPE_PROXY)) {
return false;
}
return true;
};
// The format of input string is like: scheme=host:port, e.g.
// "http=127.0.0.1:3128".
auto processProxyStr = [](const nsCString& aInput,
ProxyServer::ProxyType& aOutType,
nsACString& aOutHost, int32_t& aOutPort) {
aOutType = ProxyServer::ProxyType::DEFAULT;
aOutHost = EmptyCString();
aOutPort = -1;
mozilla::Tokenizer t(aInput);
mozilla::Tokenizer::Token token;
// skip over spaces
t.SkipWhites();
t.Record();
bool parsingIPv6 = false;
bool parsingPort = false;
while (t.Next(token)) {
if (token.Equals(mozilla::Tokenizer::Token::EndOfFile())) {
if (aOutHost.IsEmpty()) {
t.Claim(aOutHost);
}
break;
} else if (proxy.Find(kSocksPrefix) == 0) {
// SOCKS proxy.
socksProxy =
Substring(proxy, kSocksPrefix.Length()); // "socks=" length.
}
if (token.Equals(mozilla::Tokenizer::Token::Char('='))) {
nsAutoCString typeStr;
t.Claim(typeStr);
aOutType = ProxyConfig::ToProxyType(typeStr.get());
t.Record();
}
if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
parsingIPv6 = true;
continue;
}
if (!parsingIPv6 && token.Equals(mozilla::Tokenizer::Token::Char(':'))) {
// Port is starting. Claim the previous as host.
t.Claim(aOutHost);
t.Record();
parsingPort = true;
continue;
}
if (token.Equals(mozilla::Tokenizer::Token::Char(']'))) {
parsingIPv6 = false;
continue;
}
}
if (delimiter == end) break;
start = ++delimiter;
if (parsingPort) {
nsAutoCString portStr;
t.Claim(portStr);
nsresult rv = NS_OK;
aOutPort = portStr.ToInteger(&rv);
if (NS_FAILED(rv)) {
aOutPort = -1;
}
}
};
auto ruleHandler = [&](const nsACString& aRule, bool& aContinue) {
const nsCString proxy(aRule);
aContinue = true;
ProxyServer::ProxyType type;
nsCString host;
int32_t port = -1;
processProxyStr(proxy, type, host, port);
if (!host.IsEmpty()) {
ProxyServer server(type, host, port);
config.Rules().mProxyServers[server.Type()] = std::move(server);
}
};
// Note that reading the proxy settings from registry directly is not
// documented by Microsoft, so doing it could be risky. We still use system
// API to read proxy settings for safe.
ReadProxyRules(INTERNET_PER_CONN_PROXY_SERVER, flagHandler, ruleHandler);
auto bypassRuleHandler = [&](const nsACString& aOverrideRule,
bool& aContinue) {
aContinue = true;
config.ByPassRules().mExceptions.AppendElement(aOverrideRule);
};
auto dummyHandler = [](uint32_t aFlags) { return true; };
ReadProxyRules(INTERNET_PER_CONN_PROXY_BYPASS, dummyHandler,
bypassRuleHandler);
{
mozilla::MutexAutoLock lock(mLock);
mConfig = std::move(config);
}
}
NS_IMETHODIMP
WindowsSystemProxySettingsAsync::GetMainThreadOnly(bool* aMainThreadOnly) {
return nsWindowsSystemProxySettings::GetMainThreadOnly(aMainThreadOnly);
}
NS_IMETHODIMP WindowsSystemProxySettingsAsync::GetPACURI(nsACString& aResult) {
AUTO_PROFILER_LABEL("WindowsSystemProxySettingsAsync::GetPACURI", OTHER);
mozilla::MutexAutoLock lock(mLock);
aResult.Assign(mConfig.PACUrl());
return NS_OK;
}
NS_IMETHODIMP WindowsSystemProxySettingsAsync::GetProxyForURI(
const nsACString& aSpec, const nsACString& aScheme, const nsACString& aHost,
const int32_t aPort, nsACString& aResult) {
// Fallback to nsWindowsSystemProxySettings::GetProxyForURI if we failed to
// monitor the change of registry keys.
if (!mInited) {
return nsWindowsSystemProxySettings::GetProxyForURI(aSpec, aScheme, aHost,
aPort, aResult);
}
if (!specificProxy.IsEmpty())
SetProxyResult("PROXY", specificProxy,
aResult); // Protocol-specific proxy.
else if (!defaultProxy.IsEmpty())
SetProxyResult("PROXY", defaultProxy, aResult); // Default proxy.
else if (!socksProxy.IsEmpty())
SetProxyResult("SOCKS", socksProxy, aResult); // SOCKS proxy.
else
SetProxyResultDirect(aResult); // Direct connection.
mozilla::MutexAutoLock lock(mLock);
for (const auto& bypassRule : mConfig.ByPassRules().mExceptions) {
if (MatchOverrideInternal(aHost, bypassRule)) {
ProxyConfig::SetProxyResultDirect(aResult);
return NS_OK;
}
}
mConfig.GetProxyString(aScheme, aResult);
return NS_OK;
}
NS_IMPL_COMPONENT_FACTORY(nsWindowsSystemProxySettings) {
return mozilla::MakeAndAddRef<nsWindowsSystemProxySettings>()
.downcast<nsISupports>();
auto settings =
mozilla::StaticPrefs::network_proxy_detect_system_proxy_changes()
? mozilla::MakeRefPtr<WindowsSystemProxySettingsAsync>()
: mozilla::MakeRefPtr<nsWindowsSystemProxySettings>();
if (NS_SUCCEEDED(settings->Init())) {
return settings.forget().downcast<nsISupports>();
}
return nullptr;
}