| OLD | NEW |
| 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 |
| OLD | NEW |