init_proxy_resolver_unittest.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2009 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 <vector> 6 7#include "base/string_util.h" 8#include "base/utf_string_conversions.h" 9#include "net/base/net_errors.h" 10#include "net/base/net_log.h" 11#include "net/base/net_log_unittest.h" 12#include "net/base/test_completion_callback.h" 13#include "net/proxy/init_proxy_resolver.h" 14#include "net/proxy/proxy_config.h" 15#include "net/proxy/proxy_resolver.h" 16#include "net/proxy/proxy_script_fetcher.h" 17#include "testing/gtest/include/gtest/gtest.h" 18 19namespace net { 20namespace { 21 22enum Error { 23 kFailedDownloading = -100, 24 kFailedParsing = -200, 25}; 26 27class Rules { 28 public: 29 struct Rule { 30 Rule(const GURL& url, 31 int fetch_error, 32 int set_pac_error) 33 : url(url), 34 fetch_error(fetch_error), 35 set_pac_error(set_pac_error) { 36 } 37 38 string16 text() const { 39 if (set_pac_error == OK) 40 return UTF8ToUTF16(url.spec() + "!valid-script"); 41 if (fetch_error == OK) 42 return UTF8ToUTF16(url.spec() + "!invalid-script"); 43 return string16(); 44 } 45 46 GURL url; 47 int fetch_error; 48 int set_pac_error; 49 }; 50 51 Rule AddSuccessRule(const char* url) { 52 Rule rule(GURL(url), OK /*fetch_error*/, OK /*set_pac_error*/); 53 rules_.push_back(rule); 54 return rule; 55 } 56 57 void AddFailDownloadRule(const char* url) { 58 rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/, 59 ERR_UNEXPECTED /*set_pac_error*/)); 60 } 61 62 void AddFailParsingRule(const char* url) { 63 rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, 64 kFailedParsing /*set_pac_error*/)); 65 } 66 67 const Rule& GetRuleByUrl(const GURL& url) const { 68 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); 69 ++it) { 70 if (it->url == url) 71 return *it; 72 } 73 LOG(FATAL) << "Rule not found for " << url; 74 return rules_[0]; 75 } 76 77 const Rule& GetRuleByText(const string16& text) const { 78 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); 79 ++it) { 80 if (it->text() == text) 81 return *it; 82 } 83 LOG(FATAL) << "Rule not found for " << text; 84 return rules_[0]; 85 } 86 87 private: 88 typedef std::vector<Rule> RuleList; 89 RuleList rules_; 90}; 91 92class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher { 93 public: 94 explicit RuleBasedProxyScriptFetcher(const Rules* rules) : rules_(rules) {} 95 96 // ProxyScriptFetcher implementation. 97 virtual int Fetch(const GURL& url, 98 string16* text, 99 CompletionCallback* callback) { 100 const Rules::Rule& rule = rules_->GetRuleByUrl(url); 101 int rv = rule.fetch_error; 102 EXPECT_NE(ERR_UNEXPECTED, rv); 103 if (rv == OK) 104 *text = rule.text(); 105 return rv; 106 } 107 108 virtual void Cancel() {} 109 110 private: 111 const Rules* rules_; 112}; 113 114class RuleBasedProxyResolver : public ProxyResolver { 115 public: 116 RuleBasedProxyResolver(const Rules* rules, bool expects_pac_bytes) 117 : ProxyResolver(expects_pac_bytes), rules_(rules) {} 118 119 // ProxyResolver implementation: 120 virtual int GetProxyForURL(const GURL& /*url*/, 121 ProxyInfo* /*results*/, 122 CompletionCallback* /*callback*/, 123 RequestHandle* /*request_handle*/, 124 const BoundNetLog& /*net_log*/) { 125 NOTREACHED(); 126 return ERR_UNEXPECTED; 127 } 128 129 virtual void CancelRequest(RequestHandle request_handle) { 130 NOTREACHED(); 131 } 132 133 virtual int SetPacScript( 134 const scoped_refptr<ProxyResolverScriptData>& script_data, 135 CompletionCallback* callback) { 136 137 const GURL url = 138 script_data->type() == ProxyResolverScriptData::TYPE_SCRIPT_URL ? 139 script_data->url() : GURL(); 140 141 const Rules::Rule& rule = expects_pac_bytes() ? 142 rules_->GetRuleByText(script_data->utf16()) : 143 rules_->GetRuleByUrl(url); 144 145 int rv = rule.set_pac_error; 146 EXPECT_NE(ERR_UNEXPECTED, rv); 147 148 if (expects_pac_bytes()) { 149 EXPECT_EQ(rule.text(), script_data->utf16()); 150 } else { 151 EXPECT_EQ(rule.url, url); 152 } 153 154 if (rv == OK) 155 script_data_ = script_data; 156 return rv; 157 } 158 159 const ProxyResolverScriptData* script_data() const { return script_data_; } 160 161 private: 162 const Rules* rules_; 163 scoped_refptr<ProxyResolverScriptData> script_data_; 164}; 165 166// Succeed using custom PAC script. 167TEST(InitProxyResolverTest, CustomPacSucceeds) { 168 Rules rules; 169 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 170 RuleBasedProxyScriptFetcher fetcher(&rules); 171 172 ProxyConfig config; 173 config.set_pac_url(GURL("http://custom/proxy.pac")); 174 175 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 176 177 TestCompletionCallback callback; 178 CapturingNetLog log(CapturingNetLog::kUnbounded); 179 InitProxyResolver init(&resolver, &fetcher, &log); 180 EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback)); 181 EXPECT_EQ(rule.text(), resolver.script_data()->utf16()); 182 183 // Check the NetLog was filled correctly. 184 EXPECT_EQ(6u, log.entries().size()); 185 EXPECT_TRUE(LogContainsBeginEvent( 186 log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER)); 187 EXPECT_TRUE(LogContainsBeginEvent( 188 log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 189 EXPECT_TRUE(LogContainsEndEvent( 190 log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 191 EXPECT_TRUE(LogContainsBeginEvent( 192 log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 193 EXPECT_TRUE(LogContainsEndEvent( 194 log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 195 EXPECT_TRUE(LogContainsEndEvent( 196 log.entries(), 5, NetLog::TYPE_INIT_PROXY_RESOLVER)); 197} 198 199// Fail downloading the custom PAC script. 200TEST(InitProxyResolverTest, CustomPacFails1) { 201 Rules rules; 202 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 203 RuleBasedProxyScriptFetcher fetcher(&rules); 204 205 ProxyConfig config; 206 config.set_pac_url(GURL("http://custom/proxy.pac")); 207 208 rules.AddFailDownloadRule("http://custom/proxy.pac"); 209 210 TestCompletionCallback callback; 211 CapturingNetLog log(CapturingNetLog::kUnbounded); 212 InitProxyResolver init(&resolver, &fetcher, &log); 213 EXPECT_EQ(kFailedDownloading, 214 init.Init(config, base::TimeDelta(), NULL, &callback)); 215 EXPECT_EQ(NULL, resolver.script_data()); 216 217 // Check the NetLog was filled correctly. 218 EXPECT_EQ(4u, log.entries().size()); 219 EXPECT_TRUE(LogContainsBeginEvent( 220 log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER)); 221 EXPECT_TRUE(LogContainsBeginEvent( 222 log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 223 EXPECT_TRUE(LogContainsEndEvent( 224 log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 225 EXPECT_TRUE(LogContainsEndEvent( 226 log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER)); 227} 228 229// Fail parsing the custom PAC script. 230TEST(InitProxyResolverTest, CustomPacFails2) { 231 Rules rules; 232 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 233 RuleBasedProxyScriptFetcher fetcher(&rules); 234 235 ProxyConfig config; 236 config.set_pac_url(GURL("http://custom/proxy.pac")); 237 238 rules.AddFailParsingRule("http://custom/proxy.pac"); 239 240 TestCompletionCallback callback; 241 InitProxyResolver init(&resolver, &fetcher, NULL); 242 EXPECT_EQ(kFailedParsing, 243 init.Init(config, base::TimeDelta(), NULL, &callback)); 244 EXPECT_EQ(NULL, resolver.script_data()); 245} 246 247// Fail downloading the custom PAC script, because the fetcher was NULL. 248TEST(InitProxyResolverTest, HasNullProxyScriptFetcher) { 249 Rules rules; 250 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 251 252 ProxyConfig config; 253 config.set_pac_url(GURL("http://custom/proxy.pac")); 254 255 TestCompletionCallback callback; 256 InitProxyResolver init(&resolver, NULL, NULL); 257 EXPECT_EQ(ERR_UNEXPECTED, 258 init.Init(config, base::TimeDelta(), NULL, &callback)); 259 EXPECT_EQ(NULL, resolver.script_data()); 260} 261 262// Succeeds in choosing autodetect (wpad). 263TEST(InitProxyResolverTest, AutodetectSuccess) { 264 Rules rules; 265 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 266 RuleBasedProxyScriptFetcher fetcher(&rules); 267 268 ProxyConfig config; 269 config.set_auto_detect(true); 270 271 Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat"); 272 273 TestCompletionCallback callback; 274 InitProxyResolver init(&resolver, &fetcher, NULL); 275 EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback)); 276 EXPECT_EQ(rule.text(), resolver.script_data()->utf16()); 277} 278 279// Fails at WPAD (downloading), but succeeds in choosing the custom PAC. 280TEST(InitProxyResolverTest, AutodetectFailCustomSuccess1) { 281 Rules rules; 282 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 283 RuleBasedProxyScriptFetcher fetcher(&rules); 284 285 ProxyConfig config; 286 config.set_auto_detect(true); 287 config.set_pac_url(GURL("http://custom/proxy.pac")); 288 289 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 290 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 291 292 TestCompletionCallback callback; 293 InitProxyResolver init(&resolver, &fetcher, NULL); 294 EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback)); 295 EXPECT_EQ(rule.text(), resolver.script_data()->utf16()); 296} 297 298// Fails at WPAD (parsing), but succeeds in choosing the custom PAC. 299TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2) { 300 Rules rules; 301 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 302 RuleBasedProxyScriptFetcher fetcher(&rules); 303 304 ProxyConfig config; 305 config.set_auto_detect(true); 306 config.set_pac_url(GURL("http://custom/proxy.pac")); 307 config.proxy_rules().ParseFromString("unused-manual-proxy:99"); 308 309 rules.AddFailParsingRule("http://wpad/wpad.dat"); 310 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 311 312 TestCompletionCallback callback; 313 CapturingNetLog log(CapturingNetLog::kUnbounded); 314 315 ProxyConfig effective_config; 316 InitProxyResolver init(&resolver, &fetcher, &log); 317 EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), 318 &effective_config, &callback)); 319 EXPECT_EQ(rule.text(), resolver.script_data()->utf16()); 320 321 // Verify that the effective configuration no longer contains auto detect or 322 // any of the manual settings. 323 EXPECT_TRUE(effective_config.Equals( 324 ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac")))); 325 326 // Check the NetLog was filled correctly. 327 // (Note that the Fetch and Set states are repeated since both WPAD and custom 328 // PAC scripts are tried). 329 EXPECT_EQ(11u, log.entries().size()); 330 EXPECT_TRUE(LogContainsBeginEvent( 331 log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER)); 332 EXPECT_TRUE(LogContainsBeginEvent( 333 log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 334 EXPECT_TRUE(LogContainsEndEvent( 335 log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 336 EXPECT_TRUE(LogContainsBeginEvent( 337 log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 338 EXPECT_TRUE(LogContainsEndEvent( 339 log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 340 EXPECT_TRUE(LogContainsEvent( 341 log.entries(), 5, 342 NetLog::TYPE_INIT_PROXY_RESOLVER_FALLING_BACK_TO_NEXT_PAC_URL, 343 NetLog::PHASE_NONE)); 344 EXPECT_TRUE(LogContainsBeginEvent( 345 log.entries(), 6, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 346 EXPECT_TRUE(LogContainsEndEvent( 347 log.entries(), 7, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 348 EXPECT_TRUE(LogContainsBeginEvent( 349 log.entries(), 8, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 350 EXPECT_TRUE(LogContainsEndEvent( 351 log.entries(), 9, NetLog::TYPE_INIT_PROXY_RESOLVER_SET_PAC_SCRIPT)); 352 EXPECT_TRUE(LogContainsEndEvent( 353 log.entries(), 10, NetLog::TYPE_INIT_PROXY_RESOLVER)); 354} 355 356// Fails at WPAD (downloading), and fails at custom PAC (downloading). 357TEST(InitProxyResolverTest, AutodetectFailCustomFails1) { 358 Rules rules; 359 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 360 RuleBasedProxyScriptFetcher fetcher(&rules); 361 362 ProxyConfig config; 363 config.set_auto_detect(true); 364 config.set_pac_url(GURL("http://custom/proxy.pac")); 365 366 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 367 rules.AddFailDownloadRule("http://custom/proxy.pac"); 368 369 TestCompletionCallback callback; 370 InitProxyResolver init(&resolver, &fetcher, NULL); 371 EXPECT_EQ(kFailedDownloading, 372 init.Init(config, base::TimeDelta(), NULL, &callback)); 373 EXPECT_EQ(NULL, resolver.script_data()); 374} 375 376// Fails at WPAD (downloading), and fails at custom PAC (parsing). 377TEST(InitProxyResolverTest, AutodetectFailCustomFails2) { 378 Rules rules; 379 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 380 RuleBasedProxyScriptFetcher fetcher(&rules); 381 382 ProxyConfig config; 383 config.set_auto_detect(true); 384 config.set_pac_url(GURL("http://custom/proxy.pac")); 385 386 rules.AddFailDownloadRule("http://wpad/wpad.dat"); 387 rules.AddFailParsingRule("http://custom/proxy.pac"); 388 389 TestCompletionCallback callback; 390 InitProxyResolver init(&resolver, &fetcher, NULL); 391 EXPECT_EQ(kFailedParsing, 392 init.Init(config, base::TimeDelta(), NULL, &callback)); 393 EXPECT_EQ(NULL, resolver.script_data()); 394} 395 396// Fails at WPAD (parsing), but succeeds in choosing the custom PAC. 397// This is the same as AutodetectFailCustomSuccess2, but using a ProxyResolver 398// that doesn't |expects_pac_bytes|. 399TEST(InitProxyResolverTest, AutodetectFailCustomSuccess2_NoFetch) { 400 Rules rules; 401 RuleBasedProxyResolver resolver(&rules, false /*expects_pac_bytes*/); 402 RuleBasedProxyScriptFetcher fetcher(&rules); 403 404 ProxyConfig config; 405 config.set_auto_detect(true); 406 config.set_pac_url(GURL("http://custom/proxy.pac")); 407 408 rules.AddFailParsingRule(""); // Autodetect. 409 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); 410 411 TestCompletionCallback callback; 412 InitProxyResolver init(&resolver, &fetcher, NULL); 413 EXPECT_EQ(OK, init.Init(config, base::TimeDelta(), NULL, &callback)); 414 EXPECT_EQ(rule.url, resolver.script_data()->url()); 415} 416 417// This is a copy-paste of CustomPacFails1, with the exception that we give it 418// a 1 millisecond delay. This means it will now complete asynchronously. 419// Moreover, we test the NetLog to make sure it logged the pause. 420TEST(InitProxyResolverTest, CustomPacFails1_WithPositiveDelay) { 421 Rules rules; 422 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 423 RuleBasedProxyScriptFetcher fetcher(&rules); 424 425 ProxyConfig config; 426 config.set_pac_url(GURL("http://custom/proxy.pac")); 427 428 rules.AddFailDownloadRule("http://custom/proxy.pac"); 429 430 TestCompletionCallback callback; 431 CapturingNetLog log(CapturingNetLog::kUnbounded); 432 InitProxyResolver init(&resolver, &fetcher, &log); 433 EXPECT_EQ(ERR_IO_PENDING, 434 init.Init(config, base::TimeDelta::FromMilliseconds(1), 435 NULL, &callback)); 436 437 EXPECT_EQ(kFailedDownloading, callback.WaitForResult()); 438 EXPECT_EQ(NULL, resolver.script_data()); 439 440 // Check the NetLog was filled correctly. 441 EXPECT_EQ(6u, log.entries().size()); 442 EXPECT_TRUE(LogContainsBeginEvent( 443 log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER)); 444 EXPECT_TRUE(LogContainsBeginEvent( 445 log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT)); 446 EXPECT_TRUE(LogContainsEndEvent( 447 log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_WAIT)); 448 EXPECT_TRUE(LogContainsBeginEvent( 449 log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 450 EXPECT_TRUE(LogContainsEndEvent( 451 log.entries(), 4, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 452 EXPECT_TRUE(LogContainsEndEvent( 453 log.entries(), 5, NetLog::TYPE_INIT_PROXY_RESOLVER)); 454} 455 456// This is a copy-paste of CustomPacFails1, with the exception that we give it 457// a -5 second delay instead of a 0 ms delay. This change should have no effect 458// so the rest of the test is unchanged. 459TEST(InitProxyResolverTest, CustomPacFails1_WithNegativeDelay) { 460 Rules rules; 461 RuleBasedProxyResolver resolver(&rules, true /*expects_pac_bytes*/); 462 RuleBasedProxyScriptFetcher fetcher(&rules); 463 464 ProxyConfig config; 465 config.set_pac_url(GURL("http://custom/proxy.pac")); 466 467 rules.AddFailDownloadRule("http://custom/proxy.pac"); 468 469 TestCompletionCallback callback; 470 CapturingNetLog log(CapturingNetLog::kUnbounded); 471 InitProxyResolver init(&resolver, &fetcher, &log); 472 EXPECT_EQ(kFailedDownloading, 473 init.Init(config, base::TimeDelta::FromSeconds(-5), 474 NULL, &callback)); 475 EXPECT_EQ(NULL, resolver.script_data()); 476 477 // Check the NetLog was filled correctly. 478 EXPECT_EQ(4u, log.entries().size()); 479 EXPECT_TRUE(LogContainsBeginEvent( 480 log.entries(), 0, NetLog::TYPE_INIT_PROXY_RESOLVER)); 481 EXPECT_TRUE(LogContainsBeginEvent( 482 log.entries(), 1, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 483 EXPECT_TRUE(LogContainsEndEvent( 484 log.entries(), 2, NetLog::TYPE_INIT_PROXY_RESOLVER_FETCH_PAC_SCRIPT)); 485 EXPECT_TRUE(LogContainsEndEvent( 486 log.entries(), 3, NetLog::TYPE_INIT_PROXY_RESOLVER)); 487} 488 489} // namespace 490} // namespace net 491