Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: net/proxy/proxy_config_service_mac.cc

Issue 463028: Separate ProxyResolverMac and ProxyConfigServiceMac into their own files (Closed)
Patch Set: '' Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/proxy/proxy_config_service_mac.h ('k') | net/proxy/proxy_resolver_mac.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/proxy/proxy_resolver_mac.h" 5 #include "net/proxy/proxy_config_service_mac.h"
6 6
7 #include <CoreFoundation/CoreFoundation.h> 7 #include <CoreFoundation/CoreFoundation.h>
8 #include <CoreServices/CoreServices.h>
9 #include <SystemConfiguration/SystemConfiguration.h> 8 #include <SystemConfiguration/SystemConfiguration.h>
10 9
10 #include "base/logging.h"
11 #include "base/mac_util.h"
11 #include "base/scoped_cftyperef.h" 12 #include "base/scoped_cftyperef.h"
12 #include "base/string_util.h"
13 #include "base/sys_string_conversions.h" 13 #include "base/sys_string_conversions.h"
14 #include "net/base/net_errors.h" 14 #include "net/base/net_errors.h"
15 #include "net/proxy/proxy_config.h" 15 #include "net/proxy/proxy_config.h"
16 #include "net/proxy/proxy_info.h" 16 #include "net/proxy/proxy_info.h"
17 #include "net/proxy/proxy_server.h" 17 #include "net/proxy/proxy_server.h"
18 18
19 namespace { 19 namespace {
20 20
21 // Utility function to pull out a value from a dictionary, check its type, and
22 // return it. Returns NULL if the key is not present or of the wrong type.
23 CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
24 CFStringRef key,
25 CFTypeID expected_type) {
26 CFTypeRef value = CFDictionaryGetValue(dict, key);
27 if (!value)
28 return value;
29
30 if (CFGetTypeID(value) != expected_type) {
31 scoped_cftyperef<CFStringRef> expected_type_ref(
32 CFCopyTypeIDDescription(expected_type));
33 scoped_cftyperef<CFStringRef> actual_type_ref(
34 CFCopyTypeIDDescription(CFGetTypeID(value)));
35 LOG(WARNING) << "Expected value for key "
36 << base::SysCFStringRefToUTF8(key)
37 << " to be "
38 << base::SysCFStringRefToUTF8(expected_type_ref)
39 << " but it was "
40 << base::SysCFStringRefToUTF8(actual_type_ref)
41 << " instead";
42 return NULL;
43 }
44
45 return value;
46 }
47
48 // Utility function to pull out a boolean value from a dictionary and return it, 21 // Utility function to pull out a boolean value from a dictionary and return it,
49 // returning a default value if the key is not present. 22 // returning a default value if the key is not present.
50 bool GetBoolFromDictionary(CFDictionaryRef dict, 23 bool GetBoolFromDictionary(CFDictionaryRef dict,
51 CFStringRef key, 24 CFStringRef key,
52 bool default_value) { 25 bool default_value) {
53 CFNumberRef number = (CFNumberRef)GetValueFromDictionary(dict, key, 26 CFNumberRef number = (CFNumberRef)mac_util::GetValueFromDictionary(
54 CFNumberGetTypeID()); 27 dict, key, CFNumberGetTypeID());
55 if (!number) 28 if (!number)
56 return default_value; 29 return default_value;
57 30
58 int int_value; 31 int int_value;
59 if (CFNumberGetValue(number, kCFNumberIntType, &int_value)) 32 if (CFNumberGetValue(number, kCFNumberIntType, &int_value))
60 return int_value; 33 return int_value;
61 else 34 else
62 return default_value; 35 return default_value;
63 } 36 }
64 37
65 // Utility function to pull out a host/port pair from a dictionary and return it
66 // as a ProxyServer object. Pass in a dictionary that has a value for the host
67 // key and optionally a value for the port key. In the error condition where
68 // the host value is especially malformed, returns an invalid ProxyServer.
69 net::ProxyServer GetProxyServerFromDictionary(net::ProxyServer::Scheme scheme,
70 CFDictionaryRef dict,
71 CFStringRef host_key,
72 CFStringRef port_key) {
73 if (scheme == net::ProxyServer::SCHEME_INVALID ||
74 scheme == net::ProxyServer::SCHEME_DIRECT) {
75 // No hostname port to extract; we are done.
76 return net::ProxyServer(scheme, std::string(), -1);
77 }
78
79 CFStringRef host_ref =
80 (CFStringRef)GetValueFromDictionary(dict, host_key,
81 CFStringGetTypeID());
82 if (!host_ref) {
83 LOG(WARNING) << "Could not find expected key "
84 << base::SysCFStringRefToUTF8(host_key)
85 << " in the proxy dictionary";
86 return net::ProxyServer(); // Invalid.
87 }
88 std::string host = base::SysCFStringRefToUTF8(host_ref);
89
90 CFNumberRef port_ref =
91 (CFNumberRef)GetValueFromDictionary(dict, port_key,
92 CFNumberGetTypeID());
93 int port;
94 if (port_ref) {
95 CFNumberGetValue(port_ref, kCFNumberIntType, &port);
96 } else {
97 port = net::ProxyServer::GetDefaultPortForScheme(scheme);
98 }
99
100 return net::ProxyServer(scheme, host, port);
101 }
102
103 // Utility function to map a CFProxyType to a ProxyServer::Scheme.
104 // If the type is unknown, returns ProxyServer::SCHEME_INVALID.
105 net::ProxyServer::Scheme GetProxyServerScheme(CFStringRef proxy_type) {
106 if (CFEqual(proxy_type, kCFProxyTypeNone))
107 return net::ProxyServer::SCHEME_DIRECT;
108 if (CFEqual(proxy_type, kCFProxyTypeHTTP))
109 return net::ProxyServer::SCHEME_HTTP;
110 if (CFEqual(proxy_type, kCFProxyTypeSOCKS)) {
111 // We can't tell whether this was v4 or v5. We will assume it is
112 // v5 since that is the only version OS X supports.
113 return net::ProxyServer::SCHEME_SOCKS5;
114 }
115 return net::ProxyServer::SCHEME_INVALID;
116 }
117
118 // Callback for CFNetworkExecuteProxyAutoConfigurationURL. |client| is a pointer
119 // to a CFTypeRef. This stashes either |error| or |proxies| in that location.
120 void ResultCallback(void* client, CFArrayRef proxies, CFErrorRef error) {
121 DCHECK((proxies != NULL) == (error == NULL));
122
123 CFTypeRef* result_ptr = (CFTypeRef*)client;
124 DCHECK(result_ptr != NULL);
125 DCHECK(*result_ptr == NULL);
126
127 if (error != NULL) {
128 *result_ptr = CFRetain(error);
129 } else {
130 *result_ptr = CFRetain(proxies);
131 }
132 CFRunLoopStop(CFRunLoopGetCurrent());
133 }
134
135 } // namespace 38 } // namespace
136 39
137 namespace net { 40 namespace net {
138 41
139 int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) { 42 int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
140 scoped_cftyperef<CFDictionaryRef> config_dict( 43 scoped_cftyperef<CFDictionaryRef> config_dict(
141 SCDynamicStoreCopyProxies(NULL)); 44 SCDynamicStoreCopyProxies(NULL));
142 DCHECK(config_dict); 45 DCHECK(config_dict);
143 46
144 // auto-detect 47 // auto-detect
145 48
146 // There appears to be no UI for this configuration option, and we're not sure 49 // There appears to be no UI for this configuration option, and we're not sure
147 // if Apple's proxy code even takes it into account. But the constant is in 50 // if Apple's proxy code even takes it into account. But the constant is in
148 // the header file so we'll use it. 51 // the header file so we'll use it.
149 config->auto_detect = 52 config->auto_detect =
150 GetBoolFromDictionary(config_dict.get(), 53 GetBoolFromDictionary(config_dict.get(),
151 kSCPropNetProxiesProxyAutoDiscoveryEnable, 54 kSCPropNetProxiesProxyAutoDiscoveryEnable,
152 false); 55 false);
153 56
154 // PAC file 57 // PAC file
155 58
156 if (GetBoolFromDictionary(config_dict.get(), 59 if (GetBoolFromDictionary(config_dict.get(),
157 kSCPropNetProxiesProxyAutoConfigEnable, 60 kSCPropNetProxiesProxyAutoConfigEnable,
158 false)) { 61 false)) {
159 CFStringRef pac_url_ref = 62 CFStringRef pac_url_ref = (CFStringRef)mac_util::GetValueFromDictionary(
160 (CFStringRef)GetValueFromDictionary( 63 config_dict.get(),
161 config_dict.get(), 64 kSCPropNetProxiesProxyAutoConfigURLString,
162 kSCPropNetProxiesProxyAutoConfigURLString, 65 CFStringGetTypeID());
163 CFStringGetTypeID());
164 if (pac_url_ref) 66 if (pac_url_ref)
165 config->pac_url = GURL(base::SysCFStringRefToUTF8(pac_url_ref)); 67 config->pac_url = GURL(base::SysCFStringRefToUTF8(pac_url_ref));
166 } 68 }
167 69
168 // proxies (for now ftp, http, https, and SOCKS) 70 // proxies (for now ftp, http, https, and SOCKS)
169 71
170 if (GetBoolFromDictionary(config_dict.get(), 72 if (GetBoolFromDictionary(config_dict.get(),
171 kSCPropNetProxiesFTPEnable, 73 kSCPropNetProxiesFTPEnable,
172 false)) { 74 false)) {
173 ProxyServer proxy_server = 75 ProxyServer proxy_server =
174 GetProxyServerFromDictionary(ProxyServer::SCHEME_HTTP, 76 ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
175 config_dict.get(), 77 config_dict.get(),
176 kSCPropNetProxiesFTPProxy, 78 kSCPropNetProxiesFTPProxy,
177 kSCPropNetProxiesFTPPort); 79 kSCPropNetProxiesFTPPort);
178 if (proxy_server.is_valid()) { 80 if (proxy_server.is_valid()) {
179 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; 81 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
180 config->proxy_rules.proxy_for_ftp = proxy_server; 82 config->proxy_rules.proxy_for_ftp = proxy_server;
181 } 83 }
182 } 84 }
183 if (GetBoolFromDictionary(config_dict.get(), 85 if (GetBoolFromDictionary(config_dict.get(),
184 kSCPropNetProxiesHTTPEnable, 86 kSCPropNetProxiesHTTPEnable,
185 false)) { 87 false)) {
186 ProxyServer proxy_server = 88 ProxyServer proxy_server =
187 GetProxyServerFromDictionary(ProxyServer::SCHEME_HTTP, 89 ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
188 config_dict.get(), 90 config_dict.get(),
189 kSCPropNetProxiesHTTPProxy, 91 kSCPropNetProxiesHTTPProxy,
190 kSCPropNetProxiesHTTPPort); 92 kSCPropNetProxiesHTTPPort);
191 if (proxy_server.is_valid()) { 93 if (proxy_server.is_valid()) {
192 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; 94 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
193 config->proxy_rules.proxy_for_http = proxy_server; 95 config->proxy_rules.proxy_for_http = proxy_server;
194 } 96 }
195 } 97 }
196 if (GetBoolFromDictionary(config_dict.get(), 98 if (GetBoolFromDictionary(config_dict.get(),
197 kSCPropNetProxiesHTTPSEnable, 99 kSCPropNetProxiesHTTPSEnable,
198 false)) { 100 false)) {
199 ProxyServer proxy_server = 101 ProxyServer proxy_server =
200 GetProxyServerFromDictionary(ProxyServer::SCHEME_HTTP, 102 ProxyServer::FromDictionary(ProxyServer::SCHEME_HTTP,
201 config_dict.get(), 103 config_dict.get(),
202 kSCPropNetProxiesHTTPSProxy, 104 kSCPropNetProxiesHTTPSProxy,
203 kSCPropNetProxiesHTTPSPort); 105 kSCPropNetProxiesHTTPSPort);
204 if (proxy_server.is_valid()) { 106 if (proxy_server.is_valid()) {
205 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; 107 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
206 config->proxy_rules.proxy_for_https = proxy_server; 108 config->proxy_rules.proxy_for_https = proxy_server;
207 } 109 }
208 } 110 }
209 if (GetBoolFromDictionary(config_dict.get(), 111 if (GetBoolFromDictionary(config_dict.get(),
210 kSCPropNetProxiesSOCKSEnable, 112 kSCPropNetProxiesSOCKSEnable,
211 false)) { 113 false)) {
212 ProxyServer proxy_server = 114 ProxyServer proxy_server =
213 GetProxyServerFromDictionary(ProxyServer::SCHEME_SOCKS5, 115 ProxyServer::FromDictionary(ProxyServer::SCHEME_SOCKS5,
214 config_dict.get(), 116 config_dict.get(),
215 kSCPropNetProxiesSOCKSProxy, 117 kSCPropNetProxiesSOCKSProxy,
216 kSCPropNetProxiesSOCKSPort); 118 kSCPropNetProxiesSOCKSPort);
217 if (proxy_server.is_valid()) { 119 if (proxy_server.is_valid()) {
218 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; 120 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
219 config->proxy_rules.socks_proxy = proxy_server; 121 config->proxy_rules.socks_proxy = proxy_server;
220 } 122 }
221 } 123 }
222 124
223 // proxy bypass list 125 // proxy bypass list
224 126
225 CFArrayRef bypass_array_ref = 127 CFArrayRef bypass_array_ref =
226 (CFArrayRef)GetValueFromDictionary(config_dict.get(), 128 (CFArrayRef)mac_util::GetValueFromDictionary(
227 kSCPropNetProxiesExceptionsList, 129 config_dict.get(),
228 CFArrayGetTypeID()); 130 kSCPropNetProxiesExceptionsList,
131 CFArrayGetTypeID());
229 if (bypass_array_ref) { 132 if (bypass_array_ref) {
230 CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref); 133 CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref);
231 for (CFIndex i = 0; i < bypass_array_count; ++i) { 134 for (CFIndex i = 0; i < bypass_array_count; ++i) {
232 CFStringRef bypass_item_ref = 135 CFStringRef bypass_item_ref =
233 (CFStringRef)CFArrayGetValueAtIndex(bypass_array_ref, i); 136 (CFStringRef)CFArrayGetValueAtIndex(bypass_array_ref, i);
234 if (CFGetTypeID(bypass_item_ref) != CFStringGetTypeID()) { 137 if (CFGetTypeID(bypass_item_ref) != CFStringGetTypeID()) {
235 LOG(WARNING) << "Expected value for item " << i 138 LOG(WARNING) << "Expected value for item " << i
236 << " in the kSCPropNetProxiesExceptionsList" 139 << " in the kSCPropNetProxiesExceptionsList"
237 " to be a CFStringRef but it was not"; 140 " to be a CFStringRef but it was not";
238 141
239 } else { 142 } else {
240 config->proxy_bypass.push_back( 143 config->proxy_bypass.push_back(
241 base::SysCFStringRefToUTF8(bypass_item_ref)); 144 base::SysCFStringRefToUTF8(bypass_item_ref));
242 } 145 }
243 } 146 }
244 } 147 }
245 148
246 // proxy bypass boolean 149 // proxy bypass boolean
247 150
248 config->proxy_bypass_local_names = 151 config->proxy_bypass_local_names =
249 GetBoolFromDictionary(config_dict.get(), 152 GetBoolFromDictionary(config_dict.get(),
250 kSCPropNetProxiesExcludeSimpleHostnames, 153 kSCPropNetProxiesExcludeSimpleHostnames,
251 false); 154 false);
252 155
253 return OK; 156 return OK;
254 } 157 }
255 158
256 // Gets the proxy information for a query URL from a PAC. Implementation
257 // inspired by http://developer.apple.com/samplecode/CFProxySupportTool/
258 int ProxyResolverMac::GetProxyForURL(const GURL& query_url,
259 ProxyInfo* results,
260 CompletionCallback* /*callback*/,
261 RequestHandle* /*request*/,
262 LoadLog* load_log) {
263 scoped_cftyperef<CFStringRef> query_ref(
264 base::SysUTF8ToCFStringRef(query_url.spec()));
265 scoped_cftyperef<CFURLRef> query_url_ref(
266 CFURLCreateWithString(kCFAllocatorDefault,
267 query_ref.get(),
268 NULL));
269 if (!query_url_ref.get())
270 return ERR_FAILED;
271 scoped_cftyperef<CFStringRef> pac_ref(
272 base::SysUTF8ToCFStringRef(pac_url_.spec()));
273 scoped_cftyperef<CFURLRef> pac_url_ref(
274 CFURLCreateWithString(kCFAllocatorDefault,
275 pac_ref.get(),
276 NULL));
277 if (!pac_url_ref.get())
278 return ERR_FAILED;
279
280 // Work around <rdar://problem/5530166>. This dummy call to
281 // CFNetworkCopyProxiesForURL initializes some state within CFNetwork that is
282 // required by CFNetworkExecuteProxyAutoConfigurationURL.
283
284 CFArrayRef dummy_result = CFNetworkCopyProxiesForURL(query_url_ref.get(),
285 NULL);
286 if (dummy_result)
287 CFRelease(dummy_result);
288
289 // We cheat here. We need to act as if we were synchronous, so we pump the
290 // runloop ourselves. Our caller moved us to a new thread anyway, so this is
291 // OK to do. (BTW, CFNetworkExecuteProxyAutoConfigurationURL returns a
292 // runloop source we need to release despite its name.)
293
294 CFTypeRef result = NULL;
295 CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };
296 scoped_cftyperef<CFRunLoopSourceRef> runloop_source(
297 CFNetworkExecuteProxyAutoConfigurationURL(pac_url_ref.get(),
298 query_url_ref.get(),
299 ResultCallback,
300 &context));
301 if (!runloop_source)
302 return ERR_FAILED;
303
304 const CFStringRef private_runloop_mode =
305 CFSTR("org.chromium.ProxyResolverMac");
306
307 CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source.get(),
308 private_runloop_mode);
309 CFRunLoopRunInMode(private_runloop_mode, DBL_MAX, false);
310 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloop_source.get(),
311 private_runloop_mode);
312 DCHECK(result != NULL);
313
314 if (CFGetTypeID(result) == CFErrorGetTypeID()) {
315 // TODO(avi): do something better than this
316 CFRelease(result);
317 return ERR_FAILED;
318 }
319 DCHECK(CFGetTypeID(result) == CFArrayGetTypeID());
320 scoped_cftyperef<CFArrayRef> proxy_array_ref((CFArrayRef)result);
321
322 // This string will be an ordered list of <proxy-uri> entries, separated by
323 // semi-colons. It is the format that ProxyInfo::UseNamedProxy() expects.
324 // proxy-uri = [<proxy-scheme>"://"]<proxy-host>":"<proxy-port>
325 // (This also includes entries for direct connection, as "direct://").
326 std::string proxy_uri_list;
327
328 CFIndex proxy_array_count = CFArrayGetCount(proxy_array_ref.get());
329 for (CFIndex i = 0; i < proxy_array_count; ++i) {
330 CFDictionaryRef proxy_dictionary =
331 (CFDictionaryRef)CFArrayGetValueAtIndex(proxy_array_ref.get(), i);
332 DCHECK(CFGetTypeID(proxy_dictionary) == CFDictionaryGetTypeID());
333
334 // The dictionary may have the following keys:
335 // - kCFProxyTypeKey : The type of the proxy
336 // - kCFProxyHostNameKey
337 // - kCFProxyPortNumberKey : The meat we're after.
338 // - kCFProxyUsernameKey
339 // - kCFProxyPasswordKey : Despite the existence of these keys in the
340 // documentation, they're never populated. Even if a
341 // username/password were to be set in the network
342 // proxy system preferences, we'd need to fetch it
343 // from the Keychain ourselves. CFProxy is such a
344 // tease.
345 // - kCFProxyAutoConfigurationURLKey : If the PAC file specifies another
346 // PAC file, I'm going home.
347
348 CFStringRef proxy_type =
349 (CFStringRef)GetValueFromDictionary(proxy_dictionary,
350 kCFProxyTypeKey,
351 CFStringGetTypeID());
352 ProxyServer proxy_server =
353 GetProxyServerFromDictionary(GetProxyServerScheme(proxy_type),
354 proxy_dictionary,
355 kCFProxyHostNameKey,
356 kCFProxyPortNumberKey);
357 if (!proxy_server.is_valid())
358 continue;
359
360 if (!proxy_uri_list.empty())
361 proxy_uri_list += ";";
362 proxy_uri_list += proxy_server.ToURI();
363 }
364
365 if (!proxy_uri_list.empty())
366 results->UseNamedProxy(proxy_uri_list);
367 // Else do nothing (results is already guaranteed to be in the default state).
368
369 return OK;
370 }
371
372 } // namespace net 159 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/proxy_config_service_mac.h ('k') | net/proxy/proxy_resolver_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698