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.
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/net_log.h"
16 #include "net/base/net_log_unittest.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/dns/mock_host_resolver.h"
19 #include "net/proxy/dhcp_proxy_script_fetcher.h"
20 #include "net/proxy/mock_proxy_script_fetcher.h"
21 #include "net/proxy/proxy_config.h"
22 #include "net/proxy/proxy_resolver.h"
23 #include "net/proxy/proxy_script_decider.h"
24 #include "net/proxy/proxy_script_fetcher.h"
25 #include "net/url_request/url_request_context.h"
26 #include "testing/gtest/include/gtest/gtest.h"
32 kFailedDownloading
= -100,
33 kFailedParsing
= ERR_PAC_SCRIPT_FAILED
,
39 Rule(const GURL
& url
, int fetch_error
, bool is_valid_script
)
41 fetch_error(fetch_error
),
42 is_valid_script(is_valid_script
) {
45 base::string16
text() const {
47 return base::UTF8ToUTF16(url
.spec() + "!FindProxyForURL");
48 if (fetch_error
== OK
)
49 return base::UTF8ToUTF16(url
.spec() + "!invalid-script");
50 return base::string16();
58 Rule
AddSuccessRule(const char* url
) {
59 Rule
rule(GURL(url
), OK
/*fetch_error*/, true);
60 rules_
.push_back(rule
);
64 void AddFailDownloadRule(const char* url
) {
65 rules_
.push_back(Rule(GURL(url
), kFailedDownloading
/*fetch_error*/,
69 void AddFailParsingRule(const char* url
) {
70 rules_
.push_back(Rule(GURL(url
), OK
/*fetch_error*/, false));
73 const Rule
& GetRuleByUrl(const GURL
& url
) const {
74 for (RuleList::const_iterator it
= rules_
.begin(); it
!= rules_
.end();
79 LOG(FATAL
) << "Rule not found for " << url
;
83 const Rule
& GetRuleByText(const base::string16
& text
) const {
84 for (RuleList::const_iterator it
= rules_
.begin(); it
!= rules_
.end();
86 if (it
->text() == text
)
89 LOG(FATAL
) << "Rule not found for " << text
;
94 typedef std::vector
<Rule
> RuleList
;
98 class RuleBasedProxyScriptFetcher
: public ProxyScriptFetcher
{
100 explicit RuleBasedProxyScriptFetcher(const Rules
* rules
)
101 : rules_(rules
), request_context_(NULL
) {}
103 virtual void SetRequestContext(URLRequestContext
* context
) {
104 request_context_
= context
;
107 // ProxyScriptFetcher implementation.
108 int Fetch(const GURL
& url
,
109 base::string16
* text
,
110 const CompletionCallback
& callback
) override
{
111 const Rules::Rule
& rule
= rules_
->GetRuleByUrl(url
);
112 int rv
= rule
.fetch_error
;
113 EXPECT_NE(ERR_UNEXPECTED
, rv
);
119 void Cancel() override
{}
121 URLRequestContext
* GetRequestContext() const override
{
122 return request_context_
;
127 URLRequestContext
* request_context_
;
130 // A mock retriever, returns asynchronously when CompleteRequests() is called.
131 class MockDhcpProxyScriptFetcher
: public DhcpProxyScriptFetcher
{
133 MockDhcpProxyScriptFetcher();
134 ~MockDhcpProxyScriptFetcher() override
;
136 int Fetch(base::string16
* utf16_text
,
137 const CompletionCallback
& callback
) override
;
138 void Cancel() override
;
139 const GURL
& GetPacURL() const override
;
141 virtual void SetPacURL(const GURL
& url
);
143 virtual void CompleteRequests(int result
, const base::string16
& script
);
146 CompletionCallback callback_
;
147 base::string16
* utf16_text_
;
149 DISALLOW_COPY_AND_ASSIGN(MockDhcpProxyScriptFetcher
);
152 MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() { }
154 MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() { }
156 int MockDhcpProxyScriptFetcher::Fetch(base::string16
* utf16_text
,
157 const CompletionCallback
& callback
) {
158 utf16_text_
= utf16_text
;
159 callback_
= callback
;
160 return ERR_IO_PENDING
;
163 void MockDhcpProxyScriptFetcher::Cancel() { }
165 const GURL
& MockDhcpProxyScriptFetcher::GetPacURL() const {
169 void MockDhcpProxyScriptFetcher::SetPacURL(const GURL
& url
) {
173 void MockDhcpProxyScriptFetcher::CompleteRequests(
174 int result
, const base::string16
& script
) {
175 *utf16_text_
= script
;
176 callback_
.Run(result
);
179 // Succeed using custom PAC script.
180 TEST(ProxyScriptDeciderTest
, CustomPacSucceeds
) {
182 RuleBasedProxyScriptFetcher
fetcher(&rules
);
183 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
186 config
.set_pac_url(GURL("http://custom/proxy.pac"));
188 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
190 TestCompletionCallback callback
;
192 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
193 EXPECT_EQ(OK
, decider
.Start(
194 config
, base::TimeDelta(), true, callback
.callback()));
195 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
197 // Check the NetLog was filled correctly.
198 CapturingNetLog::CapturedEntryList entries
;
199 log
.GetEntries(&entries
);
201 EXPECT_EQ(4u, entries
.size());
202 EXPECT_TRUE(LogContainsBeginEvent(
203 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
204 EXPECT_TRUE(LogContainsBeginEvent(
205 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
206 EXPECT_TRUE(LogContainsEndEvent(
207 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
208 EXPECT_TRUE(LogContainsEndEvent(
209 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
211 EXPECT_TRUE(decider
.effective_config().has_pac_url());
212 EXPECT_EQ(config
.pac_url(), decider
.effective_config().pac_url());
215 // Fail downloading the custom PAC script.
216 TEST(ProxyScriptDeciderTest
, CustomPacFails1
) {
218 RuleBasedProxyScriptFetcher
fetcher(&rules
);
219 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
222 config
.set_pac_url(GURL("http://custom/proxy.pac"));
224 rules
.AddFailDownloadRule("http://custom/proxy.pac");
226 TestCompletionCallback callback
;
228 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
229 EXPECT_EQ(kFailedDownloading
,
230 decider
.Start(config
, base::TimeDelta(), true,
231 callback
.callback()));
232 EXPECT_EQ(NULL
, decider
.script_data());
234 // Check the NetLog was filled correctly.
235 CapturingNetLog::CapturedEntryList entries
;
236 log
.GetEntries(&entries
);
238 EXPECT_EQ(4u, entries
.size());
239 EXPECT_TRUE(LogContainsBeginEvent(
240 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
241 EXPECT_TRUE(LogContainsBeginEvent(
242 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
243 EXPECT_TRUE(LogContainsEndEvent(
244 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
245 EXPECT_TRUE(LogContainsEndEvent(
246 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
248 EXPECT_FALSE(decider
.effective_config().has_pac_url());
251 // Fail parsing the custom PAC script.
252 TEST(ProxyScriptDeciderTest
, CustomPacFails2
) {
254 RuleBasedProxyScriptFetcher
fetcher(&rules
);
255 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
258 config
.set_pac_url(GURL("http://custom/proxy.pac"));
260 rules
.AddFailParsingRule("http://custom/proxy.pac");
262 TestCompletionCallback callback
;
263 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
264 EXPECT_EQ(kFailedParsing
,
265 decider
.Start(config
, base::TimeDelta(), true,
266 callback
.callback()));
267 EXPECT_EQ(NULL
, decider
.script_data());
270 // Fail downloading the custom PAC script, because the fetcher was NULL.
271 TEST(ProxyScriptDeciderTest
, HasNullProxyScriptFetcher
) {
273 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
276 config
.set_pac_url(GURL("http://custom/proxy.pac"));
278 TestCompletionCallback callback
;
279 ProxyScriptDecider
decider(NULL
, &dhcp_fetcher
, NULL
);
280 EXPECT_EQ(ERR_UNEXPECTED
,
281 decider
.Start(config
, base::TimeDelta(), true,
282 callback
.callback()));
283 EXPECT_EQ(NULL
, decider
.script_data());
286 // Succeeds in choosing autodetect (WPAD DNS).
287 TEST(ProxyScriptDeciderTest
, AutodetectSuccess
) {
289 RuleBasedProxyScriptFetcher
fetcher(&rules
);
290 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
293 config
.set_auto_detect(true);
295 Rules::Rule rule
= rules
.AddSuccessRule("http://wpad/wpad.dat");
297 TestCompletionCallback callback
;
298 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
299 EXPECT_EQ(OK
, decider
.Start(
300 config
, base::TimeDelta(), true, callback
.callback()));
301 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
303 EXPECT_TRUE(decider
.effective_config().has_pac_url());
304 EXPECT_EQ(rule
.url
, decider
.effective_config().pac_url());
307 class ProxyScriptDeciderQuickCheckTest
: public ::testing::Test
{
309 ProxyScriptDeciderQuickCheckTest()
310 : rule_(rules_
.AddSuccessRule("http://wpad/wpad.dat")),
311 fetcher_(&rules_
) { }
313 void SetUp() override
{
314 request_context_
.set_host_resolver(&resolver_
);
315 fetcher_
.SetRequestContext(&request_context_
);
316 config_
.set_auto_detect(true);
317 decider_
.reset(new ProxyScriptDecider(&fetcher_
, &dhcp_fetcher_
, NULL
));
321 return decider_
->Start(config_
, base::TimeDelta(), true,
322 callback_
.callback());
326 scoped_ptr
<ProxyScriptDecider
> decider_
;
327 MockHostResolver resolver_
;
330 TestCompletionCallback callback_
;
331 RuleBasedProxyScriptFetcher fetcher_
;
333 DoNothingDhcpProxyScriptFetcher dhcp_fetcher_
;
336 URLRequestContext request_context_
;
339 // Fails if a synchronous DNS lookup success for wpad causes QuickCheck to fail.
340 TEST_F(ProxyScriptDeciderQuickCheckTest
, SyncSuccess
) {
341 resolver_
.set_synchronous_mode(true);
342 resolver_
.rules()->AddRule("wpad", "1.2.3.4");
344 EXPECT_EQ(OK
, StartDecider());
345 EXPECT_EQ(rule_
.text(), decider_
->script_data()->utf16());
347 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
348 EXPECT_EQ(rule_
.url
, decider_
->effective_config().pac_url());
351 // Fails if an asynchronous DNS lookup success for wpad causes QuickCheck to
353 TEST_F(ProxyScriptDeciderQuickCheckTest
, AsyncSuccess
) {
354 resolver_
.set_ondemand_mode(true);
355 resolver_
.rules()->AddRule("wpad", "1.2.3.4");
357 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
358 ASSERT_TRUE(resolver_
.has_pending_requests());
359 resolver_
.ResolveAllPending();
360 callback_
.WaitForResult();
361 EXPECT_FALSE(resolver_
.has_pending_requests());
362 EXPECT_EQ(rule_
.text(), decider_
->script_data()->utf16());
363 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
364 EXPECT_EQ(rule_
.url
, decider_
->effective_config().pac_url());
367 // Fails if an asynchronous DNS lookup failure (i.e. an NXDOMAIN) still causes
368 // ProxyScriptDecider to yield a PAC URL.
369 TEST_F(ProxyScriptDeciderQuickCheckTest
, AsyncFail
) {
370 resolver_
.set_ondemand_mode(true);
371 resolver_
.rules()->AddSimulatedFailure("wpad");
372 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
373 ASSERT_TRUE(resolver_
.has_pending_requests());
374 resolver_
.ResolveAllPending();
375 callback_
.WaitForResult();
376 EXPECT_FALSE(decider_
->effective_config().has_pac_url());
379 // Fails if a DNS lookup timeout either causes ProxyScriptDecider to yield a PAC
380 // URL or causes ProxyScriptDecider not to cancel its pending resolution.
381 TEST_F(ProxyScriptDeciderQuickCheckTest
, AsyncTimeout
) {
382 resolver_
.set_ondemand_mode(true);
383 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
384 ASSERT_TRUE(resolver_
.has_pending_requests());
385 callback_
.WaitForResult();
386 EXPECT_FALSE(resolver_
.has_pending_requests());
387 EXPECT_FALSE(decider_
->effective_config().has_pac_url());
390 // Fails if DHCP check doesn't take place before QuickCheck.
391 TEST_F(ProxyScriptDeciderQuickCheckTest
, QuickCheckInhibitsDhcp
) {
392 MockDhcpProxyScriptFetcher dhcp_fetcher
;
393 const char *kPac
= "function FindProxyForURL(u,h) { return \"DIRECT\"; }";
394 base::string16 pac_contents
= base::UTF8ToUTF16(kPac
);
395 GURL
url("http://foobar/baz");
396 dhcp_fetcher
.SetPacURL(url
);
397 decider_
.reset(new ProxyScriptDecider(&fetcher_
, &dhcp_fetcher
, NULL
));
398 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
399 dhcp_fetcher
.CompleteRequests(OK
, pac_contents
);
400 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
401 EXPECT_EQ(decider_
->effective_config().pac_url(), url
);
404 // Fails if QuickCheck still happens when disabled. To ensure QuickCheck is not
405 // happening, we add a synchronous failing resolver, which would ordinarily
406 // mean a QuickCheck failure, then ensure that our ProxyScriptFetcher is still
408 TEST_F(ProxyScriptDeciderQuickCheckTest
, QuickCheckDisabled
) {
409 const char *kPac
= "function FindProxyForURL(u,h) { return \"DIRECT\"; }";
410 resolver_
.set_synchronous_mode(true);
411 resolver_
.rules()->AddSimulatedFailure("wpad");
412 MockProxyScriptFetcher fetcher
;
413 decider_
.reset(new ProxyScriptDecider(&fetcher
, &dhcp_fetcher_
, NULL
));
414 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
415 EXPECT_TRUE(fetcher
.has_pending_request());
416 fetcher
.NotifyFetchCompletion(OK
, kPac
);
419 TEST_F(ProxyScriptDeciderQuickCheckTest
, ExplicitPacUrl
) {
420 const char *kCustomUrl
= "http://custom/proxy.pac";
421 config_
.set_pac_url(GURL(kCustomUrl
));
422 Rules::Rule rule
= rules_
.AddSuccessRule(kCustomUrl
);
423 resolver_
.rules()->AddSimulatedFailure("wpad");
424 resolver_
.rules()->AddRule("custom", "1.2.3.4");
425 EXPECT_EQ(ERR_IO_PENDING
, StartDecider());
426 callback_
.WaitForResult();
427 EXPECT_TRUE(decider_
->effective_config().has_pac_url());
428 EXPECT_EQ(rule
.url
, decider_
->effective_config().pac_url());
431 // Fails at WPAD (downloading), but succeeds in choosing the custom PAC.
432 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomSuccess1
) {
434 RuleBasedProxyScriptFetcher
fetcher(&rules
);
435 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
438 config
.set_auto_detect(true);
439 config
.set_pac_url(GURL("http://custom/proxy.pac"));
441 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
442 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
444 TestCompletionCallback callback
;
445 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
446 EXPECT_EQ(OK
, decider
.Start(
447 config
, base::TimeDelta(), true, callback
.callback()));
448 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
450 EXPECT_TRUE(decider
.effective_config().has_pac_url());
451 EXPECT_EQ(rule
.url
, decider
.effective_config().pac_url());
454 // Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in
455 // choosing the custom PAC.
456 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomSuccess2
) {
458 RuleBasedProxyScriptFetcher
fetcher(&rules
);
459 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
462 config
.set_auto_detect(true);
463 config
.set_pac_url(GURL("http://custom/proxy.pac"));
464 config
.proxy_rules().ParseFromString("unused-manual-proxy:99");
466 rules
.AddFailParsingRule("http://wpad/wpad.dat");
467 Rules::Rule rule
= rules
.AddSuccessRule("http://custom/proxy.pac");
469 TestCompletionCallback callback
;
472 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
473 EXPECT_EQ(OK
, decider
.Start(config
, base::TimeDelta(),
474 true, callback
.callback()));
475 EXPECT_EQ(rule
.text(), decider
.script_data()->utf16());
477 // Verify that the effective configuration no longer contains auto detect or
478 // any of the manual settings.
479 EXPECT_TRUE(decider
.effective_config().Equals(
480 ProxyConfig::CreateFromCustomPacURL(GURL("http://custom/proxy.pac"))));
482 // Check the NetLog was filled correctly.
483 // (Note that various states are repeated since both WPAD and custom
484 // PAC scripts are tried).
485 CapturingNetLog::CapturedEntryList entries
;
486 log
.GetEntries(&entries
);
488 EXPECT_EQ(10u, entries
.size());
489 EXPECT_TRUE(LogContainsBeginEvent(
490 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
491 // This is the DHCP phase, which fails fetching rather than parsing, so
492 // there is no pair of SET_PAC_SCRIPT events.
493 EXPECT_TRUE(LogContainsBeginEvent(
494 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
495 EXPECT_TRUE(LogContainsEndEvent(
496 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
497 EXPECT_TRUE(LogContainsEvent(
499 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE
,
500 NetLog::PHASE_NONE
));
501 // This is the DNS phase, which attempts a fetch but fails.
502 EXPECT_TRUE(LogContainsBeginEvent(
503 entries
, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
504 EXPECT_TRUE(LogContainsEndEvent(
505 entries
, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
506 EXPECT_TRUE(LogContainsEvent(
508 NetLog::TYPE_PROXY_SCRIPT_DECIDER_FALLING_BACK_TO_NEXT_PAC_SOURCE
,
509 NetLog::PHASE_NONE
));
510 // Finally, the custom PAC URL phase.
511 EXPECT_TRUE(LogContainsBeginEvent(
512 entries
, 7, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
513 EXPECT_TRUE(LogContainsEndEvent(
514 entries
, 8, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
515 EXPECT_TRUE(LogContainsEndEvent(
516 entries
, 9, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
519 // Fails at WPAD (downloading), and fails at custom PAC (downloading).
520 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomFails1
) {
522 RuleBasedProxyScriptFetcher
fetcher(&rules
);
523 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
526 config
.set_auto_detect(true);
527 config
.set_pac_url(GURL("http://custom/proxy.pac"));
529 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
530 rules
.AddFailDownloadRule("http://custom/proxy.pac");
532 TestCompletionCallback callback
;
533 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
534 EXPECT_EQ(kFailedDownloading
,
535 decider
.Start(config
, base::TimeDelta(), true,
536 callback
.callback()));
537 EXPECT_EQ(NULL
, decider
.script_data());
540 // Fails at WPAD (downloading), and fails at custom PAC (parsing).
541 TEST(ProxyScriptDeciderTest
, AutodetectFailCustomFails2
) {
543 RuleBasedProxyScriptFetcher
fetcher(&rules
);
544 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
547 config
.set_auto_detect(true);
548 config
.set_pac_url(GURL("http://custom/proxy.pac"));
550 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
551 rules
.AddFailParsingRule("http://custom/proxy.pac");
553 TestCompletionCallback callback
;
554 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
555 EXPECT_EQ(kFailedParsing
,
556 decider
.Start(config
, base::TimeDelta(), true,
557 callback
.callback()));
558 EXPECT_EQ(NULL
, decider
.script_data());
561 // This is a copy-paste of CustomPacFails1, with the exception that we give it
562 // a 1 millisecond delay. This means it will now complete asynchronously.
563 // Moreover, we test the NetLog to make sure it logged the pause.
564 TEST(ProxyScriptDeciderTest
, CustomPacFails1_WithPositiveDelay
) {
566 RuleBasedProxyScriptFetcher
fetcher(&rules
);
567 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
570 config
.set_pac_url(GURL("http://custom/proxy.pac"));
572 rules
.AddFailDownloadRule("http://custom/proxy.pac");
574 TestCompletionCallback callback
;
576 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
577 EXPECT_EQ(ERR_IO_PENDING
,
578 decider
.Start(config
, base::TimeDelta::FromMilliseconds(1),
579 true, callback
.callback()));
581 EXPECT_EQ(kFailedDownloading
, callback
.WaitForResult());
582 EXPECT_EQ(NULL
, decider
.script_data());
584 // Check the NetLog was filled correctly.
585 CapturingNetLog::CapturedEntryList entries
;
586 log
.GetEntries(&entries
);
588 EXPECT_EQ(6u, entries
.size());
589 EXPECT_TRUE(LogContainsBeginEvent(
590 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
591 EXPECT_TRUE(LogContainsBeginEvent(
592 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT
));
593 EXPECT_TRUE(LogContainsEndEvent(
594 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_WAIT
));
595 EXPECT_TRUE(LogContainsBeginEvent(
596 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
597 EXPECT_TRUE(LogContainsEndEvent(
598 entries
, 4, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
599 EXPECT_TRUE(LogContainsEndEvent(
600 entries
, 5, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
603 // This is a copy-paste of CustomPacFails1, with the exception that we give it
604 // a -5 second delay instead of a 0 ms delay. This change should have no effect
605 // so the rest of the test is unchanged.
606 TEST(ProxyScriptDeciderTest
, CustomPacFails1_WithNegativeDelay
) {
608 RuleBasedProxyScriptFetcher
fetcher(&rules
);
609 DoNothingDhcpProxyScriptFetcher dhcp_fetcher
;
612 config
.set_pac_url(GURL("http://custom/proxy.pac"));
614 rules
.AddFailDownloadRule("http://custom/proxy.pac");
616 TestCompletionCallback callback
;
618 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, &log
);
619 EXPECT_EQ(kFailedDownloading
,
620 decider
.Start(config
, base::TimeDelta::FromSeconds(-5),
621 true, callback
.callback()));
622 EXPECT_EQ(NULL
, decider
.script_data());
624 // Check the NetLog was filled correctly.
625 CapturingNetLog::CapturedEntryList entries
;
626 log
.GetEntries(&entries
);
628 EXPECT_EQ(4u, entries
.size());
629 EXPECT_TRUE(LogContainsBeginEvent(
630 entries
, 0, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
631 EXPECT_TRUE(LogContainsBeginEvent(
632 entries
, 1, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
633 EXPECT_TRUE(LogContainsEndEvent(
634 entries
, 2, NetLog::TYPE_PROXY_SCRIPT_DECIDER_FETCH_PAC_SCRIPT
));
635 EXPECT_TRUE(LogContainsEndEvent(
636 entries
, 3, NetLog::TYPE_PROXY_SCRIPT_DECIDER
));
639 class SynchronousSuccessDhcpFetcher
: public DhcpProxyScriptFetcher
{
641 explicit SynchronousSuccessDhcpFetcher(const base::string16
& expected_text
)
642 : gurl_("http://dhcppac/"), expected_text_(expected_text
) {
645 int Fetch(base::string16
* utf16_text
,
646 const CompletionCallback
& callback
) override
{
647 *utf16_text
= expected_text_
;
651 void Cancel() override
{}
653 const GURL
& GetPacURL() const override
{ return gurl_
; }
655 const base::string16
& expected_text() const {
656 return expected_text_
;
661 base::string16 expected_text_
;
663 DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher
);
666 // All of the tests above that use ProxyScriptDecider have tested
667 // failure to fetch a PAC file via DHCP configuration, so we now test
668 // success at downloading and parsing, and then success at downloading,
669 // failure at parsing.
671 TEST(ProxyScriptDeciderTest
, AutodetectDhcpSuccess
) {
673 RuleBasedProxyScriptFetcher
fetcher(&rules
);
674 SynchronousSuccessDhcpFetcher
dhcp_fetcher(
675 base::WideToUTF16(L
"http://bingo/!FindProxyForURL"));
678 config
.set_auto_detect(true);
680 rules
.AddSuccessRule("http://bingo/");
681 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
683 TestCompletionCallback callback
;
684 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
685 EXPECT_EQ(OK
, decider
.Start(
686 config
, base::TimeDelta(), true, callback
.callback()));
687 EXPECT_EQ(dhcp_fetcher
.expected_text(),
688 decider
.script_data()->utf16());
690 EXPECT_TRUE(decider
.effective_config().has_pac_url());
691 EXPECT_EQ(GURL("http://dhcppac/"), decider
.effective_config().pac_url());
694 TEST(ProxyScriptDeciderTest
, AutodetectDhcpFailParse
) {
696 RuleBasedProxyScriptFetcher
fetcher(&rules
);
697 SynchronousSuccessDhcpFetcher
dhcp_fetcher(
698 base::WideToUTF16(L
"http://bingo/!invalid-script"));
701 config
.set_auto_detect(true);
703 rules
.AddFailParsingRule("http://bingo/");
704 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
706 TestCompletionCallback callback
;
707 ProxyScriptDecider
decider(&fetcher
, &dhcp_fetcher
, NULL
);
708 // Since there is fallback to DNS-based WPAD, the final error will be that
709 // it failed downloading, not that it failed parsing.
710 EXPECT_EQ(kFailedDownloading
,
711 decider
.Start(config
, base::TimeDelta(), true, callback
.callback()));
712 EXPECT_EQ(NULL
, decider
.script_data());
714 EXPECT_FALSE(decider
.effective_config().has_pac_url());
717 class AsyncFailDhcpFetcher
718 : public DhcpProxyScriptFetcher
,
719 public base::SupportsWeakPtr
<AsyncFailDhcpFetcher
> {
721 AsyncFailDhcpFetcher() {}
722 ~AsyncFailDhcpFetcher() override
{}
724 int Fetch(base::string16
* utf16_text
,
725 const CompletionCallback
& callback
) override
{
726 callback_
= callback
;
727 base::MessageLoop::current()->PostTask(
729 base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure
, AsWeakPtr()));
730 return ERR_IO_PENDING
;
733 void Cancel() override
{ callback_
.Reset(); }
735 const GURL
& GetPacURL() const override
{ return dummy_gurl_
; }
737 void CallbackWithFailure() {
738 if (!callback_
.is_null())
739 callback_
.Run(ERR_PAC_NOT_IN_DHCP
);
744 CompletionCallback callback_
;
747 TEST(ProxyScriptDeciderTest
, DhcpCancelledByDestructor
) {
748 // This regression test would crash before
749 // http://codereview.chromium.org/7044058/
750 // Thus, we don't care much about actual results (hence no EXPECT or ASSERT
751 // macros below), just that it doesn't crash.
753 RuleBasedProxyScriptFetcher
fetcher(&rules
);
755 scoped_ptr
<AsyncFailDhcpFetcher
> dhcp_fetcher(new AsyncFailDhcpFetcher());
758 config
.set_auto_detect(true);
759 rules
.AddFailDownloadRule("http://wpad/wpad.dat");
761 TestCompletionCallback callback
;
763 // Scope so ProxyScriptDecider gets destroyed early.
765 ProxyScriptDecider
decider(&fetcher
, dhcp_fetcher
.get(), NULL
);
766 decider
.Start(config
, base::TimeDelta(), true, callback
.callback());
769 // Run the message loop to let the DHCP fetch complete and post the results
770 // back. Before the fix linked to above, this would try to invoke on
771 // the callback object provided by ProxyScriptDecider after it was
773 base::MessageLoop::current()->RunUntilIdle();