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

Side by Side Diff: net/proxy/proxy_server_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_server.h ('k') | net/proxy/proxy_service.cc » ('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_server.h"
6 6
7 #include <CoreFoundation/CoreFoundation.h> 7 #include <CoreFoundation/CoreFoundation.h>
8 #include <CoreServices/CoreServices.h>
9 #include <SystemConfiguration/SystemConfiguration.h>
10 8
11 #include "base/scoped_cftyperef.h" 9 #include <string>
12 #include "base/string_util.h" 10
11 #include "base/logging.h"
12 #include "base/mac_util.h"
13 #include "base/sys_string_conversions.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 14
19 namespace { 15 namespace net {
20 16
21 // Utility function to pull out a value from a dictionary, check its type, and 17 // static
22 // return it. Returns NULL if the key is not present or of the wrong type. 18 ProxyServer ProxyServer::FromDictionary(Scheme scheme,
23 CFTypeRef GetValueFromDictionary(CFDictionaryRef dict, 19 CFDictionaryRef dict,
24 CFStringRef key, 20 CFStringRef host_key,
25 CFTypeID expected_type) { 21 CFStringRef port_key) {
26 CFTypeRef value = CFDictionaryGetValue(dict, key); 22 if (scheme == SCHEME_INVALID || scheme == SCHEME_DIRECT) {
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,
49 // returning a default value if the key is not present.
50 bool GetBoolFromDictionary(CFDictionaryRef dict,
51 CFStringRef key,
52 bool default_value) {
53 CFNumberRef number = (CFNumberRef)GetValueFromDictionary(dict, key,
54 CFNumberGetTypeID());
55 if (!number)
56 return default_value;
57
58 int int_value;
59 if (CFNumberGetValue(number, kCFNumberIntType, &int_value))
60 return int_value;
61 else
62 return default_value;
63 }
64
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. 23 // No hostname port to extract; we are done.
76 return net::ProxyServer(scheme, std::string(), -1); 24 return ProxyServer(scheme, std::string(), -1);
77 } 25 }
78 26
79 CFStringRef host_ref = 27 CFStringRef host_ref =
80 (CFStringRef)GetValueFromDictionary(dict, host_key, 28 (CFStringRef)mac_util::GetValueFromDictionary(dict, host_key,
81 CFStringGetTypeID()); 29 CFStringGetTypeID());
82 if (!host_ref) { 30 if (!host_ref) {
83 LOG(WARNING) << "Could not find expected key " 31 LOG(WARNING) << "Could not find expected key "
84 << base::SysCFStringRefToUTF8(host_key) 32 << base::SysCFStringRefToUTF8(host_key)
85 << " in the proxy dictionary"; 33 << " in the proxy dictionary";
86 return net::ProxyServer(); // Invalid. 34 return ProxyServer(); // Invalid.
87 } 35 }
88 std::string host = base::SysCFStringRefToUTF8(host_ref); 36 std::string host = base::SysCFStringRefToUTF8(host_ref);
89 37
90 CFNumberRef port_ref = 38 CFNumberRef port_ref =
91 (CFNumberRef)GetValueFromDictionary(dict, port_key, 39 (CFNumberRef)mac_util::GetValueFromDictionary(dict, port_key,
92 CFNumberGetTypeID()); 40 CFNumberGetTypeID());
93 int port; 41 int port;
94 if (port_ref) { 42 if (port_ref) {
95 CFNumberGetValue(port_ref, kCFNumberIntType, &port); 43 CFNumberGetValue(port_ref, kCFNumberIntType, &port);
96 } else { 44 } else {
97 port = net::ProxyServer::GetDefaultPortForScheme(scheme); 45 port = GetDefaultPortForScheme(scheme);
98 } 46 }
99 47
100 return net::ProxyServer(scheme, host, port); 48 return 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
136
137 namespace net {
138
139 int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) {
140 scoped_cftyperef<CFDictionaryRef> config_dict(
141 SCDynamicStoreCopyProxies(NULL));
142 DCHECK(config_dict);
143
144 // auto-detect
145
146 // 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
148 // the header file so we'll use it.
149 config->auto_detect =
150 GetBoolFromDictionary(config_dict.get(),
151 kSCPropNetProxiesProxyAutoDiscoveryEnable,
152 false);
153
154 // PAC file
155
156 if (GetBoolFromDictionary(config_dict.get(),
157 kSCPropNetProxiesProxyAutoConfigEnable,
158 false)) {
159 CFStringRef pac_url_ref =
160 (CFStringRef)GetValueFromDictionary(
161 config_dict.get(),
162 kSCPropNetProxiesProxyAutoConfigURLString,
163 CFStringGetTypeID());
164 if (pac_url_ref)
165 config->pac_url = GURL(base::SysCFStringRefToUTF8(pac_url_ref));
166 }
167
168 // proxies (for now ftp, http, https, and SOCKS)
169
170 if (GetBoolFromDictionary(config_dict.get(),
171 kSCPropNetProxiesFTPEnable,
172 false)) {
173 ProxyServer proxy_server =
174 GetProxyServerFromDictionary(ProxyServer::SCHEME_HTTP,
175 config_dict.get(),
176 kSCPropNetProxiesFTPProxy,
177 kSCPropNetProxiesFTPPort);
178 if (proxy_server.is_valid()) {
179 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
180 config->proxy_rules.proxy_for_ftp = proxy_server;
181 }
182 }
183 if (GetBoolFromDictionary(config_dict.get(),
184 kSCPropNetProxiesHTTPEnable,
185 false)) {
186 ProxyServer proxy_server =
187 GetProxyServerFromDictionary(ProxyServer::SCHEME_HTTP,
188 config_dict.get(),
189 kSCPropNetProxiesHTTPProxy,
190 kSCPropNetProxiesHTTPPort);
191 if (proxy_server.is_valid()) {
192 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
193 config->proxy_rules.proxy_for_http = proxy_server;
194 }
195 }
196 if (GetBoolFromDictionary(config_dict.get(),
197 kSCPropNetProxiesHTTPSEnable,
198 false)) {
199 ProxyServer proxy_server =
200 GetProxyServerFromDictionary(ProxyServer::SCHEME_HTTP,
201 config_dict.get(),
202 kSCPropNetProxiesHTTPSProxy,
203 kSCPropNetProxiesHTTPSPort);
204 if (proxy_server.is_valid()) {
205 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
206 config->proxy_rules.proxy_for_https = proxy_server;
207 }
208 }
209 if (GetBoolFromDictionary(config_dict.get(),
210 kSCPropNetProxiesSOCKSEnable,
211 false)) {
212 ProxyServer proxy_server =
213 GetProxyServerFromDictionary(ProxyServer::SCHEME_SOCKS5,
214 config_dict.get(),
215 kSCPropNetProxiesSOCKSProxy,
216 kSCPropNetProxiesSOCKSPort);
217 if (proxy_server.is_valid()) {
218 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
219 config->proxy_rules.socks_proxy = proxy_server;
220 }
221 }
222
223 // proxy bypass list
224
225 CFArrayRef bypass_array_ref =
226 (CFArrayRef)GetValueFromDictionary(config_dict.get(),
227 kSCPropNetProxiesExceptionsList,
228 CFArrayGetTypeID());
229 if (bypass_array_ref) {
230 CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref);
231 for (CFIndex i = 0; i < bypass_array_count; ++i) {
232 CFStringRef bypass_item_ref =
233 (CFStringRef)CFArrayGetValueAtIndex(bypass_array_ref, i);
234 if (CFGetTypeID(bypass_item_ref) != CFStringGetTypeID()) {
235 LOG(WARNING) << "Expected value for item " << i
236 << " in the kSCPropNetProxiesExceptionsList"
237 " to be a CFStringRef but it was not";
238
239 } else {
240 config->proxy_bypass.push_back(
241 base::SysCFStringRefToUTF8(bypass_item_ref));
242 }
243 }
244 }
245
246 // proxy bypass boolean
247
248 config->proxy_bypass_local_names =
249 GetBoolFromDictionary(config_dict.get(),
250 kSCPropNetProxiesExcludeSimpleHostnames,
251 false);
252
253 return OK;
254 }
255
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 } 49 }
371 50
372 } // namespace net 51 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/proxy_server.h ('k') | net/proxy/proxy_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698