OLD | NEW |
| (Empty) |
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 <vector> | |
6 | |
7 #include "base/bind.h" | |
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" | |
27 | |
28 namespace net { | |
29 namespace { | |
30 | |
31 enum Error { | |
32 kFailedDownloading = -100, | |
33 kFailedParsing = ERR_PAC_SCRIPT_FAILED, | |
34 }; | |
35 | |
36 class Rules { | |
37 public: | |
38 struct Rule { | |
39 Rule(const GURL& url, int fetch_error, bool is_valid_script) | |
40 : url(url), | |
41 fetch_error(fetch_error), | |
42 is_valid_script(is_valid_script) { | |
43 } | |
44 | |
45 base::string16 text() const { | |
46 if (is_valid_script) | |
47 return base::UTF8ToUTF16(url.spec() + "!FindProxyForURL"); | |
48 if (fetch_error == OK) | |
49 return base::UTF8ToUTF16(url.spec() + "!invalid-script"); | |
50 return base::string16(); | |
51 } | |
52 | |
53 GURL url; | |
54 int fetch_error; | |
55 bool is_valid_script; | |
56 }; | |
57 | |
58 Rule AddSuccessRule(const char* url) { | |
59 Rule rule(GURL(url), OK /*fetch_error*/, true); | |
60 rules_.push_back(rule); | |
61 return rule; | |
62 } | |
63 | |
64 void AddFailDownloadRule(const char* url) { | |
65 rules_.push_back(Rule(GURL(url), kFailedDownloading /*fetch_error*/, | |
66 false)); | |
67 } | |
68 | |
69 void AddFailParsingRule(const char* url) { | |
70 rules_.push_back(Rule(GURL(url), OK /*fetch_error*/, false)); | |
71 } | |
72 | |
73 const Rule& GetRuleByUrl(const GURL& url) const { | |
74 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); | |
75 ++it) { | |
76 if (it->url == url) | |
77 return *it; | |
78 } | |
79 LOG(FATAL) << "Rule not found for " << url; | |
80 return rules_[0]; | |
81 } | |
82 | |
83 const Rule& GetRuleByText(const base::string16& text) const { | |
84 for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); | |
85 ++it) { | |
86 if (it->text() == text) | |
87 return *it; | |
88 } | |
89 LOG(FATAL) << "Rule not found for " << text; | |
90 return rules_[0]; | |
91 } | |
92 | |
93 private: | |
94 typedef std::vector<Rule> RuleList; | |
95 RuleList rules_; | |
96 }; | |
97 | |
98 class RuleBasedProxyScriptFetcher : public ProxyScriptFetcher { | |
99 public: | |
100 explicit RuleBasedProxyScriptFetcher(const Rules* rules) | |
101 : rules_(rules), request_context_(NULL) {} | |
102 | |
103 virtual void SetRequestContext(URLRequestContext* context) { | |
104 request_context_ = context; | |
105 } | |
106 | |
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); | |
114 if (rv == OK) | |
115 *text = rule.text(); | |
116 return rv; | |
117 } | |
118 | |
119 void Cancel() override {} | |
120 | |
121 URLRequestContext* GetRequestContext() const override { | |
122 return request_context_; | |
123 } | |
124 | |
125 private: | |
126 const Rules* rules_; | |
127 URLRequestContext* request_context_; | |
128 }; | |
129 | |
130 // A mock retriever, returns asynchronously when CompleteRequests() is called. | |
131 class MockDhcpProxyScriptFetcher : public DhcpProxyScriptFetcher { | |
132 public: | |
133 MockDhcpProxyScriptFetcher(); | |
134 ~MockDhcpProxyScriptFetcher() override; | |
135 | |
136 int Fetch(base::string16* utf16_text, | |
137 const CompletionCallback& callback) override; | |
138 void Cancel() override; | |
139 const GURL& GetPacURL() const override; | |
140 | |
141 virtual void SetPacURL(const GURL& url); | |
142 | |
143 virtual void CompleteRequests(int result, const base::string16& script); | |
144 | |
145 private: | |
146 CompletionCallback callback_; | |
147 base::string16* utf16_text_; | |
148 GURL gurl_; | |
149 DISALLOW_COPY_AND_ASSIGN(MockDhcpProxyScriptFetcher); | |
150 }; | |
151 | |
152 MockDhcpProxyScriptFetcher::MockDhcpProxyScriptFetcher() { } | |
153 | |
154 MockDhcpProxyScriptFetcher::~MockDhcpProxyScriptFetcher() { } | |
155 | |
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; | |
161 } | |
162 | |
163 void MockDhcpProxyScriptFetcher::Cancel() { } | |
164 | |
165 const GURL& MockDhcpProxyScriptFetcher::GetPacURL() const { | |
166 return gurl_; | |
167 } | |
168 | |
169 void MockDhcpProxyScriptFetcher::SetPacURL(const GURL& url) { | |
170 gurl_ = url; | |
171 } | |
172 | |
173 void MockDhcpProxyScriptFetcher::CompleteRequests( | |
174 int result, const base::string16& script) { | |
175 *utf16_text_ = script; | |
176 callback_.Run(result); | |
177 } | |
178 | |
179 // Succeed using custom PAC script. | |
180 TEST(ProxyScriptDeciderTest, CustomPacSucceeds) { | |
181 Rules rules; | |
182 RuleBasedProxyScriptFetcher fetcher(&rules); | |
183 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
184 | |
185 ProxyConfig config; | |
186 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
187 | |
188 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); | |
189 | |
190 TestCompletionCallback callback; | |
191 CapturingNetLog log; | |
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()); | |
196 | |
197 // Check the NetLog was filled correctly. | |
198 CapturingNetLog::CapturedEntryList entries; | |
199 log.GetEntries(&entries); | |
200 | |
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)); | |
210 | |
211 EXPECT_TRUE(decider.effective_config().has_pac_url()); | |
212 EXPECT_EQ(config.pac_url(), decider.effective_config().pac_url()); | |
213 } | |
214 | |
215 // Fail downloading the custom PAC script. | |
216 TEST(ProxyScriptDeciderTest, CustomPacFails1) { | |
217 Rules rules; | |
218 RuleBasedProxyScriptFetcher fetcher(&rules); | |
219 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
220 | |
221 ProxyConfig config; | |
222 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
223 | |
224 rules.AddFailDownloadRule("http://custom/proxy.pac"); | |
225 | |
226 TestCompletionCallback callback; | |
227 CapturingNetLog log; | |
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()); | |
233 | |
234 // Check the NetLog was filled correctly. | |
235 CapturingNetLog::CapturedEntryList entries; | |
236 log.GetEntries(&entries); | |
237 | |
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)); | |
247 | |
248 EXPECT_FALSE(decider.effective_config().has_pac_url()); | |
249 } | |
250 | |
251 // Fail parsing the custom PAC script. | |
252 TEST(ProxyScriptDeciderTest, CustomPacFails2) { | |
253 Rules rules; | |
254 RuleBasedProxyScriptFetcher fetcher(&rules); | |
255 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
256 | |
257 ProxyConfig config; | |
258 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
259 | |
260 rules.AddFailParsingRule("http://custom/proxy.pac"); | |
261 | |
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()); | |
268 } | |
269 | |
270 // Fail downloading the custom PAC script, because the fetcher was NULL. | |
271 TEST(ProxyScriptDeciderTest, HasNullProxyScriptFetcher) { | |
272 Rules rules; | |
273 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
274 | |
275 ProxyConfig config; | |
276 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
277 | |
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()); | |
284 } | |
285 | |
286 // Succeeds in choosing autodetect (WPAD DNS). | |
287 TEST(ProxyScriptDeciderTest, AutodetectSuccess) { | |
288 Rules rules; | |
289 RuleBasedProxyScriptFetcher fetcher(&rules); | |
290 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
291 | |
292 ProxyConfig config; | |
293 config.set_auto_detect(true); | |
294 | |
295 Rules::Rule rule = rules.AddSuccessRule("http://wpad/wpad.dat"); | |
296 | |
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()); | |
302 | |
303 EXPECT_TRUE(decider.effective_config().has_pac_url()); | |
304 EXPECT_EQ(rule.url, decider.effective_config().pac_url()); | |
305 } | |
306 | |
307 class ProxyScriptDeciderQuickCheckTest : public ::testing::Test { | |
308 public: | |
309 ProxyScriptDeciderQuickCheckTest() | |
310 : rule_(rules_.AddSuccessRule("http://wpad/wpad.dat")), | |
311 fetcher_(&rules_) { } | |
312 | |
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)); | |
318 } | |
319 | |
320 int StartDecider() { | |
321 return decider_->Start(config_, base::TimeDelta(), true, | |
322 callback_.callback()); | |
323 } | |
324 | |
325 protected: | |
326 scoped_ptr<ProxyScriptDecider> decider_; | |
327 MockHostResolver resolver_; | |
328 Rules rules_; | |
329 Rules::Rule rule_; | |
330 TestCompletionCallback callback_; | |
331 RuleBasedProxyScriptFetcher fetcher_; | |
332 ProxyConfig config_; | |
333 DoNothingDhcpProxyScriptFetcher dhcp_fetcher_; | |
334 | |
335 private: | |
336 URLRequestContext request_context_; | |
337 }; | |
338 | |
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"); | |
343 | |
344 EXPECT_EQ(OK, StartDecider()); | |
345 EXPECT_EQ(rule_.text(), decider_->script_data()->utf16()); | |
346 | |
347 EXPECT_TRUE(decider_->effective_config().has_pac_url()); | |
348 EXPECT_EQ(rule_.url, decider_->effective_config().pac_url()); | |
349 } | |
350 | |
351 // Fails if an asynchronous DNS lookup success for wpad causes QuickCheck to | |
352 // fail. | |
353 TEST_F(ProxyScriptDeciderQuickCheckTest, AsyncSuccess) { | |
354 resolver_.set_ondemand_mode(true); | |
355 resolver_.rules()->AddRule("wpad", "1.2.3.4"); | |
356 | |
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()); | |
365 } | |
366 | |
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()); | |
377 } | |
378 | |
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()); | |
388 } | |
389 | |
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); | |
402 } | |
403 | |
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 | |
407 // asked to fetch. | |
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); | |
417 } | |
418 | |
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()); | |
429 } | |
430 | |
431 // Fails at WPAD (downloading), but succeeds in choosing the custom PAC. | |
432 TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess1) { | |
433 Rules rules; | |
434 RuleBasedProxyScriptFetcher fetcher(&rules); | |
435 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
436 | |
437 ProxyConfig config; | |
438 config.set_auto_detect(true); | |
439 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
440 | |
441 rules.AddFailDownloadRule("http://wpad/wpad.dat"); | |
442 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); | |
443 | |
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()); | |
449 | |
450 EXPECT_TRUE(decider.effective_config().has_pac_url()); | |
451 EXPECT_EQ(rule.url, decider.effective_config().pac_url()); | |
452 } | |
453 | |
454 // Fails at WPAD (no DHCP config, DNS PAC fails parsing), but succeeds in | |
455 // choosing the custom PAC. | |
456 TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess2) { | |
457 Rules rules; | |
458 RuleBasedProxyScriptFetcher fetcher(&rules); | |
459 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
460 | |
461 ProxyConfig config; | |
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"); | |
465 | |
466 rules.AddFailParsingRule("http://wpad/wpad.dat"); | |
467 Rules::Rule rule = rules.AddSuccessRule("http://custom/proxy.pac"); | |
468 | |
469 TestCompletionCallback callback; | |
470 CapturingNetLog log; | |
471 | |
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()); | |
476 | |
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")))); | |
481 | |
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); | |
487 | |
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( | |
498 entries, 3, | |
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( | |
507 entries, 6, | |
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)); | |
517 } | |
518 | |
519 // Fails at WPAD (downloading), and fails at custom PAC (downloading). | |
520 TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails1) { | |
521 Rules rules; | |
522 RuleBasedProxyScriptFetcher fetcher(&rules); | |
523 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
524 | |
525 ProxyConfig config; | |
526 config.set_auto_detect(true); | |
527 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
528 | |
529 rules.AddFailDownloadRule("http://wpad/wpad.dat"); | |
530 rules.AddFailDownloadRule("http://custom/proxy.pac"); | |
531 | |
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()); | |
538 } | |
539 | |
540 // Fails at WPAD (downloading), and fails at custom PAC (parsing). | |
541 TEST(ProxyScriptDeciderTest, AutodetectFailCustomFails2) { | |
542 Rules rules; | |
543 RuleBasedProxyScriptFetcher fetcher(&rules); | |
544 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
545 | |
546 ProxyConfig config; | |
547 config.set_auto_detect(true); | |
548 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
549 | |
550 rules.AddFailDownloadRule("http://wpad/wpad.dat"); | |
551 rules.AddFailParsingRule("http://custom/proxy.pac"); | |
552 | |
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()); | |
559 } | |
560 | |
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) { | |
565 Rules rules; | |
566 RuleBasedProxyScriptFetcher fetcher(&rules); | |
567 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
568 | |
569 ProxyConfig config; | |
570 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
571 | |
572 rules.AddFailDownloadRule("http://custom/proxy.pac"); | |
573 | |
574 TestCompletionCallback callback; | |
575 CapturingNetLog log; | |
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())); | |
580 | |
581 EXPECT_EQ(kFailedDownloading, callback.WaitForResult()); | |
582 EXPECT_EQ(NULL, decider.script_data()); | |
583 | |
584 // Check the NetLog was filled correctly. | |
585 CapturingNetLog::CapturedEntryList entries; | |
586 log.GetEntries(&entries); | |
587 | |
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)); | |
601 } | |
602 | |
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) { | |
607 Rules rules; | |
608 RuleBasedProxyScriptFetcher fetcher(&rules); | |
609 DoNothingDhcpProxyScriptFetcher dhcp_fetcher; | |
610 | |
611 ProxyConfig config; | |
612 config.set_pac_url(GURL("http://custom/proxy.pac")); | |
613 | |
614 rules.AddFailDownloadRule("http://custom/proxy.pac"); | |
615 | |
616 TestCompletionCallback callback; | |
617 CapturingNetLog log; | |
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()); | |
623 | |
624 // Check the NetLog was filled correctly. | |
625 CapturingNetLog::CapturedEntryList entries; | |
626 log.GetEntries(&entries); | |
627 | |
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)); | |
637 } | |
638 | |
639 class SynchronousSuccessDhcpFetcher : public DhcpProxyScriptFetcher { | |
640 public: | |
641 explicit SynchronousSuccessDhcpFetcher(const base::string16& expected_text) | |
642 : gurl_("http://dhcppac/"), expected_text_(expected_text) { | |
643 } | |
644 | |
645 int Fetch(base::string16* utf16_text, | |
646 const CompletionCallback& callback) override { | |
647 *utf16_text = expected_text_; | |
648 return OK; | |
649 } | |
650 | |
651 void Cancel() override {} | |
652 | |
653 const GURL& GetPacURL() const override { return gurl_; } | |
654 | |
655 const base::string16& expected_text() const { | |
656 return expected_text_; | |
657 } | |
658 | |
659 private: | |
660 GURL gurl_; | |
661 base::string16 expected_text_; | |
662 | |
663 DISALLOW_COPY_AND_ASSIGN(SynchronousSuccessDhcpFetcher); | |
664 }; | |
665 | |
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. | |
670 | |
671 TEST(ProxyScriptDeciderTest, AutodetectDhcpSuccess) { | |
672 Rules rules; | |
673 RuleBasedProxyScriptFetcher fetcher(&rules); | |
674 SynchronousSuccessDhcpFetcher dhcp_fetcher( | |
675 base::WideToUTF16(L"http://bingo/!FindProxyForURL")); | |
676 | |
677 ProxyConfig config; | |
678 config.set_auto_detect(true); | |
679 | |
680 rules.AddSuccessRule("http://bingo/"); | |
681 rules.AddFailDownloadRule("http://wpad/wpad.dat"); | |
682 | |
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()); | |
689 | |
690 EXPECT_TRUE(decider.effective_config().has_pac_url()); | |
691 EXPECT_EQ(GURL("http://dhcppac/"), decider.effective_config().pac_url()); | |
692 } | |
693 | |
694 TEST(ProxyScriptDeciderTest, AutodetectDhcpFailParse) { | |
695 Rules rules; | |
696 RuleBasedProxyScriptFetcher fetcher(&rules); | |
697 SynchronousSuccessDhcpFetcher dhcp_fetcher( | |
698 base::WideToUTF16(L"http://bingo/!invalid-script")); | |
699 | |
700 ProxyConfig config; | |
701 config.set_auto_detect(true); | |
702 | |
703 rules.AddFailParsingRule("http://bingo/"); | |
704 rules.AddFailDownloadRule("http://wpad/wpad.dat"); | |
705 | |
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()); | |
713 | |
714 EXPECT_FALSE(decider.effective_config().has_pac_url()); | |
715 } | |
716 | |
717 class AsyncFailDhcpFetcher | |
718 : public DhcpProxyScriptFetcher, | |
719 public base::SupportsWeakPtr<AsyncFailDhcpFetcher> { | |
720 public: | |
721 AsyncFailDhcpFetcher() {} | |
722 ~AsyncFailDhcpFetcher() override {} | |
723 | |
724 int Fetch(base::string16* utf16_text, | |
725 const CompletionCallback& callback) override { | |
726 callback_ = callback; | |
727 base::MessageLoop::current()->PostTask( | |
728 FROM_HERE, | |
729 base::Bind(&AsyncFailDhcpFetcher::CallbackWithFailure, AsWeakPtr())); | |
730 return ERR_IO_PENDING; | |
731 } | |
732 | |
733 void Cancel() override { callback_.Reset(); } | |
734 | |
735 const GURL& GetPacURL() const override { return dummy_gurl_; } | |
736 | |
737 void CallbackWithFailure() { | |
738 if (!callback_.is_null()) | |
739 callback_.Run(ERR_PAC_NOT_IN_DHCP); | |
740 } | |
741 | |
742 private: | |
743 GURL dummy_gurl_; | |
744 CompletionCallback callback_; | |
745 }; | |
746 | |
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. | |
752 Rules rules; | |
753 RuleBasedProxyScriptFetcher fetcher(&rules); | |
754 | |
755 scoped_ptr<AsyncFailDhcpFetcher> dhcp_fetcher(new AsyncFailDhcpFetcher()); | |
756 | |
757 ProxyConfig config; | |
758 config.set_auto_detect(true); | |
759 rules.AddFailDownloadRule("http://wpad/wpad.dat"); | |
760 | |
761 TestCompletionCallback callback; | |
762 | |
763 // Scope so ProxyScriptDecider gets destroyed early. | |
764 { | |
765 ProxyScriptDecider decider(&fetcher, dhcp_fetcher.get(), NULL); | |
766 decider.Start(config, base::TimeDelta(), true, callback.callback()); | |
767 } | |
768 | |
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 | |
772 // no longer valid. | |
773 base::MessageLoop::current()->RunUntilIdle(); | |
774 } | |
775 | |
776 } // namespace | |
777 } // namespace net | |
OLD | NEW |