diff options
author | robertshield@google.com <robertshield@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-12 15:07:50 +0000 |
---|---|---|
committer | robertshield@google.com <robertshield@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-12 15:07:50 +0000 |
commit | ab501a6a67596eb43d233f91f7500779dcbe8740 (patch) | |
tree | 90bfc9f94bf80c4ed7081d8d54454f02075c3c26 | |
parent | 481fe3bfb2359849d1d3fc9d0ceba4161fbb5a3e (diff) | |
download | chromium_src-ab501a6a67596eb43d233f91f7500779dcbe8740.zip chromium_src-ab501a6a67596eb43d233f91f7500779dcbe8740.tar.gz chromium_src-ab501a6a67596eb43d233f91f7500779dcbe8740.tar.bz2 |
Making command-line specified proxy settings more flexible - allowing for setting of auto-detect, pac url, per-schema proxy settings, proxy bypass urls.
BUG=http://crbug.com/266
Review URL: http://codereview.chromium.org/115029
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15855 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 64 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.h | 8 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context_unittest.cc | 181 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | chrome/chrome.sln | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 18 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 4 | ||||
-rw-r--r-- | chrome/test/unit/unittests.vcproj | 4 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 6 | ||||
-rw-r--r-- | net/net.gyp | 3 | ||||
-rw-r--r-- | net/proxy/proxy_config.cc | 69 | ||||
-rw-r--r-- | net/proxy/proxy_config.h | 11 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_fixed.h | 9 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_linux.cc | 67 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_linux.h | 4 | ||||
-rw-r--r-- | net/proxy/proxy_config_unittest.cc | 34 | ||||
-rw-r--r-- | net/proxy/proxy_script_fetcher_unittest.cc | 2 | ||||
-rw-r--r-- | net/proxy/proxy_service.cc | 60 | ||||
-rw-r--r-- | net/proxy/proxy_service.h | 10 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.h | 7 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell_request_context.cc | 5 |
21 files changed, 444 insertions, 127 deletions
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index b15db26..85a33c9 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -23,26 +23,68 @@ #include "net/proxy/proxy_service.h" #include "webkit/glue/webkit_glue.h" -// Sets up proxy info if overrides were specified on the command line. -// Otherwise returns NULL (meaning we should use the system defaults). -// The caller is responsible for deleting returned pointer. -static net::ProxyInfo* CreateProxyInfo(const CommandLine& command_line) { - net::ProxyInfo* proxy_info = NULL; +net::ProxyConfig* CreateProxyConfig(const CommandLine& command_line) { + // Scan for all "enable" type proxy switches. + static const wchar_t* proxy_switches[] = { + switches::kProxyServer, + switches::kProxyServerPacUrl, + switches::kProxyServerAutoDetect, + switches::kProxyServerBypassUrls + }; + + bool found_enable_proxy_switch = false; + for (size_t i = 0; i < arraysize(proxy_switches); i++) { + if (command_line.HasSwitch(proxy_switches[i])) { + found_enable_proxy_switch = true; + break; + } + } + + if (!found_enable_proxy_switch && + !command_line.HasSwitch(switches::kNoProxyServer)) { + return NULL; + } + + net::ProxyConfig* proxy_config = new net::ProxyConfig(); + if (command_line.HasSwitch(switches::kNoProxyServer)) { + // Ignore (and warn about) all the other proxy config switches we get if + // the no-proxy-server command line argument is present. + if (found_enable_proxy_switch) { + LOG(WARNING) << "Additional command line proxy switches found when --" + << switches::kNoProxyServer << " was specified."; + } + return proxy_config; + } if (command_line.HasSwitch(switches::kProxyServer)) { - proxy_info = new net::ProxyInfo(); const std::wstring& proxy_server = command_line.GetSwitchValue(switches::kProxyServer); - proxy_info->UseNamedProxy(WideToASCII(proxy_server)); + proxy_config->proxy_rules.ParseFromString(WideToASCII(proxy_server)); + } + + if (command_line.HasSwitch(switches::kProxyServerPacUrl)) { + proxy_config->pac_url = + GURL(WideToASCII(command_line.GetSwitchValue( + switches::kProxyServerPacUrl))); + } + + if (command_line.HasSwitch(switches::kProxyServerAutoDetect)) { + proxy_config->auto_detect = true; + } + + if (command_line.HasSwitch(switches::kProxyServerBypassUrls)) { + proxy_config->ParseNoProxyList( + WideToASCII(command_line.GetSwitchValue( + switches::kProxyServerBypassUrls))); } - return proxy_info; + return proxy_config; } // Create a proxy service according to the options on command line. static net::ProxyService* CreateProxyService(URLRequestContext* context, const CommandLine& command_line) { - scoped_ptr<net::ProxyInfo> proxy_info(CreateProxyInfo(command_line)); + scoped_ptr<net::ProxyConfig> proxy_config(CreateProxyConfig(command_line)); bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver); if (use_v8 && command_line.HasSwitch(switches::kSingleProcess)) { @@ -53,8 +95,8 @@ static net::ProxyService* CreateProxyService(URLRequestContext* context, } return use_v8 ? - net::ProxyService::CreateUsingV8Resolver(proxy_info.get(), context) : - net::ProxyService::Create(proxy_info.get()); + net::ProxyService::CreateUsingV8Resolver(proxy_config.get(), context) : + net::ProxyService::Create(proxy_config.get()); } // static diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h index 34b3d97..6f392a7 100644 --- a/chrome/browser/net/chrome_url_request_context.h +++ b/chrome/browser/net/chrome_url_request_context.h @@ -9,6 +9,10 @@ #include "net/url_request/url_request_context.h" class Profile; +class CommandLine; +namespace net { +class ProxyConfig; +} // A URLRequestContext subclass used by the browser. This can be used to store // extra information about requests, beyond what is supported by the base @@ -96,3 +100,7 @@ class ChromeURLRequestContext : public URLRequestContext, bool is_media_; bool is_off_the_record_; }; + +// Creates a proxy configuration using the overrides specified on the command +// line. Returns NULL if the system defaults should be used instead. +net::ProxyConfig* CreateProxyConfig(const CommandLine& command_line); diff --git a/chrome/browser/net/chrome_url_request_context_unittest.cc b/chrome/browser/net/chrome_url_request_context_unittest.cc new file mode 100644 index 0000000..e74e7a8 --- /dev/null +++ b/chrome/browser/net/chrome_url_request_context_unittest.cc @@ -0,0 +1,181 @@ +// Copyright (c) 2006-2009 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 "base/command_line.h" +#include "chrome/browser/net/chrome_url_request_context.h" +#include "chrome/common/chrome_switches.h" +#include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service_common_unittest.h" + +#include "testing/gtest/include/gtest/gtest.h" + +// Builds an identifier for each test in an array. +#define TEST_DESC(desc) StringPrintf("at line %d <%s>", __LINE__, desc) + +TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { + // Build the input command lines here. + CommandLine empty(L"foo.exe"); + CommandLine no_proxy(L"foo.exe"); + no_proxy.AppendSwitch(switches::kNoProxyServer); + CommandLine no_proxy_extra_params(L"foo.exe"); + no_proxy_extra_params.AppendSwitch(switches::kNoProxyServer); + no_proxy_extra_params.AppendSwitchWithValue(switches::kProxyServer, + L"http://proxy:8888"); + CommandLine single_proxy(L"foo.exe"); + single_proxy.AppendSwitchWithValue(switches::kProxyServer, + L"http://proxy:8888"); + CommandLine per_scheme_proxy(L"foo.exe"); + per_scheme_proxy.AppendSwitchWithValue(switches::kProxyServer, + L"http=httpproxy:8888;ftp=ftpproxy:8889"); + CommandLine per_scheme_proxy_bypass(L"foo.exe"); + per_scheme_proxy_bypass.AppendSwitchWithValue(switches::kProxyServer, + L"http=httpproxy:8888;ftp=ftpproxy:8889"); + per_scheme_proxy_bypass.AppendSwitchWithValue( + switches::kProxyServerBypassUrls, + L".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8"); + CommandLine with_pac_url(L"foo.exe"); + with_pac_url.AppendSwitchWithValue(switches::kProxyServerPacUrl, + L"http://wpad/wpad.dat"); + with_pac_url.AppendSwitchWithValue( + switches::kProxyServerBypassUrls, + L".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8"); + CommandLine with_auto_detect(L"foo.exe"); + with_auto_detect.AppendSwitch(switches::kProxyServerAutoDetect); + + // Inspired from proxy_config_service_win_unittest.cc. + const struct { + // Short description to identify the test + std::string description; + + // The command line to build a ProxyConfig from. + const CommandLine& command_line; + + // Expected outputs (fields of the ProxyConfig). + bool is_null; + bool auto_detect; + GURL pac_url; + net::ProxyConfig::ProxyRules proxy_rules; + const char* proxy_bypass_list; // newline separated + bool bypass_local_names; + } tests[] = { + { + TEST_DESC("Empty command line"), + // Input + empty, + // Expected result + true, // is_null + false, // auto_detect + GURL(), // pac_url + net::ProxyConfig::ProxyRules(), // proxy_rules + "", // proxy_bypass_list + false // bypass_local_names + }, + { + TEST_DESC("No proxy"), + // Input + no_proxy, + // Expected result + false, // is_null + false, // auto_detect + GURL(), // pac_url + net::ProxyConfig::ProxyRules(), // proxy_rules + "", // proxy_bypass_list + false // bypass_local_names + }, + { + TEST_DESC("No proxy with extra parameters."), + // Input + no_proxy_extra_params, + // Expected result + false, // is_null + false, // auto_detect + GURL(), // pac_url + net::ProxyConfig::ProxyRules(), // proxy_rules + "", // proxy_bypass_list + false // bypass_local_names + }, + { + TEST_DESC("Single proxy."), + // Input + single_proxy, + // Expected result + false, // is_null + false, // auto_detect + GURL(), // pac_url + net::MakeSingleProxyRules("http://proxy:8888"), // proxy_rules + "", // proxy_bypass_list + false // bypass_local_names + }, + { + TEST_DESC("Per scheme proxy."), + // Input + per_scheme_proxy, + // Expected result + false, // is_null + false, // auto_detect + GURL(), // pac_url + net::MakeProxyPerSchemeRules("httpproxy:8888", + "", + "ftpproxy:8889"), // proxy_rules + "", // proxy_bypass_list + false // bypass_local_names + }, + { + TEST_DESC("Per scheme proxy with bypass URLs."), + // Input + per_scheme_proxy_bypass, + // Expected result + false, // is_null + false, // auto_detect + GURL(), // pac_url + net::MakeProxyPerSchemeRules("httpproxy:8888", + "", + "ftpproxy:8889"), // proxy_rules + "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", + false // bypass_local_names + }, + { + TEST_DESC("Pac URL with proxy bypass URLs"), + // Input + with_pac_url, + // Expected result + false, // is_null + false, // auto_detect + GURL("http://wpad/wpad.dat"), // pac_url + net::ProxyConfig::ProxyRules(), // proxy_rules + "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", + false // bypass_local_names + }, + { + TEST_DESC("Autodetect"), + // Input + with_auto_detect, + // Expected result + false, // is_null + true, // auto_detect + GURL(), // pac_url + net::ProxyConfig::ProxyRules(), // proxy_rules + "", // proxy_bypass_list + false // bypass_local_names + } + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); i++) { + SCOPED_TRACE(StringPrintf("Test[%d] %s", i, tests[i].description.c_str())); + scoped_ptr<net::ProxyConfig> config(CreateProxyConfig( + CommandLine(tests[i].command_line))); + + if (tests[i].is_null) { + EXPECT_TRUE(config == NULL); + } else { + EXPECT_TRUE(config != NULL); + EXPECT_EQ(tests[i].auto_detect, config->auto_detect); + EXPECT_EQ(tests[i].pac_url, config->pac_url); + EXPECT_EQ(tests[i].proxy_bypass_list, + net::FlattenProxyBypass(config->proxy_bypass)); + EXPECT_EQ(tests[i].bypass_local_names, config->proxy_bypass_local_names); + EXPECT_EQ(tests[i].proxy_rules, config->proxy_rules); + } + } +} diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 2bb811b..79d9be2 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2584,6 +2584,7 @@ 'chrome_resources', 'chrome_strings', 'test_support_unit', + '../net/net.gyp:net_test_support', '../printing/printing.gyp:printing', '../webkit/webkit.gyp:webkit', '../skia/skia.gyp:skia', @@ -2685,6 +2686,7 @@ 'browser/metrics/metrics_response_unittest.cc', 'browser/navigation_controller_unittest.cc', 'browser/navigation_entry_unittest.cc', + 'browser/net/chrome_url_request_context_unittest.cc', 'browser/net/dns_host_info_unittest.cc', 'browser/net/dns_master_unittest.cc', 'browser/net/resolve_proxy_msg_helper_unittest.cc', diff --git a/chrome/chrome.sln b/chrome/chrome.sln index ce4d621..ca346ed 100644 --- a/chrome/chrome.sln +++ b/chrome/chrome.sln @@ -304,7 +304,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_tests", "test\unit\uni {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} = {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} {D5E8DCB2-9C61-446F-8BEE-B18CA0E0936E} = {D5E8DCB2-9C61-446F-8BEE-B18CA0E0936E} {D9DDAF60-663F-49CC-90DC-3D08CC3D1B28} = {D9DDAF60-663F-49CC-90DC-3D08CC3D1B28} + {E99DA267-BE90-4F45-88A1-6919DB2C7567} = {E99DA267-BE90-4F45-88A1-6919DB2C7567} {EC8B7909-62AF-470D-A75D-E1D89C837142} = {EC8B7909-62AF-470D-A75D-E1D89C837142} + {ED19720A-8F14-D3FC-9C6D-EEB5AE4D5BD7} = {ED19720A-8F14-D3FC-9C6D-EEB5AE4D5BD7} {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF5E94AB-B646-4E5B-A058-52EF07B8351C} {EFBB1436-A63F-4CD8-9E99-B89226E782EC} = {EFBB1436-A63F-4CD8-9E99-B89226E782EC} {F4F4BCAA-EA59-445C-A119-3E6C29647A51} = {F4F4BCAA-EA59-445C-A119-3E6C29647A51} @@ -1223,6 +1225,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_test", "test\memory_ {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} {C564F145-9172-42C3-BFCB-6014CA97DBCD} = {C564F145-9172-42C3-BFCB-6014CA97DBCD} {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} = {CD9CA56E-4E94-444C-87D4-58CA1E6F300D} + {ED19720A-8F14-D3FC-9C6D-EEB5AE4D5BD7} = {ED19720A-8F14-D3FC-9C6D-EEB5AE4D5BD7} {EF5E94AB-B646-4E5B-A058-52EF07B8351C} = {EF5E94AB-B646-4E5B-A058-52EF07B8351C} {FA537565-7B03-4FFC-AF15-F7A979B72E22} = {FA537565-7B03-4FFC-AF15-F7A979B72E22} EndProjectSection diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index ff0522a..3e1a7d1 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -233,9 +233,25 @@ const wchar_t kMakeDefaultBrowser[] = L"make-default-browser"; // affects HTTP and HTTPS requests. const wchar_t kProxyServer[] = L"proxy-server"; +// Don't use a proxy server, always make direct connections. Overrides any +// other proxy server flags that are passed. +const wchar_t kNoProxyServer[] = L"no-proxy-server"; + +// Specify a list of URLs for whom we bypass proxy settings and use direct +// connections. Ignored if proxy-server-auto-detect or no-proxy-server are +// also specified. +// TODO(robertshield): Specify URL format. +const wchar_t kProxyServerBypassUrls[] = L"proxy-server-bypass-urls"; + +// Force proxy auto-detection. +const wchar_t kProxyServerAutoDetect[] = L"proxy-server-auto-detect"; + +// Use the pac script at the given URL +const wchar_t kProxyServerPacUrl[] = L"proxy-server-pac-url"; + // Use WinHTTP to fetch and evaluate PAC scripts. Otherwise the default is // to use Chromium's network stack to fetch, and V8 to evaluate. -const wchar_t kWinHttpProxyResolver[] = L"winhttp-proxy-resolver"; +const wchar_t kWinHttpProxyResolver[] = L"winhttp-proxy-resolver"; // Chrome will support prefetching of DNS information. Until this becomes // the default, we'll provide a command line switch. diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 83682d0..e1d0243 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -77,6 +77,10 @@ extern const wchar_t kShowIcons[]; extern const wchar_t kMakeDefaultBrowser[]; extern const wchar_t kProxyServer[]; +extern const wchar_t kNoProxyServer[]; +extern const wchar_t kProxyServerBypassUrls[]; +extern const wchar_t kProxyServerAutoDetect[]; +extern const wchar_t kProxyServerPacUrl[]; extern const wchar_t kWinHttpProxyResolver[]; extern const wchar_t kDebugPrint[]; diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj index f36c673..b3fa491 100644 --- a/chrome/test/unit/unittests.vcproj +++ b/chrome/test/unit/unittests.vcproj @@ -456,6 +456,10 @@ > </File> <File + RelativePath="..\..\browser\net\chrome_url_request_context_unittest.cc" + > + </File> + <File RelativePath="..\..\browser\safe_browsing\chunk_range_unittest.cc" > </File> diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 514ee38..007f0fb 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -345,9 +345,9 @@ ProxyService* CreateNullProxyService() { } ProxyService* CreateFixedProxyService(const std::string& proxy) { - ProxyInfo proxy_info; - proxy_info.UseNamedProxy(proxy); - return ProxyService::Create(&proxy_info); + net::ProxyConfig proxy_config; + proxy_config.proxy_rules.ParseFromString(proxy); + return ProxyService::Create(&proxy_config); } diff --git a/net/net.gyp b/net/net.gyp index a87029c..8c11266 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -444,7 +444,6 @@ 'http/http_transaction_unittest.h', 'http/http_util_unittest.cc', 'http/http_vary_data_unittest.cc', - 'proxy/proxy_config_service_common_unittest.cc', 'proxy/proxy_config_service_common_unittest.h', 'proxy/proxy_config_service_linux_unittest.cc', 'proxy/proxy_config_service_win_unittest.cc', @@ -570,6 +569,8 @@ 'sources': [ 'disk_cache/disk_cache_test_util.cc', 'disk_cache/disk_cache_test_util.h', + 'proxy/proxy_config_service_common_unittest.cc', + 'proxy/proxy_config_service_common_unittest.h', ], }, { diff --git a/net/proxy/proxy_config.cc b/net/proxy/proxy_config.cc index a860c99..751049b 100644 --- a/net/proxy/proxy_config.cc +++ b/net/proxy/proxy_config.cc @@ -25,6 +25,10 @@ bool ProxyConfig::Equals(const ProxyConfig& other) const { proxy_bypass_local_names == other.proxy_bypass_local_names; } +bool ProxyConfig::MayRequirePACResolver() const { + return auto_detect || !pac_url.is_empty(); +} + void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) { // Reset. type = TYPE_NO_RULES; @@ -76,6 +80,71 @@ const ProxyServer* ProxyConfig::ProxyRules::MapSchemeToProxy( return NULL; // No mapping for this scheme. } +namespace { + +// Returns true if the given string represents an IP address. +bool IsIPAddress(const std::string& domain) { + // From GURL::HostIsIPAddress() + url_canon::RawCanonOutputT<char, 128> ignored_output; + url_parse::Component ignored_component; + url_parse::Component domain_comp(0, domain.size()); + return url_canon::CanonicalizeIPAddress(domain.c_str(), domain_comp, + &ignored_output, + &ignored_component); +} + +} // namespace + +void ProxyConfig::ParseNoProxyList(const std::string& no_proxy) { + proxy_bypass.clear(); + if (no_proxy.empty()) + return; + // Traditional semantics: + // A single "*" is specifically allowed and unproxies anything. + // "*" wildcards other than a single "*" entry are not universally + // supported. We will support them, as we get * wildcards for free + // (see MatchPattern() called from ProxyService::ShouldBypassProxyForURL()). + // no_proxy is a comma-separated list of <trailing_domain>[:<port>]. + // If no port is specified then any port matches. + // The historical definition has trailing_domain match using a simple + // string "endswith" test, so that the match need not correspond to a + // "." boundary. For example: "google.com" matches "igoogle.com" too. + // Seems like that could be confusing, but we'll obey tradition. + // IP CIDR patterns are supposed to be supported too. We intend + // to do this in proxy_service.cc, but it's currently a TODO. + // See: http://crbug.com/9835. + StringTokenizer no_proxy_list(no_proxy, ","); + while (no_proxy_list.GetNext()) { + std::string bypass_entry = no_proxy_list.token(); + TrimWhitespaceASCII(bypass_entry, TRIM_ALL, &bypass_entry); + if (bypass_entry.empty()) + continue; + if (bypass_entry.at(0) != '*') { + // Insert a wildcard * to obtain an endsWith match, unless the + // entry looks like it might be an IP or CIDR. + // First look for either a :<port> or CIDR mask length suffix. + std::string::const_iterator begin = bypass_entry.begin(); + std::string::const_iterator scan = bypass_entry.end() - 1; + while (scan > begin && IsAsciiDigit(*scan)) + --scan; + std::string potential_ip; + if (*scan == '/' || *scan == ':') + potential_ip = std::string(begin, scan - 1); + else + potential_ip = bypass_entry; + if (!IsIPAddress(potential_ip)) { + // Do insert a wildcard. + bypass_entry.insert(0, "*"); + } + // TODO(sdoyon): When CIDR matching is implemented in + // proxy_service.cc, consider making proxy_bypass more + // sophisticated to avoid parsing out the string on every + // request. + } + proxy_bypass.push_back(bypass_entry); + } +} + } // namespace net namespace { diff --git a/net/proxy/proxy_config.h b/net/proxy/proxy_config.h index 868fba9..b90e9b7 100644 --- a/net/proxy/proxy_config.h +++ b/net/proxy/proxy_config.h @@ -42,6 +42,8 @@ class ProxyConfig { TYPE_PROXY_PER_SCHEME, }; + // Note that the default of TYPE_NO_RULES results in direct connections + // being made when using this ProxyConfig. ProxyRules() : type(TYPE_NO_RULES) {} bool empty() const { @@ -91,6 +93,11 @@ class ProxyConfig { ProxyRules proxy_rules; + // Parses entries from a comma-separated list of hosts for which proxy + // configurations should be bypassed. Clears proxy_bypass and sets it to the + // resulting list. + void ParseNoProxyList(const std::string& no_proxy); + // Indicates a list of hosts that should bypass any proxy configuration. For // these hosts, a direct connection should always be used. // The form <host>:<port> is also supported, meaning that only @@ -103,6 +110,10 @@ class ProxyConfig { // Returns true if the given config is equivalent to this config. bool Equals(const ProxyConfig& other) const; + // Returns true if this config could possibly require the proxy service to + // use a PAC resolver. + bool MayRequirePACResolver() const; + private: int id_; }; diff --git a/net/proxy/proxy_config_service_fixed.h b/net/proxy/proxy_config_service_fixed.h index dfa9351..361c2b4 100644 --- a/net/proxy/proxy_config_service_fixed.h +++ b/net/proxy/proxy_config_service_fixed.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 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. @@ -12,17 +12,16 @@ namespace net { // Implementation of ProxyConfigService that returns a fixed result. class ProxyConfigServiceFixed : public ProxyConfigService { public: - explicit ProxyConfigServiceFixed(const ProxyInfo& pi) { pi_.Use(pi); } + explicit ProxyConfigServiceFixed(const ProxyConfig& pc) : pc_(pc) {} // ProxyConfigService methods: virtual int GetProxyConfig(ProxyConfig* config) { - config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config->proxy_rules.single_proxy = pi_.proxy_server(); + *config = pc_; return OK; } private: - ProxyInfo pi_; + ProxyConfig pc_; }; } // namespace net diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc index 3c94cdf..cce5835 100644 --- a/net/proxy/proxy_config_service_linux.cc +++ b/net/proxy/proxy_config_service_linux.cc @@ -114,71 +114,6 @@ bool ProxyConfigServiceLinux::GetProxyFromEnvVar( result_server); } -namespace { - -// Returns true if the given string represents an IP address. -bool IsIPAddress(const std::string& domain) { - // From GURL::HostIsIPAddress() - url_canon::RawCanonOutputT<char, 128> ignored_output; - url_parse::Component ignored_component; - url_parse::Component domain_comp(0, domain.size()); - return url_canon::CanonicalizeIPAddress(domain.c_str(), domain_comp, - &ignored_output, - &ignored_component); -} - -} // namespace - -void ProxyConfigServiceLinux::ParseNoProxyList(const std::string& no_proxy, - ProxyConfig* config) { - if (no_proxy.empty()) - return; - // Traditional semantics: - // A single "*" is specifically allowed and unproxies anything. - // "*" wildcards other than a single "*" entry are not universally - // supported. We will support them, as we get * wildcards for free - // (see MatchPattern() called from ProxyService::ShouldBypassProxyForURL()). - // no_proxy is a comma-separated list of <trailing_domain>[:<port>]. - // If no port is specified then any port matches. - // The historical definition has trailing_domain match using a simple - // string "endswith" test, so that the match need not correspond to a - // "." boundary. For example: "google.com" matches "igoogle.com" too. - // Seems like that could be confusing, but we'll obey tradition. - // IP CIDR patterns are supposed to be supported too. We intend - // to do this in proxy_service.cc, but it's currently a TODO. - // See: http://crbug.com/9835. - StringTokenizer no_proxy_list(no_proxy, ","); - while (no_proxy_list.GetNext()) { - std::string bypass_entry = no_proxy_list.token(); - TrimWhitespaceASCII(bypass_entry, TRIM_ALL, &bypass_entry); - if (bypass_entry.empty()) - continue; - if (bypass_entry.at(0) != '*') { - // Insert a wildcard * to obtain an endsWith match, unless the - // entry looks like it might be an IP or CIDR. - // First look for either a :<port> or CIDR mask length suffix. - std::string::const_iterator begin = bypass_entry.begin(); - std::string::const_iterator scan = bypass_entry.end() - 1; - while (scan > begin && IsAsciiDigit(*scan)) - --scan; - std::string potential_ip; - if (*scan == '/' || *scan == ':') - potential_ip = std::string(begin, scan - 1); - else - potential_ip = bypass_entry; - if (!IsIPAddress(potential_ip)) { - // Do insert a wildcard. - bypass_entry.insert(0, "*"); - } - // TODO(sdoyon): When CIDR matching is implemented in - // proxy_service.cc, consider making config->proxy_bypass more - // sophisticated to avoid parsing out the string on every - // request. - } - config->proxy_bypass.push_back(bypass_entry); - } -} - bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) { // Check for automatic configuration first, in // "auto_proxy". Possibly only the "environment_proxy" firefox @@ -242,7 +177,7 @@ bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) { // connections. return !no_proxy.empty(); } - ParseNoProxyList(no_proxy, config); + config->ParseNoProxyList(no_proxy); return true; } diff --git a/net/proxy/proxy_config_service_linux.h b/net/proxy/proxy_config_service_linux.h index 51436af..354bd29 100644 --- a/net/proxy/proxy_config_service_linux.h +++ b/net/proxy/proxy_config_service_linux.h @@ -81,9 +81,7 @@ class ProxyConfigServiceLinux : public ProxyConfigService { ProxyServer* result_server); // As above but with scheme set to HTTP, for convenience. bool GetProxyFromEnvVar(const char* variable, ProxyServer* result_server); - // Parses entries from the value of the no_proxy env var, and stuffs - // them into config->proxy_bypass. - void ParseNoProxyList(const std::string& no_proxy, ProxyConfig* config); + // Fills proxy config from environment variables. Returns true if // variables were found and the configuration is valid. bool GetConfigFromEnv(ProxyConfig* config); diff --git a/net/proxy/proxy_config_unittest.cc b/net/proxy/proxy_config_unittest.cc index 9e50e3b..a4192df 100644 --- a/net/proxy/proxy_config_unittest.cc +++ b/net/proxy/proxy_config_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service_common_unittest.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -197,3 +198,36 @@ TEST(ProxyConfigTest, ParseProxyRules) { config.proxy_rules.proxy_for_ftp); } } + +TEST(ProxyConfigTest, ParseProxyBypassList) { + struct bypass_test { + const char* proxy_bypass_input; + const char* flattened_output; + }; + + const struct { + const char* proxy_bypass_input; + const char* flattened_output; + } tests[] = { + { + "*", + "*\n" + }, + { + ".google.com, .foo.com:42", + "*.google.com\n*.foo.com:42\n" + }, + { + ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", + "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n" + } + }; + + net::ProxyConfig config; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + config.ParseNoProxyList(tests[i].proxy_bypass_input); + EXPECT_EQ(tests[i].flattened_output, + net::FlattenProxyBypass(config.proxy_bypass)); + } +} diff --git a/net/proxy/proxy_script_fetcher_unittest.cc b/net/proxy/proxy_script_fetcher_unittest.cc index fae8c2d..e1c4179 100644 --- a/net/proxy/proxy_script_fetcher_unittest.cc +++ b/net/proxy/proxy_script_fetcher_unittest.cc @@ -27,7 +27,7 @@ struct FetchResult { class RequestContext : public URLRequestContext { public: RequestContext() { - net::ProxyInfo no_proxy; + net::ProxyConfig no_proxy; proxy_service_ = net::ProxyService::Create(&no_proxy); http_transaction_factory_ = net::HttpNetworkLayer::CreateFactory( proxy_service_); diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index 0919f45..c2ae532 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -71,8 +71,8 @@ class NotifyFetchCompletionTask : public Task { // We rely on the fact that the origin thread (and its message loop) will not // be destroyed until after the PAC thread is destroyed. -class ProxyService::PacRequest : - public base::RefCountedThreadSafe<ProxyService::PacRequest> { +class ProxyService::PacRequest + : public base::RefCountedThreadSafe<ProxyService::PacRequest> { public: // |service| -- the ProxyService that owns this request. // |url| -- the url of the query. @@ -193,46 +193,58 @@ ProxyService::ProxyService(ProxyConfigService* config_service, } // static -ProxyService* ProxyService::Create(const ProxyInfo* pi) { - if (pi) { - // The ProxyResolver is set to NULL, since it should never be called - // (because the configuration will never require PAC). - return new ProxyService(new ProxyConfigServiceFixed(*pi), NULL); +ProxyService* ProxyService::Create(const ProxyConfig* pc) { + scoped_ptr<ProxyConfigService> proxy_config_service; + scoped_ptr<ProxyResolver> proxy_resolver; + if (pc) { + proxy_config_service.reset(new ProxyConfigServiceFixed(*pc)); } + #if defined(OS_WIN) - return new ProxyService(new ProxyConfigServiceWin(), - new ProxyResolverWinHttp()); + if (proxy_config_service == NULL) + proxy_config_service.reset(new ProxyConfigServiceWin()); + proxy_resolver.reset(new ProxyResolverWinHttp()); #elif defined(OS_MACOSX) - return new ProxyService(new ProxyConfigServiceMac(), - new ProxyResolverMac()); + if (proxy_config_service == NULL) + proxy_config_service.reset(new ProxyConfigServiceMac()); + proxy_resolver.reset(new ProxyResolverMac()); #elif defined(OS_LINUX) // On Linux we use the V8Resolver, no fallback implementation. - return CreateNull(); + // This means that if we got called with a ProxyConfig that could require a + // resolver, or if the caller is trying to create a regular ProxyService via + // this method instead of CreateUsingV8Resolver() we have to return a + // nulled-out ProxyService. + if (!pc || pc->MayRequirePACResolver()) { + LOG(WARNING) << "Attempting to create a ProxyService with a non-v8 " + << "resolver using an invalid ProxyConfig."; + return CreateNull(); + } #else return CreateNull(); #endif + + return new ProxyService(proxy_config_service.release(), + proxy_resolver.release()); } // static ProxyService* ProxyService::CreateUsingV8Resolver( - const ProxyInfo* pi, URLRequestContext* url_request_context) { - if (pi) { - // The ProxyResolver is set to NULL, since it should never be called - // (because the configuration will never require PAC). - return new ProxyService(new ProxyConfigServiceFixed(*pi), NULL); - } - + const ProxyConfig* pc, URLRequestContext* url_request_context) { // Choose the system configuration service appropriate for each platform. - ProxyConfigService* config_service; + ProxyConfigService* config_service = NULL; + if (pc) { + config_service = new ProxyConfigServiceFixed(*pc); + } else { #if defined(OS_WIN) - config_service = new ProxyConfigServiceWin(); + config_service = new ProxyConfigServiceWin(); #elif defined(OS_MACOSX) - config_service = new ProxyConfigServiceMac(); + config_service = new ProxyConfigServiceMac(); #elif defined(OS_LINUX) - config_service = new ProxyConfigServiceLinux(); + config_service = new ProxyConfigServiceLinux(); #else - return CreateNull(); + return CreateNull(); #endif + } // Create a ProxyService that uses V8 to evaluate PAC scripts. ProxyService* proxy_service = new ProxyService( diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h index 3ebee8d..f2fbbe7 100644 --- a/net/proxy/proxy_service.h +++ b/net/proxy/proxy_service.h @@ -86,14 +86,14 @@ class ProxyService { // |proxy_script_fetcher|. void SetProxyScriptFetcher(ProxyScriptFetcher* proxy_script_fetcher); - // Creates a proxy service using the specified settings. If |pi| is NULL then + // Creates a proxy service using the specified settings. If |pc| is NULL then // the system's default proxy settings will be used (on Windows this will // use IE's settings). - static ProxyService* Create(const ProxyInfo* pi); + static ProxyService* Create(const ProxyConfig* pc); - // Creates a proxy service using the specified settings. If |pi| is NULL then + // Creates a proxy service using the specified settings. If |pc| is NULL then // the system's default proxy settings will be used. This is basically the - // same as Create(const ProxyInfo*), however under the hood it uses a + // same as Create(const ProxyConfig*), however under the hood it uses a // different implementation (V8). |url_request_context| is the URL request // context that will be used if a PAC script needs to be fetched. // ########################################################################## @@ -102,7 +102,7 @@ class ProxyService { // # other V8's running in the process must use v8::Locker. // ########################################################################## static ProxyService* CreateUsingV8Resolver( - const ProxyInfo* pi, + const ProxyConfig* pc, URLRequestContext* url_request_context); // Creates a proxy service that always fails to fetch the proxy configuration, diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h index e661153..37e6439 100644 --- a/net/url_request/url_request_unittest.h +++ b/net/url_request/url_request_unittest.h @@ -48,9 +48,9 @@ class TestURLRequestContext : public URLRequestContext { } explicit TestURLRequestContext(const std::string& proxy) { - net::ProxyInfo proxy_info; - proxy_info.UseNamedProxy(proxy); - proxy_service_ = net::ProxyService::Create(&proxy_info); + net::ProxyConfig proxy_config; + proxy_config.proxy_rules.ParseFromString(proxy); + proxy_service_ = net::ProxyService::Create(&proxy_config); http_transaction_factory_ = net::HttpNetworkLayer::CreateFactory(proxy_service_); } @@ -548,7 +548,6 @@ class FTPTestServer : public BaseTestServer { return true; } - }; #endif // NET_URL_REQUEST_URL_REQUEST_UNITTEST_H_ diff --git a/webkit/tools/test_shell/test_shell_request_context.cc b/webkit/tools/test_shell/test_shell_request_context.cc index 2597f77..6a58104 100644 --- a/webkit/tools/test_shell/test_shell_request_context.cc +++ b/webkit/tools/test_shell/test_shell_request_context.cc @@ -29,9 +29,8 @@ void TestShellRequestContext::Init( accept_language_ = "en-us,en"; accept_charset_ = "iso-8859-1,*,utf-8"; - net::ProxyInfo proxy_info; - proxy_info.UseDirect(); - proxy_service_ = net::ProxyService::Create(no_proxy ? &proxy_info : NULL); + net::ProxyConfig proxy_config; + proxy_service_ = net::ProxyService::Create(no_proxy ? &proxy_config : NULL); net::HttpCache *cache; if (cache_path.empty()) { |