1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_config_service_mac.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <CoreFoundation/CoreFoundation.h>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <SystemConfiguration/SystemConfiguration.h>
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/mac/mac_util.h"
12731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/mac/scoped_cftyperef.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/sys_string_conversions.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_config.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_info.h"
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_server.h"
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace net {
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kPollIntervalSec = 5;
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Utility function to pull out a boolean value from a dictionary and return it,
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// returning a default value if the key is not present.
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool GetBoolFromDictionary(CFDictionaryRef dict,
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           CFStringRef key,
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                           bool default_value) {
303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  CFNumberRef number = (CFNumberRef)base::mac::GetValueFromDictionary(
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      dict, key, CFNumberGetTypeID());
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!number)
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return default_value;
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int int_value;
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (CFNumberGetValue(number, kCFNumberIntType, &int_value))
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return int_value;
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return default_value;
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid GetCurrentProxyConfig(ProxyConfig* config) {
43731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::mac::ScopedCFTypeRef<CFDictionaryRef> config_dict(
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SCDynamicStoreCopyProxies(NULL));
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(config_dict);
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // auto-detect
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // There appears to be no UI for this configuration option, and we're not sure
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // if Apple's proxy code even takes it into account. But the constant is in
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // the header file so we'll use it.
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  config->set_auto_detect(
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      GetBoolFromDictionary(config_dict.get(),
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesProxyAutoDiscoveryEnable,
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            false));
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // PAC file
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (GetBoolFromDictionary(config_dict.get(),
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesProxyAutoConfigEnable,
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            false)) {
623f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    CFStringRef pac_url_ref = (CFStringRef)base::mac::GetValueFromDictionary(
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        config_dict.get(),
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        kSCPropNetProxiesProxyAutoConfigURLString,
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        CFStringGetTypeID());
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (pac_url_ref)
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->set_pac_url(GURL(base::SysCFStringRefToUTF8(pac_url_ref)));
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // proxies (for now ftp, http, https, and SOCKS)
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (GetBoolFromDictionary(config_dict.get(),
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesFTPEnable,
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            false)) {
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ProxyServer proxy_server =
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    config_dict.get(),
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesFTPProxy,
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesFTPPort);
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (proxy_server.is_valid()) {
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().type =
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().proxy_for_ftp = proxy_server;
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (GetBoolFromDictionary(config_dict.get(),
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesHTTPEnable,
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            false)) {
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ProxyServer proxy_server =
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    config_dict.get(),
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesHTTPProxy,
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesHTTPPort);
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (proxy_server.is_valid()) {
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().type =
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().proxy_for_http = proxy_server;
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (GetBoolFromDictionary(config_dict.get(),
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesHTTPSEnable,
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            false)) {
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ProxyServer proxy_server =
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    config_dict.get(),
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesHTTPSProxy,
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesHTTPSPort);
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (proxy_server.is_valid()) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().type =
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().proxy_for_https = proxy_server;
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (GetBoolFromDictionary(config_dict.get(),
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesSOCKSEnable,
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            false)) {
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ProxyServer proxy_server =
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        ProxyServer::FromDictionary(ProxyServer::SCHEME_SOCKS5,
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    config_dict.get(),
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesSOCKSProxy,
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                    kSCPropNetProxiesSOCKSPort);
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (proxy_server.is_valid()) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      config->proxy_rules().type =
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      config->proxy_rules().fallback_proxy = proxy_server;
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // proxy bypass list
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CFArrayRef bypass_array_ref =
1323f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      (CFArrayRef)base::mac::GetValueFromDictionary(
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          config_dict.get(),
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          kSCPropNetProxiesExceptionsList,
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          CFArrayGetTypeID());
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (bypass_array_ref) {
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref);
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (CFIndex i = 0; i < bypass_array_count; ++i) {
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      CFStringRef bypass_item_ref =
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          (CFStringRef)CFArrayGetValueAtIndex(bypass_array_ref, i);
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (CFGetTypeID(bypass_item_ref) != CFStringGetTypeID()) {
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        LOG(WARNING) << "Expected value for item " << i
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                     << " in the kSCPropNetProxiesExceptionsList"
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                        " to be a CFStringRef but it was not";
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      } else {
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        config->proxy_rules().bypass_rules.AddRuleFromString(
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            base::SysCFStringRefToUTF8(bypass_item_ref));
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // proxy bypass boolean
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (GetBoolFromDictionary(config_dict.get(),
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            kSCPropNetProxiesExcludeSimpleHostnames,
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            false)) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    config->proxy_rules().bypass_rules.AddRuleToBypassLocal();
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Reference-counted helper for posting a task to
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// ProxyConfigServiceMac::OnProxyConfigChanged between the notifier and IO
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// thread. This helper object may outlive the ProxyConfigServiceMac.
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass ProxyConfigServiceMac::Helper
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : public base::RefCountedThreadSafe<ProxyConfigServiceMac::Helper> {
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  explicit Helper(ProxyConfigServiceMac* parent) : parent_(parent) {
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(parent);
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Called when the parent is destroyed.
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void Orphan() {
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    parent_ = NULL;
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void OnProxyConfigChanged(const ProxyConfig& new_config) {
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (parent_)
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      parent_->OnProxyConfigChanged(new_config);
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ProxyConfigServiceMac* parent_;
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickProxyConfigServiceMac::ProxyConfigServiceMac(MessageLoop* io_loop)
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : forwarder_(this),
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      config_watcher_(&forwarder_),
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      has_fetched_config_(false),
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      helper_(new Helper(this)),
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      io_loop_(io_loop) {
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(io_loop);
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickProxyConfigServiceMac::~ProxyConfigServiceMac() {
1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(io_loop_, MessageLoop::current());
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  helper_->Orphan();
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  io_loop_ = NULL;
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceMac::AddObserver(Observer* observer) {
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(io_loop_, MessageLoop::current());
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  observers_.AddObserver(observer);
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceMac::RemoveObserver(Observer* observer) {
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(io_loop_, MessageLoop::current());
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  observers_.RemoveObserver(observer);
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennet::ProxyConfigService::ConfigAvailability
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProxyConfigServiceMac::GetLatestProxyConfig(ProxyConfig* config) {
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(io_loop_, MessageLoop::current());
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Lazy-initialize by fetching the proxy setting from this thread.
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!has_fetched_config_) {
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    GetCurrentProxyConfig(&last_config_fetched_);
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    has_fetched_config_ = true;
2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  *config = last_config_fetched_;
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return has_fetched_config_ ? CONFIG_VALID : CONFIG_PENDING;
2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceMac::SetDynamicStoreNotificationKeys(
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SCDynamicStoreRef store) {
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Called on notifier thread.
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFStringRef proxies_key = SCDynamicStoreKeyCreateProxies(NULL);
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFArrayRef key_array = CFArrayCreate(
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NULL, (const void **)(&proxies_key), 1, &kCFTypeArrayCallBacks);
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool ret = SCDynamicStoreSetNotificationKeys(store, key_array, NULL);
2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(willchan): Figure out a proper way to handle this rather than crash.
2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(ret);
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFRelease(key_array);
2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CFRelease(proxies_key);
2413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceMac::OnNetworkConfigChange(CFArrayRef changed_keys) {
2443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Called on notifier thread.
2453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Fetch the new system proxy configuration.
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ProxyConfig new_config;
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  GetCurrentProxyConfig(&new_config);
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Call OnProxyConfigChanged() on the IO thread to notify our observers.
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  io_loop_->PostTask(
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      FROM_HERE,
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          helper_.get(), &Helper::OnProxyConfigChanged, new_config));
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid ProxyConfigServiceMac::OnProxyConfigChanged(
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const ProxyConfig& new_config) {
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(io_loop_, MessageLoop::current());
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Keep track of the last value we have seen.
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  has_fetched_config_ = true;
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  last_config_fetched_ = new_config;
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Notify all the observers.
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  FOR_EACH_OBSERVER(Observer, observers_,
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                    OnProxyConfigChanged(new_config, CONFIG_VALID));
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
271