| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 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_resolver_mac.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 |
| 9 #include "base/logging.h" |
| 10 #include "base/mac_util.h" |
| 11 #include "base/scoped_cftyperef.h" | 11 #include "base/scoped_cftyperef.h" |
| 12 #include "base/string_util.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" | |
| 16 #include "net/proxy/proxy_info.h" | 15 #include "net/proxy/proxy_info.h" |
| 17 #include "net/proxy/proxy_server.h" | 16 #include "net/proxy/proxy_server.h" |
| 18 | 17 |
| 19 namespace { | 18 namespace { |
| 20 | 19 |
| 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, | |
| 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. | |
| 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. | 20 // Utility function to map a CFProxyType to a ProxyServer::Scheme. |
| 104 // If the type is unknown, returns ProxyServer::SCHEME_INVALID. | 21 // If the type is unknown, returns ProxyServer::SCHEME_INVALID. |
| 105 net::ProxyServer::Scheme GetProxyServerScheme(CFStringRef proxy_type) { | 22 net::ProxyServer::Scheme GetProxyServerScheme(CFStringRef proxy_type) { |
| 106 if (CFEqual(proxy_type, kCFProxyTypeNone)) | 23 if (CFEqual(proxy_type, kCFProxyTypeNone)) |
| 107 return net::ProxyServer::SCHEME_DIRECT; | 24 return net::ProxyServer::SCHEME_DIRECT; |
| 108 if (CFEqual(proxy_type, kCFProxyTypeHTTP)) | 25 if (CFEqual(proxy_type, kCFProxyTypeHTTP)) |
| 109 return net::ProxyServer::SCHEME_HTTP; | 26 return net::ProxyServer::SCHEME_HTTP; |
| 110 if (CFEqual(proxy_type, kCFProxyTypeSOCKS)) { | 27 if (CFEqual(proxy_type, kCFProxyTypeSOCKS)) { |
| 111 // We can't tell whether this was v4 or v5. We will assume it is | 28 // 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. | 29 // v5 since that is the only version OS X supports. |
| 113 return net::ProxyServer::SCHEME_SOCKS5; | 30 return net::ProxyServer::SCHEME_SOCKS5; |
| 114 } | 31 } |
| 115 return net::ProxyServer::SCHEME_INVALID; | 32 return net::ProxyServer::SCHEME_INVALID; |
| 116 } | 33 } |
| 117 | 34 |
| 118 // Callback for CFNetworkExecuteProxyAutoConfigurationURL. |client| is a pointer | 35 // Callback for CFNetworkExecuteProxyAutoConfigurationURL. |client| is a pointer |
| 119 // to a CFTypeRef. This stashes either |error| or |proxies| in that location. | 36 // to a CFTypeRef. This stashes either |error| or |proxies| in that location. |
| 120 void ResultCallback(void* client, CFArrayRef proxies, CFErrorRef error) { | 37 void ResultCallback(void* client, CFArrayRef proxies, CFErrorRef error) { |
| 121 DCHECK((proxies != NULL) == (error == NULL)); | 38 DCHECK((proxies != NULL) == (error == NULL)); |
| 122 | 39 |
| 123 CFTypeRef* result_ptr = (CFTypeRef*)client; | 40 CFTypeRef* result_ptr = reinterpret_cast<CFTypeRef*>(client); |
| 124 DCHECK(result_ptr != NULL); | 41 DCHECK(result_ptr != NULL); |
| 125 DCHECK(*result_ptr == NULL); | 42 DCHECK(*result_ptr == NULL); |
| 126 | 43 |
| 127 if (error != NULL) { | 44 if (error != NULL) { |
| 128 *result_ptr = CFRetain(error); | 45 *result_ptr = CFRetain(error); |
| 129 } else { | 46 } else { |
| 130 *result_ptr = CFRetain(proxies); | 47 *result_ptr = CFRetain(proxies); |
| 131 } | 48 } |
| 132 CFRunLoopStop(CFRunLoopGetCurrent()); | 49 CFRunLoopStop(CFRunLoopGetCurrent()); |
| 133 } | 50 } |
| 134 | 51 |
| 135 } // namespace | 52 } // namespace |
| 136 | 53 |
| 137 namespace net { | 54 namespace net { |
| 138 | 55 |
| 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 | 56 // Gets the proxy information for a query URL from a PAC. Implementation |
| 257 // inspired by http://developer.apple.com/samplecode/CFProxySupportTool/ | 57 // inspired by http://developer.apple.com/samplecode/CFProxySupportTool/ |
| 258 int ProxyResolverMac::GetProxyForURL(const GURL& query_url, | 58 int ProxyResolverMac::GetProxyForURL(const GURL& query_url, |
| 259 ProxyInfo* results, | 59 ProxyInfo* results, |
| 260 CompletionCallback* /*callback*/, | 60 CompletionCallback* /*callback*/, |
| 261 RequestHandle* /*request*/, | 61 RequestHandle* /*request*/, |
| 262 LoadLog* load_log) { | 62 LoadLog* load_log) { |
| 263 scoped_cftyperef<CFStringRef> query_ref( | 63 scoped_cftyperef<CFStringRef> query_ref( |
| 264 base::SysUTF8ToCFStringRef(query_url.spec())); | 64 base::SysUTF8ToCFStringRef(query_url.spec())); |
| 265 scoped_cftyperef<CFURLRef> query_url_ref( | 65 scoped_cftyperef<CFURLRef> query_url_ref( |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 // - kCFProxyPasswordKey : Despite the existence of these keys in the | 139 // - kCFProxyPasswordKey : Despite the existence of these keys in the |
| 340 // documentation, they're never populated. Even if a | 140 // documentation, they're never populated. Even if a |
| 341 // username/password were to be set in the network | 141 // username/password were to be set in the network |
| 342 // proxy system preferences, we'd need to fetch it | 142 // proxy system preferences, we'd need to fetch it |
| 343 // from the Keychain ourselves. CFProxy is such a | 143 // from the Keychain ourselves. CFProxy is such a |
| 344 // tease. | 144 // tease. |
| 345 // - kCFProxyAutoConfigurationURLKey : If the PAC file specifies another | 145 // - kCFProxyAutoConfigurationURLKey : If the PAC file specifies another |
| 346 // PAC file, I'm going home. | 146 // PAC file, I'm going home. |
| 347 | 147 |
| 348 CFStringRef proxy_type = | 148 CFStringRef proxy_type = |
| 349 (CFStringRef)GetValueFromDictionary(proxy_dictionary, | 149 (CFStringRef)mac_util::GetValueFromDictionary(proxy_dictionary, |
| 350 kCFProxyTypeKey, | 150 kCFProxyTypeKey, |
| 351 CFStringGetTypeID()); | 151 CFStringGetTypeID()); |
| 352 ProxyServer proxy_server = | 152 ProxyServer proxy_server = ProxyServer::FromDictionary( |
| 353 GetProxyServerFromDictionary(GetProxyServerScheme(proxy_type), | 153 GetProxyServerScheme(proxy_type), |
| 354 proxy_dictionary, | 154 proxy_dictionary, |
| 355 kCFProxyHostNameKey, | 155 kCFProxyHostNameKey, |
| 356 kCFProxyPortNumberKey); | 156 kCFProxyPortNumberKey); |
| 357 if (!proxy_server.is_valid()) | 157 if (!proxy_server.is_valid()) |
| 358 continue; | 158 continue; |
| 359 | 159 |
| 360 if (!proxy_uri_list.empty()) | 160 if (!proxy_uri_list.empty()) |
| 361 proxy_uri_list += ";"; | 161 proxy_uri_list += ";"; |
| 362 proxy_uri_list += proxy_server.ToURI(); | 162 proxy_uri_list += proxy_server.ToURI(); |
| 363 } | 163 } |
| 364 | 164 |
| 365 if (!proxy_uri_list.empty()) | 165 if (!proxy_uri_list.empty()) |
| 366 results->UseNamedProxy(proxy_uri_list); | 166 results->UseNamedProxy(proxy_uri_list); |
| 367 // Else do nothing (results is already guaranteed to be in the default state). | 167 // Else do nothing (results is already guaranteed to be in the default state). |
| 368 | 168 |
| 369 return OK; | 169 return OK; |
| 370 } | 170 } |
| 371 | 171 |
| 372 } // namespace net | 172 } // namespace net |
| OLD | NEW |