1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/proxy/proxy_config_service_mac.h"
6
7#include <CoreFoundation/CoreFoundation.h>
8#include <SystemConfiguration/SystemConfiguration.h>
9
10#include "base/logging.h"
11#include "base/mac_util.h"
12#include "base/scoped_cftyperef.h"
13#include "base/sys_string_conversions.h"
14#include "net/base/net_errors.h"
15#include "net/proxy/proxy_config.h"
16#include "net/proxy/proxy_info.h"
17#include "net/proxy/proxy_server.h"
18
19namespace {
20
21// Utility function to pull out a boolean value from a dictionary and return it,
22// returning a default value if the key is not present.
23bool GetBoolFromDictionary(CFDictionaryRef dict,
24                           CFStringRef key,
25                           bool default_value) {
26  CFNumberRef number = (CFNumberRef)mac_util::GetValueFromDictionary(
27      dict, key, CFNumberGetTypeID());
28  if (!number)
29    return default_value;
30
31  int int_value;
32  if (CFNumberGetValue(number, kCFNumberIntType, &int_value))
33    return int_value;
34  else
35    return default_value;
36}
37
38}  // namespace
39
40namespace net {
41
42int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
43  scoped_cftyperef<CFDictionaryRef> config_dict(
44      SCDynamicStoreCopyProxies(NULL));
45  DCHECK(config_dict);
46
47  // auto-detect
48
49  // There appears to be no UI for this configuration option, and we're not sure
50  // if Apple's proxy code even takes it into account. But the constant is in
51  // the header file so we'll use it.
52  config->auto_detect =
53      GetBoolFromDictionary(config_dict.get(),
54                            kSCPropNetProxiesProxyAutoDiscoveryEnable,
55                            false);
56
57  // PAC file
58
59  if (GetBoolFromDictionary(config_dict.get(),
60                            kSCPropNetProxiesProxyAutoConfigEnable,
61                            false)) {
62    CFStringRef pac_url_ref = (CFStringRef)mac_util::GetValueFromDictionary(
63        config_dict.get(),
64        kSCPropNetProxiesProxyAutoConfigURLString,
65        CFStringGetTypeID());
66    if (pac_url_ref)
67      config->pac_url = GURL(base::SysCFStringRefToUTF8(pac_url_ref));
68  }
69
70  // proxies (for now ftp, http, https, and SOCKS)
71
72  if (GetBoolFromDictionary(config_dict.get(),
73                            kSCPropNetProxiesFTPEnable,
74                            false)) {
75    ProxyServer proxy_server =
76        ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
77                                    config_dict.get(),
78                                    kSCPropNetProxiesFTPProxy,
79                                    kSCPropNetProxiesFTPPort);
80    if (proxy_server.is_valid()) {
81      config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
82      config->proxy_rules.proxy_for_ftp = proxy_server;
83    }
84  }
85  if (GetBoolFromDictionary(config_dict.get(),
86                            kSCPropNetProxiesHTTPEnable,
87                            false)) {
88    ProxyServer proxy_server =
89        ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
90                                    config_dict.get(),
91                                    kSCPropNetProxiesHTTPProxy,
92                                    kSCPropNetProxiesHTTPPort);
93    if (proxy_server.is_valid()) {
94      config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
95      config->proxy_rules.proxy_for_http = proxy_server;
96    }
97  }
98  if (GetBoolFromDictionary(config_dict.get(),
99                            kSCPropNetProxiesHTTPSEnable,
100                            false)) {
101    ProxyServer proxy_server =
102        ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
103                                    config_dict.get(),
104                                    kSCPropNetProxiesHTTPSProxy,
105                                    kSCPropNetProxiesHTTPSPort);
106    if (proxy_server.is_valid()) {
107      config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
108      config->proxy_rules.proxy_for_https = proxy_server;
109    }
110  }
111  if (GetBoolFromDictionary(config_dict.get(),
112                            kSCPropNetProxiesSOCKSEnable,
113                            false)) {
114    ProxyServer proxy_server =
115        ProxyServer::FromDictionary(ProxyServer::SCHEME_SOCKS5,
116                                    config_dict.get(),
117                                    kSCPropNetProxiesSOCKSProxy,
118                                    kSCPropNetProxiesSOCKSPort);
119    if (proxy_server.is_valid()) {
120      config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
121      config->proxy_rules.socks_proxy = proxy_server;
122    }
123  }
124
125  // proxy bypass list
126
127  CFArrayRef bypass_array_ref =
128      (CFArrayRef)mac_util::GetValueFromDictionary(
129          config_dict.get(),
130          kSCPropNetProxiesExceptionsList,
131          CFArrayGetTypeID());
132  if (bypass_array_ref) {
133    CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref);
134    for (CFIndex i = 0; i < bypass_array_count; ++i) {
135      CFStringRef bypass_item_ref =
136          (CFStringRef)CFArrayGetValueAtIndex(bypass_array_ref, i);
137      if (CFGetTypeID(bypass_item_ref) != CFStringGetTypeID()) {
138        LOG(WARNING) << "Expected value for item " << i
139                     << " in the kSCPropNetProxiesExceptionsList"
140                        " to be a CFStringRef but it was not";
141
142      } else {
143        config->proxy_bypass.push_back(
144            base::SysCFStringRefToUTF8(bypass_item_ref));
145      }
146    }
147  }
148
149  // proxy bypass boolean
150
151  config->proxy_bypass_local_names =
152      GetBoolFromDictionary(config_dict.get(),
153                            kSCPropNetProxiesExcludeSimpleHostnames,
154                            false);
155
156  return OK;
157}
158
159}  // namespace net
160