1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/proxy/proxy_config.h" 6#include "net/proxy/proxy_config_service_common_unittest.h" 7#include "net/proxy/proxy_info.h" 8#include "testing/gtest/include/gtest/gtest.h" 9 10namespace net { 11namespace { 12 13void ExpectProxyServerEquals(const char* expectation, 14 const ProxyList& proxy_servers) { 15 if (expectation == NULL) { 16 EXPECT_TRUE(proxy_servers.IsEmpty()); 17 } else { 18 EXPECT_EQ(expectation, proxy_servers.ToPacString()); 19 } 20} 21 22TEST(ProxyConfigTest, Equals) { 23 // Test |ProxyConfig::auto_detect|. 24 25 ProxyConfig config1; 26 config1.set_auto_detect(true); 27 28 ProxyConfig config2; 29 config2.set_auto_detect(false); 30 31 EXPECT_FALSE(config1.Equals(config2)); 32 EXPECT_FALSE(config2.Equals(config1)); 33 34 config2.set_auto_detect(true); 35 36 EXPECT_TRUE(config1.Equals(config2)); 37 EXPECT_TRUE(config2.Equals(config1)); 38 39 // Test |ProxyConfig::pac_url|. 40 41 config2.set_pac_url(GURL("http://wpad/wpad.dat")); 42 43 EXPECT_FALSE(config1.Equals(config2)); 44 EXPECT_FALSE(config2.Equals(config1)); 45 46 config1.set_pac_url(GURL("http://wpad/wpad.dat")); 47 48 EXPECT_TRUE(config1.Equals(config2)); 49 EXPECT_TRUE(config2.Equals(config1)); 50 51 // Test |ProxyConfig::proxy_rules|. 52 53 config2.proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; 54 config2.proxy_rules().single_proxies.SetSingleProxyServer( 55 ProxyServer::FromURI("myproxy:80", ProxyServer::SCHEME_HTTP)); 56 57 EXPECT_FALSE(config1.Equals(config2)); 58 EXPECT_FALSE(config2.Equals(config1)); 59 60 config1.proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; 61 config1.proxy_rules().single_proxies.SetSingleProxyServer( 62 ProxyServer::FromURI("myproxy:100", ProxyServer::SCHEME_HTTP)); 63 64 EXPECT_FALSE(config1.Equals(config2)); 65 EXPECT_FALSE(config2.Equals(config1)); 66 67 config1.proxy_rules().single_proxies.SetSingleProxyServer( 68 ProxyServer::FromURI("myproxy", ProxyServer::SCHEME_HTTP)); 69 70 EXPECT_TRUE(config1.Equals(config2)); 71 EXPECT_TRUE(config2.Equals(config1)); 72 73 // Test |ProxyConfig::bypass_rules|. 74 75 config2.proxy_rules().bypass_rules.AddRuleFromString("*.google.com"); 76 77 EXPECT_FALSE(config1.Equals(config2)); 78 EXPECT_FALSE(config2.Equals(config1)); 79 80 config1.proxy_rules().bypass_rules.AddRuleFromString("*.google.com"); 81 82 EXPECT_TRUE(config1.Equals(config2)); 83 EXPECT_TRUE(config2.Equals(config1)); 84 85 // Test |ProxyConfig::proxy_rules.reverse_bypass|. 86 87 config2.proxy_rules().reverse_bypass = true; 88 89 EXPECT_FALSE(config1.Equals(config2)); 90 EXPECT_FALSE(config2.Equals(config1)); 91 92 config1.proxy_rules().reverse_bypass = true; 93 94 EXPECT_TRUE(config1.Equals(config2)); 95 EXPECT_TRUE(config2.Equals(config1)); 96} 97 98TEST(ProxyConfigTest, ParseProxyRules) { 99 const struct { 100 const char* proxy_rules; 101 102 ProxyConfig::ProxyRules::Type type; 103 // These will be PAC-stle strings, eg 'PROXY foo.com' 104 const char* single_proxy; 105 const char* proxy_for_http; 106 const char* proxy_for_https; 107 const char* proxy_for_ftp; 108 const char* fallback_proxy; 109 } tests[] = { 110 // One HTTP proxy for all schemes. 111 { 112 "myproxy:80", 113 114 ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY, 115 "PROXY myproxy:80", 116 NULL, 117 NULL, 118 NULL, 119 NULL, 120 }, 121 122 // Multiple HTTP proxies for all schemes. 123 { 124 "myproxy:80,https://myotherproxy", 125 126 ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY, 127 "PROXY myproxy:80;HTTPS myotherproxy:443", 128 NULL, 129 NULL, 130 NULL, 131 NULL, 132 }, 133 134 // Only specify a proxy server for "http://" urls. 135 { 136 "http=myproxy:80", 137 138 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 139 NULL, 140 "PROXY myproxy:80", 141 NULL, 142 NULL, 143 NULL, 144 }, 145 146 // Specify an HTTP proxy for "ftp://" and a SOCKS proxy for "https://" urls. 147 { 148 "ftp=ftp-proxy ; https=socks4://foopy", 149 150 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 151 NULL, 152 NULL, 153 "SOCKS foopy:1080", 154 "PROXY ftp-proxy:80", 155 NULL, 156 }, 157 158 // Give a scheme-specific proxy as well as a non-scheme specific. 159 // The first entry "foopy" takes precedance marking this list as 160 // TYPE_SINGLE_PROXY. 161 { 162 "foopy ; ftp=ftp-proxy", 163 164 ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY, 165 "PROXY foopy:80", 166 NULL, 167 NULL, 168 NULL, 169 NULL, 170 }, 171 172 // Give a scheme-specific proxy as well as a non-scheme specific. 173 // The first entry "ftp=ftp-proxy" takes precedance marking this list as 174 // TYPE_PROXY_PER_SCHEME. 175 { 176 "ftp=ftp-proxy ; foopy", 177 178 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 179 NULL, 180 NULL, 181 NULL, 182 "PROXY ftp-proxy:80", 183 NULL, 184 }, 185 186 // Include a list of entries for a single scheme. 187 { 188 "ftp=ftp1,ftp2,ftp3", 189 190 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 191 NULL, 192 NULL, 193 NULL, 194 "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80", 195 NULL, 196 }, 197 198 // Include multiple entries for the same scheme -- they accumulate. 199 { 200 "http=http1,http2; http=http3", 201 202 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 203 NULL, 204 "PROXY http1:80;PROXY http2:80;PROXY http3:80", 205 NULL, 206 NULL, 207 NULL, 208 }, 209 210 // Include lists of entries for multiple schemes. 211 { 212 "ftp=ftp1,ftp2,ftp3 ; http=http1,http2; ", 213 214 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 215 NULL, 216 "PROXY http1:80;PROXY http2:80", 217 NULL, 218 "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80", 219 NULL, 220 }, 221 222 // Include non-default proxy schemes. 223 { 224 "http=https://secure_proxy; ftp=socks4://socks_proxy; https=socks://foo", 225 226 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 227 NULL, 228 "HTTPS secure_proxy:443", 229 "SOCKS5 foo:1080", 230 "SOCKS socks_proxy:1080", 231 NULL, 232 }, 233 234 // Only SOCKS proxy present, others being blank. 235 { 236 "socks=foopy", 237 238 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 239 NULL, 240 NULL, 241 NULL, 242 NULL, 243 "SOCKS foopy:1080", 244 }, 245 246 // SOCKS proxy present along with other proxies too 247 { 248 "http=httpproxy ; https=httpsproxy ; ftp=ftpproxy ; socks=foopy ", 249 250 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 251 NULL, 252 "PROXY httpproxy:80", 253 "PROXY httpsproxy:80", 254 "PROXY ftpproxy:80", 255 "SOCKS foopy:1080", 256 }, 257 258 // SOCKS proxy (with modifier) present along with some proxies 259 // (FTP being blank) 260 { 261 "http=httpproxy ; https=httpsproxy ; socks=socks5://foopy ", 262 263 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 264 NULL, 265 "PROXY httpproxy:80", 266 "PROXY httpsproxy:80", 267 NULL, 268 "SOCKS5 foopy:1080", 269 }, 270 271 // Include unsupported schemes -- they are discarded. 272 { 273 "crazy=foopy ; foo=bar ; https=myhttpsproxy", 274 275 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 276 NULL, 277 NULL, 278 "PROXY myhttpsproxy:80", 279 NULL, 280 NULL, 281 }, 282 283 // direct:// as first option for a scheme. 284 { 285 "http=direct://,myhttpproxy; https=direct://", 286 287 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 288 NULL, 289 "DIRECT;PROXY myhttpproxy:80", 290 "DIRECT", 291 NULL, 292 NULL, 293 }, 294 295 // direct:// as a second option for a scheme. 296 { 297 "http=myhttpproxy,direct://", 298 299 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME, 300 NULL, 301 "PROXY myhttpproxy:80;DIRECT", 302 NULL, 303 NULL, 304 NULL, 305 }, 306 307 }; 308 309 ProxyConfig config; 310 311 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 312 config.proxy_rules().ParseFromString(tests[i].proxy_rules); 313 314 EXPECT_EQ(tests[i].type, config.proxy_rules().type); 315 ExpectProxyServerEquals(tests[i].single_proxy, 316 config.proxy_rules().single_proxies); 317 ExpectProxyServerEquals(tests[i].proxy_for_http, 318 config.proxy_rules().proxies_for_http); 319 ExpectProxyServerEquals(tests[i].proxy_for_https, 320 config.proxy_rules().proxies_for_https); 321 ExpectProxyServerEquals(tests[i].proxy_for_ftp, 322 config.proxy_rules().proxies_for_ftp); 323 ExpectProxyServerEquals(tests[i].fallback_proxy, 324 config.proxy_rules().fallback_proxies); 325 } 326} 327 328TEST(ProxyConfigTest, ProxyRulesSetBypassFlag) { 329 // Test whether the did_bypass_proxy() flag is set in proxy info correctly. 330 ProxyConfig::ProxyRules rules; 331 ProxyInfo result; 332 333 rules.ParseFromString("http=httpproxy:80"); 334 rules.bypass_rules.AddRuleFromString(".com"); 335 336 rules.Apply(GURL("http://example.com"), &result); 337 EXPECT_TRUE(result.is_direct_only()); 338 EXPECT_TRUE(result.did_bypass_proxy()); 339 340 rules.Apply(GURL("http://example.org"), &result); 341 EXPECT_FALSE(result.is_direct()); 342 EXPECT_FALSE(result.did_bypass_proxy()); 343 344 // Try with reversed bypass rules. 345 rules.reverse_bypass = true; 346 347 rules.Apply(GURL("http://example.org"), &result); 348 EXPECT_TRUE(result.is_direct_only()); 349 EXPECT_TRUE(result.did_bypass_proxy()); 350 351 rules.Apply(GURL("http://example.com"), &result); 352 EXPECT_FALSE(result.is_direct()); 353 EXPECT_FALSE(result.did_bypass_proxy()); 354} 355 356static const char kWsUrl[] = "ws://example.com/echo"; 357static const char kWssUrl[] = "wss://example.com/echo"; 358 359class ProxyConfigWebSocketTest : public ::testing::Test { 360 protected: 361 void ParseFromString(const std::string& rules) { 362 rules_.ParseFromString(rules); 363 } 364 void Apply(const GURL& gurl) { rules_.Apply(gurl, &info_); } 365 std::string ToPacString() const { return info_.ToPacString(); } 366 367 static GURL WsUrl() { return GURL(kWsUrl); } 368 static GURL WssUrl() { return GURL(kWssUrl); } 369 370 ProxyConfig::ProxyRules rules_; 371 ProxyInfo info_; 372}; 373 374// If a single proxy is set for all protocols, WebSocket uses it. 375TEST_F(ProxyConfigWebSocketTest, UsesProxy) { 376 ParseFromString("proxy:3128"); 377 Apply(WsUrl()); 378 EXPECT_EQ("PROXY proxy:3128", ToPacString()); 379} 380 381// See RFC6455 Section 4.1. item 3, "_Proxy Usage_". 382TEST_F(ProxyConfigWebSocketTest, PrefersSocks) { 383 ParseFromString( 384 "http=proxy:3128 ; https=sslproxy:3128 ; socks=socksproxy:1080"); 385 Apply(WsUrl()); 386 EXPECT_EQ("SOCKS socksproxy:1080", ToPacString()); 387} 388 389TEST_F(ProxyConfigWebSocketTest, PrefersHttpsToHttp) { 390 ParseFromString("http=proxy:3128 ; https=sslproxy:3128"); 391 Apply(WssUrl()); 392 EXPECT_EQ("PROXY sslproxy:3128", ToPacString()); 393} 394 395TEST_F(ProxyConfigWebSocketTest, PrefersHttpsEvenForWs) { 396 ParseFromString("http=proxy:3128 ; https=sslproxy:3128"); 397 Apply(WsUrl()); 398 EXPECT_EQ("PROXY sslproxy:3128", ToPacString()); 399} 400 401TEST_F(ProxyConfigWebSocketTest, PrefersHttpToDirect) { 402 ParseFromString("http=proxy:3128"); 403 Apply(WssUrl()); 404 EXPECT_EQ("PROXY proxy:3128", ToPacString()); 405} 406 407TEST_F(ProxyConfigWebSocketTest, IgnoresFtpProxy) { 408 ParseFromString("ftp=ftpproxy:3128"); 409 Apply(WssUrl()); 410 EXPECT_EQ("DIRECT", ToPacString()); 411} 412 413TEST_F(ProxyConfigWebSocketTest, ObeysBypassRules) { 414 ParseFromString("http=proxy:3128 ; https=sslproxy:3128"); 415 rules_.bypass_rules.AddRuleFromString(".chromium.org"); 416 Apply(GURL("wss://codereview.chromium.org/feed")); 417 EXPECT_EQ("DIRECT", ToPacString()); 418} 419 420TEST_F(ProxyConfigWebSocketTest, ObeysLocalBypass) { 421 ParseFromString("http=proxy:3128 ; https=sslproxy:3128"); 422 rules_.bypass_rules.AddRuleFromString("<local>"); 423 Apply(GURL("ws://localhost/feed")); 424 EXPECT_EQ("DIRECT", ToPacString()); 425} 426 427} // namespace 428} // namespace net 429