summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoravi@google.com <avi@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-30 18:47:16 +0000
committeravi@google.com <avi@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-30 18:47:16 +0000
commit332ff119039b7dd3ba3d1994dde0b077f015bc03 (patch)
tree5d6ac0ad34e0a53d213fbefebf28e79668a67338
parent38993f6f15fb7b12ee4c973910369dc82a1a5595 (diff)
downloadchromium_src-332ff119039b7dd3ba3d1994dde0b077f015bc03.zip
chromium_src-332ff119039b7dd3ba3d1994dde0b077f015bc03.tar.gz
chromium_src-332ff119039b7dd3ba3d1994dde0b077f015bc03.tar.bz2
Initial Mac proxy implementation
Review URL: http://codereview.chromium.org/8671 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4221 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/http/http_network_layer.cc4
-rw-r--r--net/net.xcodeproj/project.pbxproj10
-rw-r--r--net/net_lib.scons5
-rw-r--r--net/proxy/proxy_resolver_mac.cc342
-rw-r--r--net/proxy/proxy_resolver_mac.h25
-rw-r--r--net/proxy/proxy_resolver_winhttp.cc15
-rw-r--r--net/proxy/proxy_service.cc29
-rw-r--r--net/proxy/proxy_service.h12
-rw-r--r--net/proxy/proxy_service_unittest.cc23
9 files changed, 441 insertions, 24 deletions
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 1aaa226..9822998 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -13,6 +13,8 @@
#if defined(OS_WIN)
#include "net/http/http_transaction_winhttp.h"
#include "net/proxy/proxy_resolver_winhttp.h"
+#elif defined(OS_MACOSX)
+#include "net/proxy/proxy_resolver_mac.h"
#endif
namespace net {
@@ -51,6 +53,8 @@ HttpNetworkLayer::HttpNetworkLayer(const ProxyInfo* pi)
} else {
#if defined(OS_WIN)
proxy_resolver_.reset(new ProxyResolverWinHttp());
+#elif defined(OS_MACOSX)
+ proxy_resolver_.reset(new ProxyResolverMac());
#else
NOTIMPLEMENTED();
proxy_resolver_.reset(new ProxyResolverNull());
diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj
index e454b48..bb4aded 100644
--- a/net/net.xcodeproj/project.pbxproj
+++ b/net/net.xcodeproj/project.pbxproj
@@ -127,6 +127,8 @@
7BED34450E5A1A9600A747DB /* libbase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BED324A0E5A17C000A747DB /* libbase.a */; };
7BED34520E5A1ABC00A747DB /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BED32530E5A17C300A747DB /* libgtest.a */; };
8200F2030E5F741E005A3C44 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8200F2020E5F741E005A3C44 /* CoreServices.framework */; };
+ 820701040EB6611F005CD9E7 /* proxy_resolver_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 820701020EB6611F005CD9E7 /* proxy_resolver_mac.cc */; };
+ 820706940EB8D9D4005CD9E7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 820706930EB8D9D4005CD9E7 /* SystemConfiguration.framework */; };
82113A1D0E8434EE00E3848F /* x509_certificate_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 82113A1C0E8434EE00E3848F /* x509_certificate_unittest.cc */; };
82113A280E84360200E3848F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82113A270E84360200E3848F /* Security.framework */; };
82113BBD0E892E5800E3848F /* x509_certificate.cc in Sources */ = {isa = PBXBuildFile; fileRef = 82113BBC0E892E5800E3848F /* x509_certificate.cc */; };
@@ -655,6 +657,9 @@
7BED33BB0E5A198600A747DB /* url_request_inet_job.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = url_request_inet_job.cc; sourceTree = "<group>"; };
7BED33BC0E5A198600A747DB /* url_request_http_job.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url_request_http_job.h; sourceTree = "<group>"; };
8200F2020E5F741E005A3C44 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = "<group>"; };
+ 820701020EB6611F005CD9E7 /* proxy_resolver_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proxy_resolver_mac.cc; path = proxy/proxy_resolver_mac.cc; sourceTree = "<group>"; };
+ 820701030EB6611F005CD9E7 /* proxy_resolver_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = proxy_resolver_mac.h; path = proxy/proxy_resolver_mac.h; sourceTree = "<group>"; };
+ 820706930EB8D9D4005CD9E7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
82113A1C0E8434EE00E3848F /* x509_certificate_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate_unittest.cc; sourceTree = "<group>"; };
82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = "<group>"; };
82113BBC0E892E5800E3848F /* x509_certificate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate.cc; sourceTree = "<group>"; };
@@ -705,6 +710,7 @@
7BA362C40E8C3D4C0023C8B9 /* libsdch.a in Frameworks */,
7BA0169E0E5A1EAE00044150 /* libzlib.a in Frameworks */,
82113A280E84360200E3848F /* Security.framework in Frameworks */,
+ 820706940EB8D9D4005CD9E7 /* SystemConfiguration.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -816,6 +822,7 @@
8200F2020E5F741E005A3C44 /* CoreServices.framework */,
7BA0157A0E5A1C9100044150 /* Foundation.framework */,
82113A270E84360200E3848F /* Security.framework */,
+ 820706930EB8D9D4005CD9E7 /* SystemConfiguration.framework */,
);
name = Frameworks;
sourceTree = SDKROOT;
@@ -1137,6 +1144,8 @@
children = (
E49DD33A0E8933C0003C7A87 /* proxy_resolver_fixed.h */,
E49DD33B0E8933C0003C7A87 /* proxy_resolver_fixed.cc */,
+ 820701030EB6611F005CD9E7 /* proxy_resolver_mac.h */,
+ 820701020EB6611F005CD9E7 /* proxy_resolver_mac.cc */,
04AC41720EA941AE0063A0AB /* proxy_resolver_null.h */,
E49DD3350E8933A2003C7A87 /* proxy_service.h */,
E49DD3360E8933A2003C7A87 /* proxy_service.cc */,
@@ -1468,6 +1477,7 @@
7B85043B0E5B2E6400730B43 /* os_file_posix.cc in Sources */,
7B85043C0E5B2E6400730B43 /* platform_mime_util_mac.mm in Sources */,
E49DD33C0E8933C0003C7A87 /* proxy_resolver_fixed.cc in Sources */,
+ 820701040EB6611F005CD9E7 /* proxy_resolver_mac.cc in Sources */,
E49DD3370E8933A2003C7A87 /* proxy_service.cc in Sources */,
7B85043D0E5B2E6400730B43 /* rankings.cc in Sources */,
7B8B5B560E5CEADE002F9A97 /* registry_controlled_domain.cc in Sources */,
diff --git a/net/net_lib.scons b/net/net_lib.scons
index 7db4aa7..82a82eb 100644
--- a/net/net_lib.scons
+++ b/net/net_lib.scons
@@ -89,7 +89,6 @@ input_files = [
'http/http_vary_data.cc',
'http/winhttp_request_throttle.cc',
'proxy/proxy_resolver_fixed.cc',
- 'proxy/proxy_resolver_winhttp.cc',
'proxy/proxy_service.cc',
'url_request/mime_sniffer_proxy.cc',
'url_request/url_request.cc',
@@ -123,7 +122,6 @@ if env['PLATFORM'] in ('posix', 'darwin'):
'base/winsock_init.cc',
'http/http_transaction_winhttp.cc',
'http/winhttp_request_throttle.cc',
- 'proxy/proxy_resolver_winhttp.cc',
'url_request/url_request_file_dir_job.cc',
'url_request/url_request_ftp_job.cc',
'url_request/url_request_inet_job.cc',
@@ -142,12 +140,15 @@ if env['PLATFORM'] == 'win32':
'disk_cache/file_win.cc',
'disk_cache/mapped_file_win.cc',
'disk_cache/os_file_win.cc',
+ 'proxy/proxy_resolver_winhttp.cc',
])
if env['PLATFORM'] == 'darwin':
input_files.extend([
'base/platform_mime_util_mac.mm',
+ 'base/ssl_client_socket_mac.cc',
'base/x509_certificate_mac.cc',
+ 'proxy/proxy_resolver_mac.cc',
])
if env['PLATFORM'] == 'posix':
diff --git a/net/proxy/proxy_resolver_mac.cc b/net/proxy/proxy_resolver_mac.cc
new file mode 100644
index 0000000..0bf52b91
--- /dev/null
+++ b/net/proxy/proxy_resolver_mac.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/proxy/proxy_resolver_mac.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include "base/scoped_cftyperef.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "net/base/net_errors.h"
+
+namespace {
+
+// Utility function to pull out a value from a dictionary, check its type, and
+// return it. Returns NULL if the key is not present or of the wrong type.
+CFTypeRef GetValueFromDictionary(CFDictionaryRef dict,
+ CFStringRef key,
+ CFTypeID expected_type) {
+ CFTypeRef value = CFDictionaryGetValue(dict, key);
+ if (!value)
+ return value;
+
+ if (CFGetTypeID(value) != expected_type) {
+ scoped_cftyperef<CFStringRef> expected_type_ref(
+ CFCopyTypeIDDescription(expected_type));
+ scoped_cftyperef<CFStringRef> actual_type_ref(
+ CFCopyTypeIDDescription(CFGetTypeID(value)));
+ LOG(WARNING) << "Expected value for key "
+ << base::SysCFStringRefToUTF8(key)
+ << " to be "
+ << base::SysCFStringRefToUTF8(expected_type_ref)
+ << " but it was "
+ << base::SysCFStringRefToUTF8(actual_type_ref)
+ << " instead";
+ return NULL;
+ }
+
+ return value;
+}
+
+// Utility function to pull out a boolean value from a dictionary and return it,
+// returning a default value if the key is not present.
+bool GetBoolFromDictionary(CFDictionaryRef dict,
+ CFStringRef key,
+ bool default_value) {
+ CFNumberRef number = (CFNumberRef)GetValueFromDictionary(dict, key,
+ CFNumberGetTypeID());
+ if (!number)
+ return default_value;
+
+ int int_value;
+ if (CFNumberGetValue(number, kCFNumberIntType, &int_value))
+ return int_value;
+ else
+ return default_value;
+}
+
+// Utility function to pull out a host/port pair from a dictionary and format
+// them into a "<host>[:<port>]" style string. Pass in a dictionary that has a
+// value for the host key and optionally a value for the port key. Returns a
+// formatted string. In the error condition where the host value is especially
+// malformed, returns an empty string. (You may still want to check for that
+// result anyway.)
+std::string GetHostPortFromDictionary(CFDictionaryRef dict,
+ CFStringRef host_key,
+ CFStringRef port_key) {
+ std::string result;
+
+ CFStringRef host_ref =
+ (CFStringRef)GetValueFromDictionary(dict, host_key,
+ CFStringGetTypeID());
+ if (!host_ref) {
+ LOG(WARNING) << "Could not find expected key "
+ << base::SysCFStringRefToUTF8(host_key)
+ << " in the proxy dictionary";
+ return result;
+ }
+ result = base::SysCFStringRefToUTF8(host_ref);
+
+ CFNumberRef port_ref =
+ (CFNumberRef)GetValueFromDictionary(dict, port_key,
+ CFNumberGetTypeID());
+ if (port_ref) {
+ int port;
+ CFNumberGetValue(port_ref, kCFNumberIntType, &port);
+ result += ":";
+ result += IntToString(port);
+ }
+
+ return result;
+}
+
+// Callback for CFNetworkExecuteProxyAutoConfigurationURL. |client| is a pointer
+// to a CFTypeRef. This stashes either |error| or |proxies| in that location.
+void ResultCallback(void* client, CFArrayRef proxies, CFErrorRef error) {
+ DCHECK((proxies != NULL) == (error == NULL));
+
+ CFTypeRef* result_ptr = (CFTypeRef*)client;
+ DCHECK(result_ptr != NULL);
+ DCHECK(*result_ptr == NULL);
+
+ if (error != NULL) {
+ *result_ptr = CFRetain(error);
+ } else {
+ *result_ptr = CFRetain(proxies);
+ }
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+} // namespace
+
+namespace net {
+
+int ProxyResolverMac::GetProxyConfig(ProxyConfig* config) {
+ scoped_cftyperef<CFDictionaryRef> config_dict(
+ SCDynamicStoreCopyProxies(NULL));
+ DCHECK(config_dict);
+
+ // auto-detect
+
+ // There appears to be no UI for this configuration option, and we're not sure
+ // if Apple's proxy code even takes it into account. But the constant is in
+ // the header file so we'll use it.
+ config->auto_detect =
+ GetBoolFromDictionary(config_dict.get(),
+ kSCPropNetProxiesProxyAutoDiscoveryEnable,
+ false);
+
+ // PAC file
+
+ if (GetBoolFromDictionary(config_dict.get(),
+ kSCPropNetProxiesProxyAutoConfigEnable,
+ false)) {
+ CFStringRef pac_url_ref =
+ (CFStringRef)GetValueFromDictionary(
+ config_dict.get(),
+ kSCPropNetProxiesProxyAutoConfigURLString,
+ CFStringGetTypeID());
+ if (pac_url_ref)
+ config->pac_url = base::SysCFStringRefToUTF8(pac_url_ref);
+ }
+
+ // proxies (for now only ftp, http and https)
+
+ if (GetBoolFromDictionary(config_dict.get(),
+ kSCPropNetProxiesFTPEnable,
+ false)) {
+ std::string host_port =
+ GetHostPortFromDictionary(config_dict.get(),
+ kSCPropNetProxiesFTPProxy,
+ kSCPropNetProxiesFTPPort);
+ if (!host_port.empty()) {
+ config->proxy_server += "ftp=";
+ config->proxy_server += host_port;
+ }
+ }
+ if (GetBoolFromDictionary(config_dict.get(),
+ kSCPropNetProxiesHTTPEnable,
+ false)) {
+ std::string host_port =
+ GetHostPortFromDictionary(config_dict.get(),
+ kSCPropNetProxiesHTTPProxy,
+ kSCPropNetProxiesHTTPPort);
+ if (!host_port.empty()) {
+ if (!config->proxy_server.empty())
+ config->proxy_server += ";";
+ config->proxy_server += "http=";
+ config->proxy_server += host_port;
+ }
+ }
+ if (GetBoolFromDictionary(config_dict.get(),
+ kSCPropNetProxiesHTTPSEnable,
+ false)) {
+ std::string host_port =
+ GetHostPortFromDictionary(config_dict.get(),
+ kSCPropNetProxiesHTTPSProxy,
+ kSCPropNetProxiesHTTPSPort);
+ if (!host_port.empty()) {
+ if (!config->proxy_server.empty())
+ config->proxy_server += ";";
+ config->proxy_server += "https=";
+ config->proxy_server += host_port;
+ }
+ }
+
+ // proxy bypass list
+
+ CFArrayRef bypass_array_ref =
+ (CFArrayRef)GetValueFromDictionary(config_dict.get(),
+ kSCPropNetProxiesExceptionsList,
+ CFArrayGetTypeID());
+ if (bypass_array_ref) {
+ CFIndex bypass_array_count = CFArrayGetCount(bypass_array_ref);
+ for (CFIndex i = 0; i < bypass_array_count; ++i) {
+ CFStringRef bypass_item_ref =
+ (CFStringRef)CFArrayGetValueAtIndex(bypass_array_ref, i);
+ if (CFGetTypeID(bypass_item_ref) != CFStringGetTypeID()) {
+ LOG(WARNING) << "Expected value for item " << i
+ << " in the kSCPropNetProxiesExceptionsList"
+ " to be a CFStringRef but it was not";
+
+ } else {
+ config->proxy_bypass.push_back(
+ base::SysCFStringRefToUTF8(bypass_item_ref));
+ }
+ }
+ }
+
+ // proxy bypass boolean
+
+ config->proxy_bypass_local_names =
+ GetBoolFromDictionary(config_dict.get(),
+ kSCPropNetProxiesExcludeSimpleHostnames,
+ false);
+
+ return OK;
+}
+
+// Gets the proxy information for a query URL from a PAC. Implementation
+// inspired by http://developer.apple.com/samplecode/CFProxySupportTool/
+int ProxyResolverMac::GetProxyForURL(const std::string& query_url,
+ const std::string& pac_url,
+ ProxyInfo* results) {
+ scoped_cftyperef<CFStringRef> query_ref(
+ base::SysUTF8ToCFStringRef(query_url));
+ scoped_cftyperef<CFStringRef> pac_ref(
+ base::SysUTF8ToCFStringRef(pac_url));
+ scoped_cftyperef<CFURLRef> query_url_ref(
+ CFURLCreateWithString(kCFAllocatorDefault,
+ query_ref.get(),
+ NULL));
+ scoped_cftyperef<CFURLRef> pac_url_ref(
+ CFURLCreateWithString(kCFAllocatorDefault,
+ pac_ref.get(),
+ NULL));
+
+ // Work around <rdar://problem/5530166>. This dummy call to
+ // CFNetworkCopyProxiesForURL initializes some state within CFNetwork that is
+ // required by CFNetworkExecuteProxyAutoConfigurationURL.
+
+ CFArrayRef dummy_result = CFNetworkCopyProxiesForURL(query_url_ref.get(),
+ NULL);
+ if (dummy_result)
+ CFRelease(dummy_result);
+
+ // We cheat here. We need to act as if we were synchronous, so we pump the
+ // runloop ourselves. Our caller moved us to a new thread anyway, so this is
+ // OK to do. (BTW, CFNetworkExecuteProxyAutoConfigurationURL returns a
+ // runloop source we need to release despite its name.)
+
+ CFTypeRef result;
+ CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };
+ scoped_cftyperef<CFRunLoopSourceRef> runloop_source(
+ CFNetworkExecuteProxyAutoConfigurationURL(pac_url_ref.get(),
+ query_url_ref.get(),
+ ResultCallback,
+ &context));
+ if (!runloop_source)
+ return ERR_FAILED;
+
+ const CFStringRef private_runloop_mode =
+ CFSTR("org.chromium.ProxyResolverMac");
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source.get(),
+ private_runloop_mode);
+ CFRunLoopRunInMode(private_runloop_mode, DBL_MAX, false);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloop_source.get(),
+ private_runloop_mode);
+ DCHECK(result != NULL);
+
+ if (CFGetTypeID(result) == CFErrorGetTypeID()) {
+ // TODO(avi): do something better than this
+ CFRelease(result);
+ return ERR_FAILED;
+ }
+ DCHECK(CFGetTypeID(result) == CFArrayGetTypeID());
+ scoped_cftyperef<CFArrayRef> proxy_array_ref((CFArrayRef)result);
+
+ // Proxy information. If we're allowed to contact the site directly, we set
+ // allow_direct to true. If we've found proxies to use, apart from
+ // accumulating them in proxy_list, we set found_proxy to true. These
+ // bool results are orthogonal.
+ bool allow_direct = false;
+ std::string proxy_list;
+ bool found_proxy = false;
+
+ CFIndex proxy_array_count = CFArrayGetCount(proxy_array_ref.get());
+ for (CFIndex i = 0; i < proxy_array_count; ++i) {
+ CFDictionaryRef proxy_dictionary =
+ (CFDictionaryRef)CFArrayGetValueAtIndex(proxy_array_ref.get(), i);
+ DCHECK(CFGetTypeID(proxy_dictionary) == CFDictionaryGetTypeID());
+
+ // The dictionary may have the following keys:
+ // - kCFProxyTypeKey : The type of the proxy. We're assuming that it's of
+ // the type we asked for (e.g. kCFProxyTypeHTTP for
+ // http://... ) if it's not kCFProxyTypeNone.
+ // - kCFProxyHostNameKey
+ // - kCFProxyPortNumberKey : The meat we're after.
+ // - kCFProxyUsernameKey
+ // - kCFProxyPasswordKey : Despite the existence of these keys in the
+ // documentation, they're never populated. Even if a
+ // username/password were to be set in the network
+ // proxy system preferences, we'd need to fetch it
+ // from the Keychain ourselves. CFProxy is such a
+ // tease.
+ // - kCFProxyAutoConfigurationURLKey : If the PAC file specifies another
+ // PAC file, I'm going home.
+
+ CFStringRef proxy_type =
+ (CFStringRef)GetValueFromDictionary(proxy_dictionary,
+ kCFProxyTypeKey,
+ CFStringGetTypeID());
+ if (CFEqual(proxy_type, kCFProxyTypeNone))
+ allow_direct = true;
+ if (CFEqual(proxy_type, kCFProxyTypeNone) ||
+ CFEqual(proxy_type, kCFProxyTypeSOCKS) ||
+ CFEqual(proxy_type, kCFProxyTypeAutoConfigurationURL))
+ continue;
+
+ if (found_proxy)
+ proxy_list += ";";
+ else
+ found_proxy = true;
+
+ proxy_list += GetHostPortFromDictionary(proxy_dictionary,
+ kCFProxyHostNameKey,
+ kCFProxyPortNumberKey);
+ }
+
+ if (found_proxy)
+ results->UseNamedProxy(proxy_list);
+ if (allow_direct)
+ results->UseDirect();
+
+ return OK;
+}
+
+} // namespace net
diff --git a/net/proxy/proxy_resolver_mac.h b/net/proxy/proxy_resolver_mac.h
new file mode 100644
index 0000000..3063866
--- /dev/null
+++ b/net/proxy/proxy_resolver_mac.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_PROXY_PROXY_RESOLVER_MAC_H_
+#define NET_PROXY_PROXY_RESOLVER_MAC_H_
+
+#include "net/proxy/proxy_service.h"
+
+namespace net {
+
+// Implementation of ProxyResolver that uses the Mac CFProxySupport to implement
+// proxies.
+class ProxyResolverMac : public ProxyResolver {
+ public:
+ // ProxyResolver methods:
+ virtual int GetProxyConfig(ProxyConfig* config);
+ virtual int GetProxyForURL(const std::string& query_url,
+ const std::string& pac_url,
+ ProxyInfo* results);
+};
+
+} // namespace net
+
+#endif // NET_PROXY_PROXY_RESOLVER_MAC_H_
diff --git a/net/proxy/proxy_resolver_winhttp.cc b/net/proxy/proxy_resolver_winhttp.cc
index 5a16df5..19dd0b0 100644
--- a/net/proxy/proxy_resolver_winhttp.cc
+++ b/net/proxy/proxy_resolver_winhttp.cc
@@ -8,6 +8,7 @@
#include <winhttp.h>
#include "base/histogram.h"
+#include "base/string_tokenizer.h"
#include "net/base/net_errors.h"
#pragma comment(lib, "winhttp.lib")
@@ -70,8 +71,18 @@ int ProxyResolverWinHttp::GetProxyConfig(ProxyConfig* config) {
config->auto_detect = true;
if (ie_config.lpszProxy)
config->proxy_server = WideToASCII(ie_config.lpszProxy);
- if (ie_config.lpszProxyBypass)
- config->proxy_bypass = WideToASCII(ie_config.lpszProxyBypass);
+ if (ie_config.lpszProxyBypass) {
+ std::string proxy_bypass = WideToASCII(ie_config.lpszProxyBypass);
+
+ StringTokenizer proxy_server_bypass_list(proxy_bypass, "; \t\n\r");
+ while (proxy_server_bypass_list.GetNext()) {
+ std::string bypass_url_domain = proxy_server_bypass_list.token();
+ if (bypass_url_domain == "<local>")
+ config->proxy_bypass_local_names = true;
+ else
+ config->proxy_bypass.push_back(bypass_url_domain);
+ }
+ }
if (ie_config.lpszAutoConfigUrl)
config->pac_url = WideToASCII(ie_config.lpszAutoConfigUrl);
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index 52d8491..394a97f 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -30,6 +30,7 @@ ProxyConfig::ID ProxyConfig::last_id_ = ProxyConfig::INVALID_ID;
ProxyConfig::ProxyConfig()
: auto_detect(false),
+ proxy_bypass_local_names(false),
id_(++last_id_) {
}
@@ -39,7 +40,8 @@ bool ProxyConfig::Equals(const ProxyConfig& other) const {
return auto_detect == other.auto_detect &&
pac_url == other.pac_url &&
proxy_server == other.proxy_server &&
- proxy_bypass == other.proxy_bypass;
+ proxy_bypass == other.proxy_bypass &&
+ proxy_bypass_local_names == other.proxy_bypass_local_names;
}
// ProxyList ------------------------------------------------------------------
@@ -445,17 +447,18 @@ bool ProxyService::ShouldBypassProxyForURL(const GURL& url) {
url_domain += "://";
url_domain += url.host();
+ // This isn't superfluous; GURL case canonicalization doesn't hit the embedded
+ // percent-encoded characters.
StringToLowerASCII(&url_domain);
- StringTokenizer proxy_server_bypass_list(config_.proxy_bypass, ";");
- while (proxy_server_bypass_list.GetNext()) {
- std::string bypass_url_domain = proxy_server_bypass_list.token();
- if (bypass_url_domain == "<local>") {
- // Any name without a DOT (.) is considered to be local.
- if (url.host().find('.') == std::string::npos)
- return true;
- continue;
- }
+ if (config_.proxy_bypass_local_names) {
+ if (url.host().find('.') == std::string::npos)
+ return true;
+ }
+
+ for(std::vector<std::string>::const_iterator i = config_.proxy_bypass.begin();
+ i != config_.proxy_bypass.end(); ++i) {
+ std::string bypass_url_domain = *i;
// The proxy server bypass list can contain entities with http/https
// If no scheme is specified then it indicates that all schemes are
@@ -473,6 +476,12 @@ bool ProxyService::ShouldBypassProxyForURL(const GURL& url) {
if (MatchPattern(url_domain, bypass_url_domain))
return true;
+
+ // Some systems (the Mac, for example) allow CIDR-style specification of
+ // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see
+ // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example).
+ // That's kinda cool so we'll provide that for everyone.
+ // TODO(avi): implement here
}
return false;
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index c596aab..8ea3653 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -47,12 +47,16 @@ class ProxyConfig {
std::string pac_url;
// If non-empty, indicates the proxy server to use (of the form host:port).
+ // If proxies depend on the scheme, a string of the format
+ // "scheme1=url[:port];scheme2=url[:port]" may be provided here.
std::string proxy_server;
- // If non-empty, indicates a comma-delimited list of hosts that should bypass
- // any proxy configuration. For these hosts, a direct connection should
- // always be used.
- std::string proxy_bypass;
+ // Indicates a list of hosts that should bypass any proxy configuration. For
+ // these hosts, a direct connection should always be used.
+ std::vector<std::string> proxy_bypass;
+
+ // Indicates whether local names (no dots) bypass proxies.
+ bool proxy_bypass_local_names;
// Returns true if the given config is equivalent to this config.
bool Equals(const ProxyConfig& other) const;
diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc
index d33ac6d..8166a42 100644
--- a/net/proxy/proxy_service_unittest.cc
+++ b/net/proxy/proxy_service_unittest.cc
@@ -301,7 +301,7 @@ TEST(ProxyServiceTest, ProxyBypassList) {
MockProxyResolver resolver;
resolver.config->proxy_server = "foopy1:8080;foopy2:9090";
resolver.config->auto_detect = false;
- resolver.config->proxy_bypass = "<local>";
+ resolver.config->proxy_bypass_local_names = true;
net::ProxyService service(&resolver);
GURL url("http://www.google.com/");
@@ -318,7 +318,9 @@ TEST(ProxyServiceTest, ProxyBypassList) {
EXPECT_EQ(rv, net::OK);
EXPECT_TRUE(info1.is_direct());
- resolver.config->proxy_bypass = "<local>;*.org";
+ resolver.config->proxy_bypass.clear();
+ resolver.config->proxy_bypass.push_back("*.org");
+ resolver.config->proxy_bypass_local_names = true;
net::ProxyService service2(&resolver);
GURL test_url2("http://www.webkit.org");
net::ProxyInfo info2;
@@ -326,7 +328,10 @@ TEST(ProxyServiceTest, ProxyBypassList) {
EXPECT_EQ(rv, net::OK);
EXPECT_TRUE(info2.is_direct());
- resolver.config->proxy_bypass = "<local>;*.org;7*";
+ resolver.config->proxy_bypass.clear();
+ resolver.config->proxy_bypass.push_back("*.org");
+ resolver.config->proxy_bypass.push_back("7*");
+ resolver.config->proxy_bypass_local_names = true;
net::ProxyService service3(&resolver);
GURL test_url3("http://74.125.19.147");
net::ProxyInfo info3;
@@ -334,7 +339,9 @@ TEST(ProxyServiceTest, ProxyBypassList) {
EXPECT_EQ(rv, net::OK);
EXPECT_TRUE(info3.is_direct());
- resolver.config->proxy_bypass = "<local>;*.org;";
+ resolver.config->proxy_bypass.clear();
+ resolver.config->proxy_bypass.push_back("*.org");
+ resolver.config->proxy_bypass_local_names = true;
net::ProxyService service4(&resolver);
GURL test_url4("http://www.msn.com");
net::ProxyInfo info4;
@@ -342,7 +349,9 @@ TEST(ProxyServiceTest, ProxyBypassList) {
EXPECT_EQ(rv, net::OK);
EXPECT_FALSE(info4.is_direct());
- resolver.config->proxy_bypass = "<local>;*.MSN.COM;";
+ resolver.config->proxy_bypass.clear();
+ resolver.config->proxy_bypass.push_back("*.MSN.COM");
+ resolver.config->proxy_bypass_local_names = true;
net::ProxyService service5(&resolver);
GURL test_url5("http://www.msnbc.msn.com");
net::ProxyInfo info5;
@@ -350,7 +359,9 @@ TEST(ProxyServiceTest, ProxyBypassList) {
EXPECT_EQ(rv, net::OK);
EXPECT_TRUE(info5.is_direct());
- resolver.config->proxy_bypass = "<local>;*.msn.com;";
+ resolver.config->proxy_bypass.clear();
+ resolver.config->proxy_bypass.push_back("*.msn.com");
+ resolver.config->proxy_bypass_local_names = true;
net::ProxyService service6(&resolver);
GURL test_url6("HTTP://WWW.MSNBC.MSN.COM");
net::ProxyInfo info6;