diff options
Diffstat (limited to 'net/proxy')
-rw-r--r-- | net/proxy/proxy_config.cc | 98 | ||||
-rw-r--r-- | net/proxy/proxy_config.h | 66 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_android.cc | 23 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_common_unittest.cc | 41 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_ios.cc | 5 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_linux.cc | 27 | ||||
-rw-r--r-- | net/proxy/proxy_config_service_mac.cc | 9 | ||||
-rw-r--r-- | net/proxy/proxy_config_unittest.cc | 138 | ||||
-rw-r--r-- | net/proxy/proxy_info.cc | 10 | ||||
-rw-r--r-- | net/proxy/proxy_info.h | 7 | ||||
-rw-r--r-- | net/proxy/proxy_list.cc | 11 | ||||
-rw-r--r-- | net/proxy/proxy_list.h | 6 |
12 files changed, 313 insertions, 128 deletions
diff --git a/net/proxy/proxy_config.cc b/net/proxy/proxy_config.cc index 022e732..91122dd 100644 --- a/net/proxy/proxy_config.cc +++ b/net/proxy/proxy_config.cc @@ -14,12 +14,23 @@ namespace net { namespace { -// If |proxy| is valid, sets it in |dict| under the key |name|. -void AddProxyToValue(const char* name, - const ProxyServer& proxy, - base::DictionaryValue* dict) { - if (proxy.is_valid()) - dict->SetString(name, proxy.ToURI()); +// If |proxies| is non-empty, sets it in |dict| under the key |name|. +void AddProxyListToValue(const char* name, + const ProxyList& proxies, + base::DictionaryValue* dict) { + if (!proxies.IsEmpty()) + dict->SetString(name, proxies.ToPacString()); +} + +// Split the |uri_list| on commas and add each entry to |proxy_list| in turn. +void AddProxyURIListToProxyList(std::string uri_list, + ProxyList* proxy_list, + ProxyServer::Scheme default_scheme) { + base::StringTokenizer proxy_uri_list(uri_list, ","); + while (proxy_uri_list.GetNext()) { + proxy_list->AddProxyServer( + ProxyServer::FromURI(proxy_uri_list.token(), default_scheme)); + } } } // namespace @@ -48,13 +59,13 @@ void ProxyConfig::ProxyRules::Apply(const GURL& url, ProxyInfo* result) const { switch (type) { case ProxyRules::TYPE_SINGLE_PROXY: { - result->UseProxyServer(single_proxy); + result->UseProxyList(single_proxies); return; } case ProxyRules::TYPE_PROXY_PER_SCHEME: { - const ProxyServer* entry = MapUrlSchemeToProxy(url.scheme()); + const ProxyList* entry = MapUrlSchemeToProxyList(url.scheme()); if (entry) { - result->UseProxyServer(*entry); + result->UseProxyList(*entry); } else { // We failed to find a matching proxy server for the current URL // scheme. Default to direct. @@ -73,11 +84,11 @@ void ProxyConfig::ProxyRules::Apply(const GURL& url, ProxyInfo* result) const { void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) { // Reset. type = TYPE_NO_RULES; - single_proxy = ProxyServer(); - proxy_for_http = ProxyServer(); - proxy_for_https = ProxyServer(); - proxy_for_ftp = ProxyServer(); - fallback_proxy = ProxyServer(); + single_proxies = ProxyList(); + proxies_for_http = ProxyList(); + proxies_for_https = ProxyList(); + proxies_for_ftp = ProxyList(); + fallback_proxies = ProxyList(); base::StringTokenizer proxy_server_list(proxy_rules, ";"); while (proxy_server_list.GetNext()) { @@ -93,8 +104,9 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) { if (!proxy_server_for_scheme.GetNext()) { if (type == TYPE_PROXY_PER_SCHEME) continue; // Unexpected. - single_proxy = ProxyServer::FromURI(url_scheme, - ProxyServer::SCHEME_HTTP); + AddProxyURIListToProxyList(url_scheme, + &single_proxies, + ProxyServer::SCHEME_HTTP); type = TYPE_SINGLE_PROXY; return; } @@ -104,7 +116,7 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) { // Add it to the per-scheme mappings (if supported scheme). type = TYPE_PROXY_PER_SCHEME; - ProxyServer* entry = MapUrlSchemeToProxyNoFallback(url_scheme); + ProxyList* entry = MapUrlSchemeToProxyListNoFallback(url_scheme); ProxyServer::Scheme default_scheme = ProxyServer::SCHEME_HTTP; // socks=XXX is inconsistent with the other formats, since "socks" @@ -112,49 +124,52 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) { // it to the SOCKS proxy server XXX". if (url_scheme == "socks") { DCHECK(!entry); - entry = &fallback_proxy; + entry = &fallback_proxies; + // Note that here 'socks' is understood to be SOCKS4, even though + // 'socks' maps to SOCKS5 in ProxyServer::GetSchemeFromURIInternal. default_scheme = ProxyServer::SCHEME_SOCKS4; } if (entry) { - *entry = ProxyServer::FromURI(proxy_server_for_scheme.token(), - default_scheme); + AddProxyURIListToProxyList(proxy_server_for_scheme.token(), + entry, + default_scheme); } } } } -const ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxy( +const ProxyList* ProxyConfig::ProxyRules::MapUrlSchemeToProxyList( const std::string& url_scheme) const { - const ProxyServer* proxy_server = - const_cast<ProxyRules*>(this)->MapUrlSchemeToProxyNoFallback(url_scheme); - if (proxy_server && proxy_server->is_valid()) - return proxy_server; - if (fallback_proxy.is_valid()) - return &fallback_proxy; + const ProxyList* proxy_server_list = const_cast<ProxyRules*>(this)-> + MapUrlSchemeToProxyListNoFallback(url_scheme); + if (proxy_server_list && !proxy_server_list->IsEmpty()) + return proxy_server_list; + if (!fallback_proxies.IsEmpty()) + return &fallback_proxies; return NULL; // No mapping for this scheme. Use direct. } bool ProxyConfig::ProxyRules::Equals(const ProxyRules& other) const { return type == other.type && - single_proxy == other.single_proxy && - proxy_for_http == other.proxy_for_http && - proxy_for_https == other.proxy_for_https && - proxy_for_ftp == other.proxy_for_ftp && - fallback_proxy == other.fallback_proxy && + single_proxies.Equals(other.single_proxies) && + proxies_for_http.Equals(other.proxies_for_http) && + proxies_for_https.Equals(other.proxies_for_https) && + proxies_for_ftp.Equals(other.proxies_for_ftp) && + fallback_proxies.Equals(other.fallback_proxies) && bypass_rules.Equals(other.bypass_rules) && reverse_bypass == other.reverse_bypass; } -ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxyNoFallback( +ProxyList* ProxyConfig::ProxyRules::MapUrlSchemeToProxyListNoFallback( const std::string& scheme) { DCHECK_EQ(TYPE_PROXY_PER_SCHEME, type); if (scheme == "http") - return &proxy_for_http; + return &proxies_for_http; if (scheme == "https") - return &proxy_for_https; + return &proxies_for_https; if (scheme == "ftp") - return &proxy_for_ftp; + return &proxies_for_ftp; return NULL; // No mapping for this scheme. } @@ -219,14 +234,15 @@ base::Value* ProxyConfig::ToValue() const { if (proxy_rules_.type != ProxyRules::TYPE_NO_RULES) { switch (proxy_rules_.type) { case ProxyRules::TYPE_SINGLE_PROXY: - AddProxyToValue("single_proxy", proxy_rules_.single_proxy, dict); + AddProxyListToValue("single_proxies", + proxy_rules_.single_proxies, dict); break; case ProxyRules::TYPE_PROXY_PER_SCHEME: { base::DictionaryValue* dict2 = new base::DictionaryValue(); - AddProxyToValue("http", proxy_rules_.proxy_for_http, dict2); - AddProxyToValue("https", proxy_rules_.proxy_for_https, dict2); - AddProxyToValue("ftp", proxy_rules_.proxy_for_ftp, dict2); - AddProxyToValue("fallback", proxy_rules_.fallback_proxy, dict2); + AddProxyListToValue("http", proxy_rules_.proxies_for_http, dict2); + AddProxyListToValue("https", proxy_rules_.proxies_for_https, dict2); + AddProxyListToValue("ftp", proxy_rules_.proxies_for_ftp, dict2); + AddProxyListToValue("fallback", proxy_rules_.fallback_proxies, dict2); dict->Set("proxy_per_scheme", dict2); break; } diff --git a/net/proxy/proxy_config.h b/net/proxy/proxy_config.h index 29619df..289aaee 100644 --- a/net/proxy/proxy_config.h +++ b/net/proxy/proxy_config.h @@ -11,6 +11,7 @@ #include "net/base/net_export.h" #include "net/proxy/proxy_bypass_rules.h" #include "net/proxy/proxy_config_source.h" +#include "net/proxy/proxy_list.h" #include "net/proxy/proxy_server.h" namespace base { @@ -36,6 +37,8 @@ class NET_EXPORT ProxyConfig { public: // ProxyRules describes the "manual" proxy settings. // TODO(eroman): Turn this into a class. + // TODO(marq): Update the enum names; "TYPE_SINGLE_PROXY" really means + // the same set of proxies are used for all requests. struct NET_EXPORT ProxyRules { enum Type { TYPE_NO_RULES, @@ -52,31 +55,63 @@ class NET_EXPORT ProxyConfig { return type == TYPE_NO_RULES; } - // Sets |result| with the proxy to use for |url| based on the current rules. + // Sets |result| with the proxies to use for |url| based on the current + // rules. void Apply(const GURL& url, ProxyInfo* result) const; // Parses the rules from a string, indicating which proxies to use. // // proxy-uri = [<proxy-scheme>"://"]<proxy-host>[":"<proxy-port>] // - // If the proxy to use depends on the scheme of the URL, can instead specify - // a semicolon separated list of: + // proxy-uri-list = <proxy-uri>[","<proxy-uri-list>] // - // <url-scheme>"="<proxy-uri> + // url-scheme = "http" | "https" | "ftp" | "socks" + // + // scheme-proxies = [<url-scheme>"="]<proxy-uri-list> + // + // proxy-rules = scheme-proxies[";"<scheme-proxies>] + // + // Thus, the proxy-rules string should be a semicolon-separated list of + // ordered proxies that apply to a particular URL scheme. Unless specified, + // the proxy scheme for proxy-uris is assumed to be http. + // + // Some special cases: + // * If the scheme is omitted from the first proxy list, that list applies + // to all URL schemes and subsequent lists are ignored. + // * If a scheme is omitted from any proxy list after a list where a scheme + // has been provided, the list without a scheme is ignored. + // * If the url-scheme is set to 'socks', that sets a fallback list that + // to all otherwise unspecified url-schemes, however the default proxy- + // scheme for proxy urls in the 'socks' list is understood to be + // socks4:// if unspecified. // // For example: // "http=foopy:80;ftp=foopy2" -- use HTTP proxy "foopy:80" for http:// // URLs, and HTTP proxy "foopy2:80" for // ftp:// URLs. // "foopy:80" -- use HTTP proxy "foopy:80" for all URLs. + // "foopy:80,bar,direct://" -- use HTTP proxy "foopy:80" for all URLs, + // failing over to "bar" if "foopy:80" is + // unavailable, and after that using no + // proxy. // "socks4://foopy" -- use SOCKS v4 proxy "foopy:1080" for all // URLs. + // "http=foop,socks5://bar.com -- use HTTP proxy "foopy" for http URLs, + // and fail over to the SOCKS5 proxy + // "bar.com" if "foop" is unavailable. + // "http=foopy,direct:// -- use HTTP proxy "foopy" for http URLs, + // and use no proxy if "foopy" is + // unavailable. + // "http=foopy;socks=foopy2 -- use HTTP proxy "foopy" for http URLs, + // and use socks4://foopy2 for all other + // URLs. void ParseFromString(const std::string& proxy_rules); - // Returns one of {&proxy_for_http, &proxy_for_https, &proxy_for_ftp, - // &fallback_proxy}, or NULL if there is no proxy to use. + // Returns one of {&proxies_for_http, &proxies_for_https, &proxies_for_ftp, + // &fallback_proxies}, or NULL if there is no proxy to use. // Should only call this if the type is TYPE_PROXY_PER_SCHEME. - const ProxyServer* MapUrlSchemeToProxy(const std::string& url_scheme) const; + const ProxyList* MapUrlSchemeToProxyList( + const std::string& url_scheme) const; // Returns true if |*this| describes the same configuration as |other|. bool Equals(const ProxyRules& other) const; @@ -90,21 +125,22 @@ class NET_EXPORT ProxyConfig { Type type; // Set if |type| is TYPE_SINGLE_PROXY. - ProxyServer single_proxy; + ProxyList single_proxies; // Set if |type| is TYPE_PROXY_PER_SCHEME. - ProxyServer proxy_for_http; - ProxyServer proxy_for_https; - ProxyServer proxy_for_ftp; + ProxyList proxies_for_http; + ProxyList proxies_for_https; + ProxyList proxies_for_ftp; - // Used when there isn't a more specific per-scheme proxy server. - ProxyServer fallback_proxy; + // Used when a fallback has been defined and the url to be proxied doesn't + // match any of the standard schemes. + ProxyList fallback_proxies; private: - // Returns one of {&proxy_for_http, &proxy_for_https, &proxy_for_ftp} + // Returns one of {&proxies_for_http, &proxies_for_https, &proxies_for_ftp} // or NULL if it is a scheme that we don't have a mapping // for. Should only call this if the type is TYPE_PROXY_PER_SCHEME. - ProxyServer* MapUrlSchemeToProxyNoFallback(const std::string& scheme); + ProxyList* MapUrlSchemeToProxyListNoFallback(const std::string& scheme); }; typedef int ID; diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc index 70c639e..a5d8ba2 100644 --- a/net/proxy/proxy_config_service_android.cc +++ b/net/proxy/proxy_config_service_android.cc @@ -124,21 +124,22 @@ bool GetProxyRules(const GetPropertyCallback& get_property, // On the opposite, Java spec suggests to use HTTPS port (443) by default (the // default value of https.proxyPort). rules->type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - rules->proxy_for_http = LookupProxy("http", get_property, - ProxyServer::SCHEME_HTTP); - rules->proxy_for_https = LookupProxy("https", get_property, - ProxyServer::SCHEME_HTTP); - rules->proxy_for_ftp = LookupProxy("ftp", get_property, - ProxyServer::SCHEME_HTTP); - rules->fallback_proxy = LookupSocksProxy(get_property); + rules->proxies_for_http.SetSingleProxyServer( + LookupProxy("http", get_property, ProxyServer::SCHEME_HTTP)); + rules->proxies_for_https.SetSingleProxyServer( + LookupProxy("https", get_property, ProxyServer::SCHEME_HTTP)); + rules->proxies_for_ftp.SetSingleProxyServer( + LookupProxy("ftp", get_property, ProxyServer::SCHEME_HTTP)); + rules->fallback_proxies.SetSingleProxyServer(LookupSocksProxy(get_property)); rules->bypass_rules.Clear(); AddBypassRules("ftp", get_property, &rules->bypass_rules); AddBypassRules("http", get_property, &rules->bypass_rules); AddBypassRules("https", get_property, &rules->bypass_rules); - return rules->proxy_for_http.is_valid() || - rules->proxy_for_https.is_valid() || - rules->proxy_for_ftp.is_valid() || - rules->fallback_proxy.is_valid(); + // We know a proxy was found if not all of the proxy lists are empty. + return !(rules->proxies_for_http.IsEmpty() && + rules->proxies_for_https.IsEmpty() && + rules->proxies_for_ftp.IsEmpty() && + rules->fallback_proxies.IsEmpty()); }; void GetLatestProxyConfigInternal(const GetPropertyCallback& get_property, diff --git a/net/proxy/proxy_config_service_common_unittest.cc b/net/proxy/proxy_config_service_common_unittest.cc index 429abc5..3835bb1 100644 --- a/net/proxy/proxy_config_service_common_unittest.cc +++ b/net/proxy/proxy_config_service_common_unittest.cc @@ -15,14 +15,37 @@ namespace net { namespace { -// Helper to verify that |expected_proxy| matches |actual_proxy|. If it does -// not, then |*did_fail| is set to true, and |*failure_details| is filled with -// a description of the failure. +// Helper to verify that |expected_proxy| matches the first proxy conatined in +// |actual_proxies|, and that |actual_proxies| contains exactly one proxy. If +// either condition is untrue, then |*did_fail| is set to true, and +// |*failure_details| is filled with a description of the failure. void MatchesProxyServerHelper(const char* failure_message, const char* expected_proxy, - const ProxyServer& actual_proxy, + const ProxyList& actual_proxies, ::testing::AssertionResult* failure_details, bool* did_fail) { + // If |expected_proxy| is empty, then we expect |actual_proxies| to be so as + // well. + if (strlen(expected_proxy) == 0) { + if (!actual_proxies.IsEmpty()) { + *did_fail = true; + *failure_details + << failure_message << ". Was expecting no proxies but got " + << actual_proxies.size() << "."; + } + return; + } + + // Otherwise we check that |actual_proxies| holds a single matching proxy. + if (actual_proxies.size() != 1) { + *did_fail = true; + *failure_details + << failure_message << ". Was expecting exactly one proxy but got " + << actual_proxies.size() << "."; + return; + } + + ProxyServer actual_proxy = actual_proxies.Get(); std::string actual_proxy_string; if (actual_proxy.is_valid()) actual_proxy_string = actual_proxy.ToURI(); @@ -81,13 +104,15 @@ ProxyRulesExpectation::ProxyRulesExpectation( } MatchesProxyServerHelper("Bad single_proxy", single_proxy, - rules.single_proxy, &failure_details, &failed); + rules.single_proxies, &failure_details, &failed); MatchesProxyServerHelper("Bad proxy_for_http", proxy_for_http, - rules.proxy_for_http, &failure_details, &failed); + rules.proxies_for_http, &failure_details, + &failed); MatchesProxyServerHelper("Bad proxy_for_https", proxy_for_https, - rules.proxy_for_https, &failure_details, &failed); + rules.proxies_for_https, &failure_details, + &failed); MatchesProxyServerHelper("Bad fallback_proxy", fallback_proxy, - rules.fallback_proxy, &failure_details, &failed); + rules.fallback_proxies, &failure_details, &failed); std::string actual_flattened_bypass = FlattenProxyBypass(rules.bypass_rules); if (std::string(flattened_bypass_rules) != actual_flattened_bypass) { diff --git a/net/proxy/proxy_config_service_ios.cc b/net/proxy/proxy_config_service_ios.cc index fdeb1bb..6a9d2d3 100644 --- a/net/proxy/proxy_config_service_ios.cc +++ b/net/proxy/proxy_config_service_ios.cc @@ -78,10 +78,11 @@ void GetCurrentProxyConfig(ProxyConfig* config) { if (proxy_server.is_valid()) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - config->proxy_rules().proxy_for_http = proxy_server; + config->proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server); // Desktop Safari applies the HTTP proxy to http:// URLs only, but // Mobile Safari applies the HTTP proxy to https:// URLs as well. - config->proxy_rules().proxy_for_https = proxy_server; + config->proxy_rules().proxies_for_https.SetSingleProxyServer( + proxy_server); } } diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc index 523a55e..b1dda52 100644 --- a/net/proxy/proxy_config_service_linux.cc +++ b/net/proxy/proxy_config_service_linux.cc @@ -137,11 +137,11 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) { ProxyServer proxy_server; if (GetProxyFromEnvVar("all_proxy", &proxy_server)) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config->proxy_rules().single_proxy = proxy_server; + config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_server); } else { bool have_http = GetProxyFromEnvVar("http_proxy", &proxy_server); if (have_http) - config->proxy_rules().proxy_for_http = proxy_server; + config->proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server); // It would be tempting to let http_proxy apply for all protocols // if https_proxy and ftp_proxy are not defined. Googling turns up // several documents that mention only http_proxy. But then the @@ -149,10 +149,11 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) { // like other apps do this. So we will refrain. bool have_https = GetProxyFromEnvVar("https_proxy", &proxy_server); if (have_https) - config->proxy_rules().proxy_for_https = proxy_server; + config->proxy_rules().proxies_for_https. + SetSingleProxyServer(proxy_server); bool have_ftp = GetProxyFromEnvVar("ftp_proxy", &proxy_server); if (have_ftp) - config->proxy_rules().proxy_for_ftp = proxy_server; + config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_server); if (have_http || have_https || have_ftp) { // mustn't change type unless some rules are actually set. config->proxy_rules().type = @@ -170,7 +171,7 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) { scheme = ProxyServer::SCHEME_SOCKS4; if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config->proxy_rules().single_proxy = proxy_server; + config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_server); } } // Look for the proxy bypass list. @@ -1445,21 +1446,23 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromSettings( if (proxy_for_http.is_valid()) { // Use the http proxy for all schemes. config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config->proxy_rules().single_proxy = proxy_for_http; + config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_for_http); } } else if (num_proxies_specified > 0) { if (socks_proxy.is_valid() && num_proxies_specified == 1) { // If the only proxy specified was for SOCKS, use it for all schemes. config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config->proxy_rules().single_proxy = socks_proxy; + config->proxy_rules().single_proxies.SetSingleProxyServer(socks_proxy); } else { - // Otherwise use the indicate proxies per-scheme. + // Otherwise use the indicated proxies per-scheme. config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - config->proxy_rules().proxy_for_http = proxy_for_http; - config->proxy_rules().proxy_for_https = proxy_for_https; - config->proxy_rules().proxy_for_ftp = proxy_for_ftp; - config->proxy_rules().fallback_proxy = socks_proxy; + config->proxy_rules().proxies_for_http. + SetSingleProxyServer(proxy_for_http); + config->proxy_rules().proxies_for_https. + SetSingleProxyServer(proxy_for_https); + config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_for_ftp); + config->proxy_rules().fallback_proxies.SetSingleProxyServer(socks_proxy); } } diff --git a/net/proxy/proxy_config_service_mac.cc b/net/proxy/proxy_config_service_mac.cc index b4099d8..6994ffd 100644 --- a/net/proxy/proxy_config_service_mac.cc +++ b/net/proxy/proxy_config_service_mac.cc @@ -80,7 +80,7 @@ void GetCurrentProxyConfig(ProxyConfig* config) { if (proxy_server.is_valid()) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - config->proxy_rules().proxy_for_ftp = proxy_server; + config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_server); } } if (GetBoolFromDictionary(config_dict.get(), @@ -94,7 +94,7 @@ void GetCurrentProxyConfig(ProxyConfig* config) { if (proxy_server.is_valid()) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - config->proxy_rules().proxy_for_http = proxy_server; + config->proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server); } } if (GetBoolFromDictionary(config_dict.get(), @@ -108,7 +108,8 @@ void GetCurrentProxyConfig(ProxyConfig* config) { if (proxy_server.is_valid()) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - config->proxy_rules().proxy_for_https = proxy_server; + config->proxy_rules().proxies_for_https. + SetSingleProxyServer(proxy_server); } } if (GetBoolFromDictionary(config_dict.get(), @@ -122,7 +123,7 @@ void GetCurrentProxyConfig(ProxyConfig* config) { if (proxy_server.is_valid()) { config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; - config->proxy_rules().fallback_proxy = proxy_server; + config->proxy_rules().fallback_proxies.SetSingleProxyServer(proxy_server); } } diff --git a/net/proxy/proxy_config_unittest.cc b/net/proxy/proxy_config_unittest.cc index 47ea689..4b041b3 100644 --- a/net/proxy/proxy_config_unittest.cc +++ b/net/proxy/proxy_config_unittest.cc @@ -11,11 +11,11 @@ namespace net { namespace { void ExpectProxyServerEquals(const char* expectation, - const ProxyServer& proxy_server) { + const ProxyList& proxy_servers) { if (expectation == NULL) { - EXPECT_FALSE(proxy_server.is_valid()); + EXPECT_TRUE(proxy_servers.IsEmpty()); } else { - EXPECT_EQ(expectation, proxy_server.ToURI()); + EXPECT_EQ(expectation, proxy_servers.ToPacString()); } } @@ -51,21 +51,21 @@ TEST(ProxyConfigTest, Equals) { // Test |ProxyConfig::proxy_rules|. config2.proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config2.proxy_rules().single_proxy = - ProxyServer::FromURI("myproxy:80", ProxyServer::SCHEME_HTTP); + config2.proxy_rules().single_proxies.SetSingleProxyServer( + ProxyServer::FromURI("myproxy:80", ProxyServer::SCHEME_HTTP)); EXPECT_FALSE(config1.Equals(config2)); EXPECT_FALSE(config2.Equals(config1)); config1.proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; - config1.proxy_rules().single_proxy = - ProxyServer::FromURI("myproxy:100", ProxyServer::SCHEME_HTTP); + config1.proxy_rules().single_proxies.SetSingleProxyServer( + ProxyServer::FromURI("myproxy:100", ProxyServer::SCHEME_HTTP)); EXPECT_FALSE(config1.Equals(config2)); EXPECT_FALSE(config2.Equals(config1)); - config1.proxy_rules().single_proxy = - ProxyServer::FromURI("myproxy", ProxyServer::SCHEME_HTTP); + config1.proxy_rules().single_proxies.SetSingleProxyServer( + ProxyServer::FromURI("myproxy", ProxyServer::SCHEME_HTTP)); EXPECT_TRUE(config1.Equals(config2)); EXPECT_TRUE(config2.Equals(config1)); @@ -100,6 +100,7 @@ TEST(ProxyConfigTest, ParseProxyRules) { const char* proxy_rules; ProxyConfig::ProxyRules::Type type; + // These will be PAC-stle strings, eg 'PROXY foo.com' const char* single_proxy; const char* proxy_for_http; const char* proxy_for_https; @@ -111,7 +112,19 @@ TEST(ProxyConfigTest, ParseProxyRules) { "myproxy:80", ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY, - "myproxy:80", + "PROXY myproxy:80", + NULL, + NULL, + NULL, + NULL, + }, + + // Multiple HTTP proxies for all schemes. + { + "myproxy:80,https://myotherproxy", + + ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY, + "PROXY myproxy:80;HTTPS myotherproxy:443", NULL, NULL, NULL, @@ -124,7 +137,7 @@ TEST(ProxyConfigTest, ParseProxyRules) { ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, NULL, - "myproxy:80", + "PROXY myproxy:80", NULL, NULL, NULL, @@ -137,8 +150,8 @@ TEST(ProxyConfigTest, ParseProxyRules) { ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, NULL, NULL, - "socks4://foopy:1080", - "ftp-proxy:80", + "SOCKS foopy:1080", + "PROXY ftp-proxy:80", NULL, }, @@ -149,7 +162,7 @@ TEST(ProxyConfigTest, ParseProxyRules) { "foopy ; ftp=ftp-proxy", ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY, - "foopy:80", + "PROXY foopy:80", NULL, NULL, NULL, @@ -166,19 +179,55 @@ TEST(ProxyConfigTest, ParseProxyRules) { NULL, NULL, NULL, - "ftp-proxy:80", + "PROXY ftp-proxy:80", NULL, }, - // Include duplicate entries -- last one wins. + // Include a list of entries for a single scheme. { - "ftp=ftp1 ; ftp=ftp2 ; ftp=ftp3", + "ftp=ftp1,ftp2,ftp3", ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, NULL, NULL, NULL, - "ftp3:80", + "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80", + NULL, + }, + + // Include multiple entries for the same scheme -- they accumulate. + { + "http=http1,http2; http=http3", + + ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, + NULL, + "PROXY http1:80;PROXY http2:80;PROXY http3:80", + NULL, + NULL, + NULL, + }, + + // Include lists of entries for multiple schemes. + { + "ftp=ftp1,ftp2,ftp3 ; http=http1,http2; ", + + ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, + NULL, + "PROXY http1:80;PROXY http2:80", + NULL, + "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80", + NULL, + }, + + // Include non-default proxy schemes. + { + "http=https://secure_proxy; ftp=socks4://socks_proxy; https=socks://foo", + + ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, + NULL, + "HTTPS secure_proxy:443", + "SOCKS5 foo:1080", + "SOCKS socks_proxy:1080", NULL, }, @@ -191,7 +240,7 @@ TEST(ProxyConfigTest, ParseProxyRules) { NULL, NULL, NULL, - "socks4://foopy:1080", + "SOCKS foopy:1080", }, // SOCKS proxy present along with other proxies too @@ -200,10 +249,10 @@ TEST(ProxyConfigTest, ParseProxyRules) { ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, NULL, - "httpproxy:80", - "httpsproxy:80", - "ftpproxy:80", - "socks4://foopy:1080", + "PROXY httpproxy:80", + "PROXY httpsproxy:80", + "PROXY ftpproxy:80", + "SOCKS foopy:1080", }, // SOCKS proxy (with modifier) present along with some proxies @@ -213,10 +262,10 @@ TEST(ProxyConfigTest, ParseProxyRules) { ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, NULL, - "httpproxy:80", - "httpsproxy:80", + "PROXY httpproxy:80", + "PROXY httpsproxy:80", NULL, - "socks5://foopy:1080", + "SOCKS5 foopy:1080", }, // Include unsupported schemes -- they are discarded. @@ -226,10 +275,35 @@ TEST(ProxyConfigTest, ParseProxyRules) { ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, NULL, NULL, - "myhttpsproxy:80", + "PROXY myhttpsproxy:80", + NULL, + NULL, + }, + + // direct:// as first option for a scheme. + { + "http=direct://,myhttpproxy; https=direct://", + + ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, + NULL, + "DIRECT;PROXY myhttpproxy:80", + "DIRECT", + NULL, + NULL, + }, + + // direct:// as a second option for a scheme. + { + "http=myhttpproxy,direct://", + + ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, + NULL, + "PROXY myhttpproxy:80;DIRECT", + NULL, NULL, NULL, }, + }; ProxyConfig config; @@ -239,15 +313,15 @@ TEST(ProxyConfigTest, ParseProxyRules) { EXPECT_EQ(tests[i].type, config.proxy_rules().type); ExpectProxyServerEquals(tests[i].single_proxy, - config.proxy_rules().single_proxy); + config.proxy_rules().single_proxies); ExpectProxyServerEquals(tests[i].proxy_for_http, - config.proxy_rules().proxy_for_http); + config.proxy_rules().proxies_for_http); ExpectProxyServerEquals(tests[i].proxy_for_https, - config.proxy_rules().proxy_for_https); + config.proxy_rules().proxies_for_https); ExpectProxyServerEquals(tests[i].proxy_for_ftp, - config.proxy_rules().proxy_for_ftp); + config.proxy_rules().proxies_for_ftp); ExpectProxyServerEquals(tests[i].fallback_proxy, - config.proxy_rules().fallback_proxy); + config.proxy_rules().fallback_proxies); } } diff --git a/net/proxy/proxy_info.cc b/net/proxy/proxy_info.cc index dd68820..b6fcc867 100644 --- a/net/proxy/proxy_info.cc +++ b/net/proxy/proxy_info.cc @@ -49,6 +49,16 @@ void ProxyInfo::UseProxyServer(const ProxyServer& proxy_server) { proxy_list_.SetSingleProxyServer(proxy_server); } +void ProxyInfo::UsePacString(const std::string& pac_string) { + Reset(); + proxy_list_.SetFromPacString(pac_string); +} + +void ProxyInfo::UseProxyList(const ProxyList& proxy_list) { + Reset(); + proxy_list_ = proxy_list; +} + std::string ProxyInfo::ToPacString() const { return proxy_list_.ToPacString(); } diff --git a/net/proxy/proxy_info.h b/net/proxy/proxy_info.h index cea21e2..877e404 100644 --- a/net/proxy/proxy_info.h +++ b/net/proxy/proxy_info.h @@ -44,9 +44,10 @@ class NET_EXPORT ProxyInfo { void UseProxyServer(const ProxyServer& proxy_server); // Parses from the given PAC result. - void UsePacString(const std::string& pac_string) { - proxy_list_.SetFromPacString(pac_string); - } + void UsePacString(const std::string& pac_string); + + // Use the proxies from the given list. + void UseProxyList(const ProxyList& proxy_list); // Returns true if this proxy info specifies a direct connection. bool is_direct() const { diff --git a/net/proxy/proxy_list.cc b/net/proxy/proxy_list.cc index 1b2ecc7..4a49501 100644 --- a/net/proxy/proxy_list.cc +++ b/net/proxy/proxy_list.cc @@ -35,6 +35,10 @@ void ProxyList::Set(const std::string& proxy_uri_list) { void ProxyList::SetSingleProxyServer(const ProxyServer& proxy_server) { proxies_.clear(); + AddProxyServer(proxy_server); +} + +void ProxyList::AddProxyServer(const ProxyServer& proxy_server) { if (proxy_server.is_valid()) proxies_.push_back(proxy_server); } @@ -110,6 +114,13 @@ size_t ProxyList::size() const { return proxies_.size(); } +// Returns true if |*this| lists the same proxies as |other|. +bool ProxyList::Equals(const ProxyList& other) const { + if (size() != other.size()) + return false; + return proxies_ == other.proxies_; +} + const ProxyServer& ProxyList::Get() const { DCHECK(!proxies_.empty()); return proxies_[0]; diff --git a/net/proxy/proxy_list.h b/net/proxy/proxy_list.h index 209dd67..70208a1 100644 --- a/net/proxy/proxy_list.h +++ b/net/proxy/proxy_list.h @@ -31,6 +31,9 @@ class NET_EXPORT_PRIVATE ProxyList { // Set the proxy list to a single entry, |proxy_server|. void SetSingleProxyServer(const ProxyServer& proxy_server); + // Append a single proxy server to the end of the proxy list. + void AddProxyServer(const ProxyServer& proxy_server); + // De-prioritizes the proxies that we have cached as not working, by moving // them to the end of the fallback list. void DeprioritizeBadProxies(const ProxyRetryInfoMap& proxy_retry_info); @@ -52,6 +55,9 @@ class NET_EXPORT_PRIVATE ProxyList { // Returns the number of proxy servers in this list. size_t size() const; + // Returns true if |*this| lists the same proxies as |other|. + bool Equals(const ProxyList& other) const; + // Returns the first proxy server in the list. It is only valid to call // this if !IsEmpty(). const ProxyServer& Get() const; |