This source file includes following definitions.
- GetBoolFromDictionary
- GetCurrentProxyConfig
- Helper
- Orphan
- OnProxyConfigChanged
- SetDynamicStoreNotificationKeys
- OnNetworkConfigChange
- io_thread_task_runner_
- AddObserver
- RemoveObserver
- GetLatestProxyConfig
- SetDynamicStoreNotificationKeys
- OnNetworkConfigChange
- OnProxyConfigChanged
#include "net/proxy/proxy_config_service_mac.h"
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "base/bind.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_config.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_server.h"
namespace net {
namespace {
bool GetBoolFromDictionary(CFDictionaryRef dict,
CFStringRef key,
bool default_value) {
CFNumberRef number = base::mac::GetValueFromDictionary<CFNumberRef>(dict,
key);
if (!number)
return default_value;
int int_value;
if (CFNumberGetValue(number, kCFNumberIntType, &int_value))
return int_value;
else
return default_value;
}
void GetCurrentProxyConfig(ProxyConfig* config) {
base::ScopedCFTypeRef<CFDictionaryRef> config_dict(
SCDynamicStoreCopyProxies(NULL));
DCHECK(config_dict);
config->set_auto_detect(
GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesProxyAutoDiscoveryEnable,
false));
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesProxyAutoConfigEnable,
false)) {
CFStringRef pac_url_ref = base::mac::GetValueFromDictionary<CFStringRef>(
config_dict.get(), kSCPropNetProxiesProxyAutoConfigURLString);
if (pac_url_ref)
config->set_pac_url(GURL(base::SysCFStringRefToUTF8(pac_url_ref)));
}
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesFTPEnable,
false)) {
ProxyServer proxy_server =
ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
config_dict.get(),
kSCPropNetProxiesFTPProxy,
kSCPropNetProxiesFTPPort);
if (proxy_server.is_valid()) {
config->proxy_rules().type =
ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_server);
}
}
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesHTTPEnable,
false)) {
ProxyServer proxy_server =
ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
config_dict.get(),
kSCPropNetProxiesHTTPProxy,
kSCPropNetProxiesHTTPPort);
if (proxy_server.is_valid()) {
config->proxy_rules().type =
ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
config->proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server);
}
}
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesHTTPSEnable,
false)) {
ProxyServer proxy_server =
ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
config_dict.get(),
kSCPropNetProxiesHTTPSProxy,
kSCPropNetProxiesHTTPSPort);
if (proxy_server.is_valid()) {
config->proxy_rules().type =
ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
config->proxy_rules().proxies_for_https.
SetSingleProxyServer(proxy_server);
}
}
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesSOCKSEnable,
false)) {
ProxyServer proxy_server =
ProxyServer::FromDictionary(ProxyServer::SCHEME_SOCKS5,
config_dict.get(),
kSCPropNetProxiesSOCKSProxy,
kSCPropNetProxiesSOCKSPort);
if (proxy_server.is_valid()) {
config->proxy_rules().type =
ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
config->proxy_rules().fallback_proxies.SetSingleProxyServer(proxy_server);
}
}
CFArrayRef bypass_array_ref = base::mac::GetValueFromDictionary<CFArrayRef>(
config_dict.get(), kSCPropNetProxiesExceptionsList);
if (bypass_array_ref) {
CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref);
for (CFIndex i = 0; i < bypass_array_count; ++i) {
CFStringRef bypass_item_ref = base::mac::CFCast<CFStringRef>(
CFArrayGetValueAtIndex(bypass_array_ref, i));
if (!bypass_item_ref) {
LOG(WARNING) << "Expected value for item " << i
<< " in the kSCPropNetProxiesExceptionsList"
" to be a CFStringRef but it was not";
} else {
config->proxy_rules().bypass_rules.AddRuleFromString(
base::SysCFStringRefToUTF8(bypass_item_ref));
}
}
}
if (GetBoolFromDictionary(config_dict.get(),
kSCPropNetProxiesExcludeSimpleHostnames,
false)) {
config->proxy_rules().bypass_rules.AddRuleToBypassLocal();
}
config->set_source(PROXY_CONFIG_SOURCE_SYSTEM);
}
}
class ProxyConfigServiceMac::Helper
: public base::RefCountedThreadSafe<ProxyConfigServiceMac::Helper> {
public:
explicit Helper(ProxyConfigServiceMac* parent) : parent_(parent) {
DCHECK(parent);
}
void Orphan() {
parent_ = NULL;
}
void OnProxyConfigChanged(const ProxyConfig& new_config) {
if (parent_)
parent_->OnProxyConfigChanged(new_config);
}
private:
friend class base::RefCountedThreadSafe<Helper>;
~Helper() {}
ProxyConfigServiceMac* parent_;
};
void ProxyConfigServiceMac::Forwarder::SetDynamicStoreNotificationKeys(
SCDynamicStoreRef store) {
proxy_config_service_->SetDynamicStoreNotificationKeys(store);
}
void ProxyConfigServiceMac::Forwarder::OnNetworkConfigChange(
CFArrayRef changed_keys) {
proxy_config_service_->OnNetworkConfigChange(changed_keys);
}
ProxyConfigServiceMac::ProxyConfigServiceMac(
base::SingleThreadTaskRunner* io_thread_task_runner)
: forwarder_(this),
has_fetched_config_(false),
helper_(new Helper(this)),
io_thread_task_runner_(io_thread_task_runner) {
DCHECK(io_thread_task_runner_.get());
config_watcher_.reset(new NetworkConfigWatcherMac(&forwarder_));
}
ProxyConfigServiceMac::~ProxyConfigServiceMac() {
DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
config_watcher_.reset();
helper_->Orphan();
}
void ProxyConfigServiceMac::AddObserver(Observer* observer) {
DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
observers_.AddObserver(observer);
}
void ProxyConfigServiceMac::RemoveObserver(Observer* observer) {
DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
observers_.RemoveObserver(observer);
}
net::ProxyConfigService::ConfigAvailability
ProxyConfigServiceMac::GetLatestProxyConfig(ProxyConfig* config) {
DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
if (!has_fetched_config_) {
GetCurrentProxyConfig(&last_config_fetched_);
has_fetched_config_ = true;
}
*config = last_config_fetched_;
return has_fetched_config_ ? CONFIG_VALID : CONFIG_PENDING;
}
void ProxyConfigServiceMac::SetDynamicStoreNotificationKeys(
SCDynamicStoreRef store) {
CFStringRef proxies_key = SCDynamicStoreKeyCreateProxies(NULL);
CFArrayRef key_array = CFArrayCreate(
NULL, (const void **)(&proxies_key), 1, &kCFTypeArrayCallBacks);
bool ret = SCDynamicStoreSetNotificationKeys(store, key_array, NULL);
CHECK(ret);
CFRelease(key_array);
CFRelease(proxies_key);
}
void ProxyConfigServiceMac::OnNetworkConfigChange(CFArrayRef changed_keys) {
ProxyConfig new_config;
GetCurrentProxyConfig(&new_config);
io_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&Helper::OnProxyConfigChanged, helper_.get(), new_config));
}
void ProxyConfigServiceMac::OnProxyConfigChanged(
const ProxyConfig& new_config) {
DCHECK(io_thread_task_runner_->BelongsToCurrentThread());
has_fetched_config_ = true;
last_config_fetched_ = new_config;
FOR_EACH_OBSERVER(Observer, observers_,
OnProxyConfigChanged(new_config, CONFIG_VALID));
}
}