1 // Copyright 2012 The Chromium Authors
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_resolution/configured_proxy_resolution_service.h"
6
7 #include <cstdarg>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/check.h"
14 #include "base/format_macros.h"
15 #include "base/functional/bind.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/run_loop.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/test/metrics/histogram_tester.h"
22 #include "base/time/time.h"
23 #include "net/base/mock_network_change_notifier.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/network_change_notifier.h"
26 #include "net/base/network_isolation_key.h"
27 #include "net/base/proxy_delegate.h"
28 #include "net/base/proxy_server.h"
29 #include "net/base/proxy_string_util.h"
30 #include "net/base/test_completion_callback.h"
31 #include "net/log/net_log.h"
32 #include "net/log/net_log_event_type.h"
33 #include "net/log/net_log_with_source.h"
34 #include "net/log/test_net_log.h"
35 #include "net/log/test_net_log_util.h"
36 #include "net/proxy_resolution/dhcp_pac_file_fetcher.h"
37 #include "net/proxy_resolution/mock_pac_file_fetcher.h"
38 #include "net/proxy_resolution/mock_proxy_resolver.h"
39 #include "net/proxy_resolution/pac_file_fetcher.h"
40 #include "net/proxy_resolution/proxy_config_service.h"
41 #include "net/proxy_resolution/proxy_resolution_request.h"
42 #include "net/proxy_resolution/proxy_resolver.h"
43 #include "net/test/gtest_util.h"
44 #include "net/test/test_with_task_environment.h"
45 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
46 #include "testing/gmock/include/gmock/gmock.h"
47 #include "testing/gtest/include/gtest/gtest.h"
48 #include "url/gurl.h"
49
50 using testing::ElementsAre;
51 using testing::Key;
52
53 using net::test::IsError;
54 using net::test::IsOk;
55
56 // TODO(eroman): Write a test which exercises
57 // ConfiguredProxyResolutionService::SuspendAllPendingRequests().
58 namespace net {
59 namespace {
60
61 // This polling policy will decide to poll every 1 ms.
62 class ImmediatePollPolicy
63 : public ConfiguredProxyResolutionService::PacPollPolicy {
64 public:
65 ImmediatePollPolicy() = default;
66
67 ImmediatePollPolicy(const ImmediatePollPolicy&) = delete;
68 ImmediatePollPolicy& operator=(const ImmediatePollPolicy&) = delete;
69
GetNextDelay(int error,base::TimeDelta current_delay,base::TimeDelta * next_delay) const70 Mode GetNextDelay(int error,
71 base::TimeDelta current_delay,
72 base::TimeDelta* next_delay) const override {
73 *next_delay = base::Milliseconds(1);
74 return MODE_USE_TIMER;
75 }
76 };
77
78 // This polling policy chooses a fantastically large delay. In other words, it
79 // will never trigger a poll
80 class NeverPollPolicy : public ConfiguredProxyResolutionService::PacPollPolicy {
81 public:
82 NeverPollPolicy() = default;
83
84 NeverPollPolicy(const NeverPollPolicy&) = delete;
85 NeverPollPolicy& operator=(const NeverPollPolicy&) = delete;
86
GetNextDelay(int error,base::TimeDelta current_delay,base::TimeDelta * next_delay) const87 Mode GetNextDelay(int error,
88 base::TimeDelta current_delay,
89 base::TimeDelta* next_delay) const override {
90 *next_delay = base::Days(60);
91 return MODE_USE_TIMER;
92 }
93 };
94
95 // This polling policy starts a poll immediately after network activity.
96 class ImmediateAfterActivityPollPolicy
97 : public ConfiguredProxyResolutionService::PacPollPolicy {
98 public:
99 ImmediateAfterActivityPollPolicy() = default;
100
101 ImmediateAfterActivityPollPolicy(const ImmediateAfterActivityPollPolicy&) =
102 delete;
103 ImmediateAfterActivityPollPolicy& operator=(
104 const ImmediateAfterActivityPollPolicy&) = delete;
105
GetNextDelay(int error,base::TimeDelta current_delay,base::TimeDelta * next_delay) const106 Mode GetNextDelay(int error,
107 base::TimeDelta current_delay,
108 base::TimeDelta* next_delay) const override {
109 *next_delay = base::TimeDelta();
110 return MODE_START_AFTER_ACTIVITY;
111 }
112 };
113
114 // This test fixture is used to partially disable the background polling done by
115 // the ConfiguredProxyResolutionService (which it uses to detect whenever its
116 // PAC script contents or WPAD results have changed).
117 //
118 // We disable the feature by setting the poll interval to something really
119 // large, so it will never actually be reached even on the slowest bots that run
120 // these tests.
121 //
122 // We disable the polling in order to avoid any timing dependencies in the
123 // tests. If the bot were to run the tests very slowly and we hadn't disabled
124 // polling, then it might start a background re-try in the middle of our test
125 // and confuse our expectations leading to flaky failures.
126 //
127 // The tests which verify the polling code re-enable the polling behavior but
128 // are careful to avoid timing problems.
129 class ConfiguredProxyResolutionServiceTest : public ::testing::Test,
130 public WithTaskEnvironment {
131 protected:
ConfiguredProxyResolutionServiceTest()132 ConfiguredProxyResolutionServiceTest()
133 : WithTaskEnvironment(
134 base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
135
SetUp()136 void SetUp() override {
137 testing::Test::SetUp();
138 previous_policy_ =
139 ConfiguredProxyResolutionService::set_pac_script_poll_policy(
140 &never_poll_policy_);
141 }
142
TearDown()143 void TearDown() override {
144 // Restore the original policy.
145 ConfiguredProxyResolutionService::set_pac_script_poll_policy(
146 previous_policy_);
147 testing::Test::TearDown();
148 }
149
150 private:
151 NeverPollPolicy never_poll_policy_;
152 raw_ptr<const ConfiguredProxyResolutionService::PacPollPolicy>
153 previous_policy_;
154 };
155
156 const char kValidPacScript1[] = "pac-script-v1-FindProxyForURL";
157 const char16_t kValidPacScript116[] = u"pac-script-v1-FindProxyForURL";
158 const char kValidPacScript2[] = "pac-script-v2-FindProxyForURL";
159 const char16_t kValidPacScript216[] = u"pac-script-v2-FindProxyForURL";
160
161 class MockProxyConfigService : public ProxyConfigService {
162 public:
MockProxyConfigService(const ProxyConfig & config)163 explicit MockProxyConfigService(const ProxyConfig& config)
164 : config_(
165 ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS)) {}
166
MockProxyConfigService(const std::string & pac_url)167 explicit MockProxyConfigService(const std::string& pac_url)
168 : config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url)),
169 TRAFFIC_ANNOTATION_FOR_TESTS) {}
170
AddObserver(Observer * observer)171 void AddObserver(Observer* observer) override {
172 observers_.AddObserver(observer);
173 }
174
RemoveObserver(Observer * observer)175 void RemoveObserver(Observer* observer) override {
176 observers_.RemoveObserver(observer);
177 }
178
GetLatestProxyConfig(ProxyConfigWithAnnotation * results)179 ConfigAvailability GetLatestProxyConfig(
180 ProxyConfigWithAnnotation* results) override {
181 if (availability_ == CONFIG_VALID)
182 *results = config_;
183 return availability_;
184 }
185
SetConfig(const ProxyConfigWithAnnotation & config)186 void SetConfig(const ProxyConfigWithAnnotation& config) {
187 availability_ = CONFIG_VALID;
188 config_ = config;
189 for (auto& observer : observers_)
190 observer.OnProxyConfigChanged(config_, availability_);
191 }
192
SetPacUrlConfig(base::StringPiece pac_url)193 void SetPacUrlConfig(base::StringPiece pac_url) {
194 SetConfig(ProxyConfigWithAnnotation(
195 ProxyConfig::CreateFromCustomPacURL(GURL(pac_url)),
196 TRAFFIC_ANNOTATION_FOR_TESTS));
197 }
198
199 private:
200 ConfigAvailability availability_ = CONFIG_VALID;
201 ProxyConfigWithAnnotation config_;
202 base::ObserverList<Observer, true>::Unchecked observers_;
203 };
204
205 // A test network delegate that exercises the OnResolveProxy callback.
206 class TestResolveProxyDelegate : public ProxyDelegate {
207 public:
OnResolveProxy(const GURL & url,const std::string & method,const ProxyRetryInfoMap & proxy_retry_info,ProxyInfo * result)208 void OnResolveProxy(const GURL& url,
209 const std::string& method,
210 const ProxyRetryInfoMap& proxy_retry_info,
211 ProxyInfo* result) override {
212 method_ = method;
213 num_resolve_proxy_called_++;
214 proxy_retry_info_ = proxy_retry_info;
215 DCHECK(!add_proxy_ || !remove_proxy_);
216 if (add_proxy_) {
217 result->UseNamedProxy("delegate_proxy.com");
218 } else if (remove_proxy_) {
219 result->UseDirect();
220 }
221 }
222
num_resolve_proxy_called() const223 int num_resolve_proxy_called() const { return num_resolve_proxy_called_; }
224
method() const225 const std::string& method() const { return method_; }
226
set_add_proxy(bool add_proxy)227 void set_add_proxy(bool add_proxy) { add_proxy_ = add_proxy; }
228
set_remove_proxy(bool remove_proxy)229 void set_remove_proxy(bool remove_proxy) { remove_proxy_ = remove_proxy; }
230
proxy_retry_info() const231 const ProxyRetryInfoMap& proxy_retry_info() const {
232 return proxy_retry_info_;
233 }
234
OnFallback(const ProxyServer & bad_proxy,int net_error)235 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
236
OnBeforeTunnelRequest(const ProxyServer & proxy_server,HttpRequestHeaders * extra_headers)237 void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
238 HttpRequestHeaders* extra_headers) override {}
239
OnTunnelHeadersReceived(const ProxyServer & proxy_server,const HttpResponseHeaders & response_headers)240 Error OnTunnelHeadersReceived(
241 const ProxyServer& proxy_server,
242 const HttpResponseHeaders& response_headers) override {
243 return OK;
244 }
245
246 private:
247 int num_resolve_proxy_called_ = 0;
248 bool add_proxy_ = false;
249 bool remove_proxy_ = false;
250 std::string method_;
251 ProxyRetryInfoMap proxy_retry_info_;
252 };
253
254 // A test network delegate that exercises the OnProxyFallback callback.
255 class TestProxyFallbackProxyDelegate : public ProxyDelegate {
256 public:
257 // ProxyDelegate implementation:
OnResolveProxy(const GURL & url,const std::string & method,const ProxyRetryInfoMap & proxy_retry_info,ProxyInfo * result)258 void OnResolveProxy(const GURL& url,
259 const std::string& method,
260 const ProxyRetryInfoMap& proxy_retry_info,
261 ProxyInfo* result) override {}
262
OnFallback(const ProxyServer & bad_proxy,int net_error)263 void OnFallback(const ProxyServer& bad_proxy, int net_error) override {
264 proxy_server_ = bad_proxy;
265 last_proxy_fallback_net_error_ = net_error;
266 num_proxy_fallback_called_++;
267 }
268
OnBeforeTunnelRequest(const ProxyServer & proxy_server,HttpRequestHeaders * extra_headers)269 void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
270 HttpRequestHeaders* extra_headers) override {}
271
OnTunnelHeadersReceived(const ProxyServer & proxy_server,const HttpResponseHeaders & response_headers)272 Error OnTunnelHeadersReceived(
273 const ProxyServer& proxy_server,
274 const HttpResponseHeaders& response_headers) override {
275 return OK;
276 }
277
num_proxy_fallback_called() const278 bool num_proxy_fallback_called() const { return num_proxy_fallback_called_; }
279
proxy_server() const280 const ProxyServer& proxy_server() const { return proxy_server_; }
281
last_proxy_fallback_net_error() const282 int last_proxy_fallback_net_error() const {
283 return last_proxy_fallback_net_error_;
284 }
285
286 private:
287 int num_proxy_fallback_called_ = 0;
288 ProxyServer proxy_server_;
289 int last_proxy_fallback_net_error_ = OK;
290 };
291
292 using JobMap = std::map<GURL, MockAsyncProxyResolver::Job*>;
293
294 // Given a jobmap and a list of target URLs |urls|, asserts that the set of URLs
295 // of the jobs appearing in |list| is exactly the set of URLs in |urls|.
GetJobsForURLs(const JobMap & map,const std::vector<GURL> & urls)296 JobMap GetJobsForURLs(const JobMap& map, const std::vector<GURL>& urls) {
297 size_t a = urls.size();
298 size_t b = map.size();
299 if (a != b) {
300 ADD_FAILURE() << "map size (" << map.size() << ") != urls size ("
301 << urls.size() << ")";
302 return map;
303 }
304 for (const auto& it : urls) {
305 if (map.count(it) != 1U) {
306 ADD_FAILURE() << "url not in map: " << it.spec();
307 break;
308 }
309 }
310 return map;
311 }
312
313 // Given a MockAsyncProxyResolver |resolver| and some GURLs, validates that the
314 // set of pending request URLs for |resolver| is exactly the supplied list of
315 // URLs and returns a map from URLs to the corresponding pending jobs.
GetPendingJobsForURLs(const MockAsyncProxyResolver & resolver,const GURL & url1=GURL (),const GURL & url2=GURL (),const GURL & url3=GURL ())316 JobMap GetPendingJobsForURLs(const MockAsyncProxyResolver& resolver,
317 const GURL& url1 = GURL(),
318 const GURL& url2 = GURL(),
319 const GURL& url3 = GURL()) {
320 std::vector<GURL> urls;
321 if (!url1.is_empty())
322 urls.push_back(url1);
323 if (!url2.is_empty())
324 urls.push_back(url2);
325 if (!url3.is_empty())
326 urls.push_back(url3);
327
328 JobMap map;
329 for (MockAsyncProxyResolver::Job* it : resolver.pending_jobs()) {
330 DCHECK(it);
331 map[it->url()] = it;
332 }
333
334 return GetJobsForURLs(map, urls);
335 }
336
337 // Given a MockAsyncProxyResolver |resolver| and some GURLs, validates that the
338 // set of cancelled request URLs for |resolver| is exactly the supplied list of
339 // URLs and returns a map from URLs to the corresponding cancelled jobs.
GetCancelledJobsForURLs(const MockAsyncProxyResolver & resolver,const GURL & url1=GURL (),const GURL & url2=GURL (),const GURL & url3=GURL ())340 JobMap GetCancelledJobsForURLs(const MockAsyncProxyResolver& resolver,
341 const GURL& url1 = GURL(),
342 const GURL& url2 = GURL(),
343 const GURL& url3 = GURL()) {
344 std::vector<GURL> urls;
345 if (!url1.is_empty())
346 urls.push_back(url1);
347 if (!url2.is_empty())
348 urls.push_back(url2);
349 if (!url3.is_empty())
350 urls.push_back(url3);
351
352 JobMap map;
353 for (const std::unique_ptr<MockAsyncProxyResolver::Job>& it :
354 resolver.cancelled_jobs()) {
355 DCHECK(it);
356 map[it->url()] = it.get();
357 }
358
359 return GetJobsForURLs(map, urls);
360 }
361
362 } // namespace
363
TEST_F(ConfiguredProxyResolutionServiceTest,Direct)364 TEST_F(ConfiguredProxyResolutionServiceTest, Direct) {
365 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
366 auto* factory_ptr = factory.get();
367 ConfiguredProxyResolutionService service(
368 std::make_unique<MockProxyConfigService>(ProxyConfig::CreateDirect()),
369 std::move(factory), nullptr, /*quick_check_enabled=*/true);
370
371 GURL url("http://www.google.com/");
372
373 ProxyInfo info;
374 TestCompletionCallback callback;
375 RecordingNetLogObserver net_log_observer;
376 std::unique_ptr<ProxyResolutionRequest> request;
377 int rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
378 &info, callback.callback(), &request,
379 NetLogWithSource::Make(NetLogSourceType::NONE));
380 EXPECT_THAT(rv, IsOk());
381 EXPECT_TRUE(factory_ptr->pending_requests().empty());
382
383 EXPECT_TRUE(info.is_direct());
384 EXPECT_TRUE(info.proxy_resolve_start_time().is_null());
385 EXPECT_TRUE(info.proxy_resolve_end_time().is_null());
386
387 // Check the NetLog was filled correctly.
388 auto entries = net_log_observer.GetEntries();
389
390 EXPECT_EQ(3u, entries.size());
391 EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
392 NetLogEventType::PROXY_RESOLUTION_SERVICE));
393 EXPECT_TRUE(LogContainsEvent(
394 entries, 1, NetLogEventType::PROXY_RESOLUTION_SERVICE_RESOLVED_PROXY_LIST,
395 NetLogEventPhase::NONE));
396 EXPECT_TRUE(LogContainsEndEvent(entries, 2,
397 NetLogEventType::PROXY_RESOLUTION_SERVICE));
398 }
399
TEST_F(ConfiguredProxyResolutionServiceTest,OnResolveProxyCallbackAddProxy)400 TEST_F(ConfiguredProxyResolutionServiceTest, OnResolveProxyCallbackAddProxy) {
401 ProxyConfig config;
402 config.proxy_rules().ParseFromString("badproxy:8080,foopy1:8080");
403 config.set_auto_detect(false);
404 config.proxy_rules().bypass_rules.ParseFromString("*.org");
405
406 ConfiguredProxyResolutionService service(
407 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
408 /*quick_check_enabled=*/true);
409
410 GURL url("http://www.google.com/");
411 GURL bypass_url("http://internet.org");
412
413 ProxyInfo info;
414 TestCompletionCallback callback;
415 NetLogWithSource net_log_with_source =
416 NetLogWithSource::Make(NetLogSourceType::NONE);
417
418 // First, warm up the ConfiguredProxyResolutionService and fake an error to
419 // mark the first server as bad.
420 std::unique_ptr<ProxyResolutionRequest> request;
421 int rv =
422 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
423 callback.callback(), &request, net_log_with_source);
424 EXPECT_THAT(rv, IsOk());
425 EXPECT_EQ("badproxy:8080", ProxyServerToProxyUri(info.proxy_server()));
426
427 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
428 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
429
430 service.ReportSuccess(info);
431
432 // Verify that network delegate is invoked.
433 TestResolveProxyDelegate delegate;
434 service.SetProxyDelegate(&delegate);
435 rv = service.ResolveProxy(url, "GET", NetworkAnonymizationKey(), &info,
436 callback.callback(), &request, net_log_with_source);
437 EXPECT_EQ(1, delegate.num_resolve_proxy_called());
438 EXPECT_THAT(delegate.proxy_retry_info(), ElementsAre(Key("badproxy:8080")));
439 EXPECT_EQ(delegate.method(), "GET");
440
441 // Verify that the ProxyDelegate's behavior is stateless across
442 // invocations of ResolveProxy. Start by having the callback add a proxy
443 // and checking that subsequent jobs are not affected.
444 delegate.set_add_proxy(true);
445
446 // Callback should interpose:
447 rv = service.ResolveProxy(url, "GET", NetworkAnonymizationKey(), &info,
448 callback.callback(), &request, net_log_with_source);
449 EXPECT_FALSE(info.is_direct());
450 EXPECT_EQ(info.proxy_server().host_port_pair().host(), "delegate_proxy.com");
451 delegate.set_add_proxy(false);
452
453 // Check non-bypassed URL:
454 rv = service.ResolveProxy(url, "GET", NetworkAnonymizationKey(), &info,
455 callback.callback(), &request, net_log_with_source);
456 EXPECT_FALSE(info.is_direct());
457 EXPECT_EQ(info.proxy_server().host_port_pair().host(), "foopy1");
458
459 // Check bypassed URL:
460 rv = service.ResolveProxy(bypass_url, "GET", NetworkAnonymizationKey(), &info,
461 callback.callback(), &request, net_log_with_source);
462 EXPECT_TRUE(info.is_direct());
463 }
464
TEST_F(ConfiguredProxyResolutionServiceTest,OnResolveProxyCallbackRemoveProxy)465 TEST_F(ConfiguredProxyResolutionServiceTest,
466 OnResolveProxyCallbackRemoveProxy) {
467 // Same as OnResolveProxyCallbackAddProxy, but verify that the
468 // ProxyDelegate's behavior is stateless across invocations after it
469 // *removes* a proxy.
470 ProxyConfig config;
471 config.proxy_rules().ParseFromString("foopy1:8080");
472 config.set_auto_detect(false);
473 config.proxy_rules().bypass_rules.ParseFromString("*.org");
474
475 ConfiguredProxyResolutionService service(
476 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
477 /*quick_check_enabled=*/true);
478
479 GURL url("http://www.google.com/");
480 GURL bypass_url("http://internet.org");
481
482 ProxyInfo info;
483 TestCompletionCallback callback;
484 NetLogWithSource net_log_with_source =
485 NetLogWithSource::Make(NetLogSourceType::NONE);
486
487 // First, warm up the ConfiguredProxyResolutionService.
488 std::unique_ptr<ProxyResolutionRequest> request;
489 int rv =
490 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
491 callback.callback(), &request, net_log_with_source);
492 EXPECT_THAT(rv, IsOk());
493
494 TestResolveProxyDelegate delegate;
495 service.SetProxyDelegate(&delegate);
496 delegate.set_remove_proxy(true);
497
498 // Callback should interpose:
499 rv = service.ResolveProxy(url, "GET", NetworkAnonymizationKey(), &info,
500 callback.callback(), &request, net_log_with_source);
501 EXPECT_TRUE(info.is_direct());
502 delegate.set_remove_proxy(false);
503
504 // Check non-bypassed URL:
505 rv = service.ResolveProxy(url, "GET", NetworkAnonymizationKey(), &info,
506 callback.callback(), &request, net_log_with_source);
507 EXPECT_FALSE(info.is_direct());
508 EXPECT_EQ(info.proxy_server().host_port_pair().host(), "foopy1");
509
510 // Check bypassed URL:
511 rv = service.ResolveProxy(bypass_url, "GET", NetworkAnonymizationKey(), &info,
512 callback.callback(), &request, net_log_with_source);
513 EXPECT_TRUE(info.is_direct());
514 }
515
516 // Test callback that deletes an item when called. This is used to test various
517 // permutations of important objects being deleted in the middle of a series of
518 // requests.
519 template <typename T>
520 class DeletingCallback : public TestCompletionCallbackBase {
521 public:
522 explicit DeletingCallback(std::unique_ptr<T>* deletee);
523
524 DeletingCallback(const DeletingCallback&) = delete;
525 DeletingCallback& operator=(const DeletingCallback&) = delete;
526
527 ~DeletingCallback() override;
528
callback()529 CompletionOnceCallback callback() {
530 return base::BindOnce(&DeletingCallback::DeleteItem,
531 base::Unretained(this));
532 }
533
534 private:
DeleteItem(int result)535 void DeleteItem(int result) {
536 deletee_->reset();
537 SetResult(result);
538 }
539
540 raw_ptr<std::unique_ptr<T>> deletee_;
541 };
542
543 template <typename T>
DeletingCallback(std::unique_ptr<T> * deletee)544 DeletingCallback<T>::DeletingCallback(std::unique_ptr<T>* deletee)
545 : deletee_(deletee) {}
546
547 template <typename T>
548 DeletingCallback<T>::~DeletingCallback() = default;
549
550 // Test that the ConfiguredProxyResolutionService correctly handles the case
551 // where a request callback deletes another request.
TEST_F(ConfiguredProxyResolutionServiceTest,CallbackDeletesRequest)552 TEST_F(ConfiguredProxyResolutionServiceTest, CallbackDeletesRequest) {
553 auto config_service =
554 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
555 MockAsyncProxyResolver resolver;
556 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
557 auto* factory_ptr = factory.get();
558
559 std::unique_ptr<ConfiguredProxyResolutionService> service =
560 std::make_unique<ConfiguredProxyResolutionService>(
561 std::move(config_service), std::move(factory), nullptr,
562 /*quick_check_enabled=*/true);
563
564 GURL url("http://www.google.com/");
565 GURL url2("http://www.example.com/");
566
567 ProxyInfo info;
568 std::unique_ptr<ProxyResolutionRequest> request, request2;
569 DeletingCallback<ProxyResolutionRequest> callback(&request2);
570 net::CompletionOnceCallback callback2 =
571 base::BindOnce([](int result) { ASSERT_FALSE(true); });
572
573 int rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
574 &info, callback.callback(), &request,
575 NetLogWithSource());
576 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
577
578 rv = service->ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
579 &info, std::move(callback2), &request2,
580 NetLogWithSource());
581 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
582
583 // Run pending requests.
584 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
585 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
586 factory_ptr->pending_requests()[0]->script_data()->url());
587 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
588
589 ASSERT_EQ(2u, resolver.pending_jobs().size());
590 // Job order is nondeterministic, as requests are stored in an std::set, so
591 // this loop figures out which one is the correct one to start.
592 int deleting_job = 2;
593 for (int i = 0; i < 2; i++) {
594 if (resolver.pending_jobs()[i]->url() == url) {
595 deleting_job = i;
596 break;
597 }
598 ASSERT_LE(i, 1); // The loop should never actually make it to the end.
599 }
600
601 // Set the result in proxy resolver.
602 resolver.pending_jobs()[deleting_job]->results()->UseNamedProxy("foopy");
603 resolver.pending_jobs()[deleting_job]->CompleteNow(OK);
604
605 //// Only one of the callbacks should have been run:
606 EXPECT_TRUE(callback.have_result());
607 EXPECT_THAT(callback.WaitForResult(), IsOk());
608
609 ASSERT_EQ(0u, resolver.pending_jobs().size());
610 ASSERT_EQ(1u, resolver.cancelled_jobs().size());
611 ASSERT_EQ(url2, resolver.cancelled_jobs()[0]->url());
612 }
613
614 // Test that the ConfiguredProxyResolutionService correctly handles the case
615 // where a request callback deletes another request. (Triggered by the loop in
616 // ConfiguredProxyResolutionService's destructor).
TEST_F(ConfiguredProxyResolutionServiceTest,CallbackDeletesRequestDuringDestructor)617 TEST_F(ConfiguredProxyResolutionServiceTest,
618 CallbackDeletesRequestDuringDestructor) {
619 auto config_service =
620 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
621
622 MockAsyncProxyResolver resolver;
623 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
624
625 std::unique_ptr<ConfiguredProxyResolutionService> service =
626 std::make_unique<ConfiguredProxyResolutionService>(
627 std::move(config_service), std::move(factory), nullptr,
628 /*quick_check_enabled=*/true);
629
630 GURL url("http://www.google.com/");
631
632 ProxyInfo info;
633 std::unique_ptr<ProxyResolutionRequest> request, request2;
634 DeletingCallback<ProxyResolutionRequest> callback(&request2),
635 callback2(&request);
636
637 int rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
638 &info, callback.callback(), &request,
639 NetLogWithSource());
640 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
641
642 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
643 &info, callback2.callback(), &request2,
644 NetLogWithSource());
645 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
646
647 // Make sure that ProxyResolutionServices is deleted before the requests, as
648 // this triggers completion of the pending requests.
649 service.reset();
650
651 // Only one of the callbacks should have been run:
652 EXPECT_TRUE(callback.have_result() ^ callback2.have_result());
653
654 // Callbacks run during destruction of ConfiguredProxyResolutionService for
655 // Requests that have not been started are called with net::ERR_ABORTED
656 if (callback.have_result()) {
657 EXPECT_THAT(callback.WaitForResult(),
658 IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
659 }
660 if (callback2.have_result()) {
661 EXPECT_THAT(callback2.WaitForResult(),
662 IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
663 }
664 }
665
666 // Test that the ConfiguredProxyResolutionService correctly handles the case
667 // where a request callback deletes its own handle.
TEST_F(ConfiguredProxyResolutionServiceTest,CallbackDeletesSelf)668 TEST_F(ConfiguredProxyResolutionServiceTest, CallbackDeletesSelf) {
669 auto config_service =
670 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
671
672 MockAsyncProxyResolver resolver;
673 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
674 auto* factory_ptr = factory.get();
675
676 std::unique_ptr<ConfiguredProxyResolutionService> service =
677 std::make_unique<ConfiguredProxyResolutionService>(
678 std::move(config_service), std::move(factory), nullptr,
679 /*quick_check_enabled=*/true);
680
681 GURL url("http://www.google.com/");
682 ProxyInfo info;
683
684 std::unique_ptr<ProxyResolutionRequest> request1;
685 TestCompletionCallback callback1;
686 int rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
687 &info, callback1.callback(), &request1,
688 NetLogWithSource());
689 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
690
691 GURL url2("http://www.example.com/");
692 std::unique_ptr<ProxyResolutionRequest> request2;
693 DeletingCallback<ProxyResolutionRequest> callback2(&request2);
694 rv = service->ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
695 &info, callback2.callback(), &request2,
696 NetLogWithSource());
697 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
698
699 std::unique_ptr<ProxyResolutionRequest> request3;
700 TestCompletionCallback callback3;
701 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
702 &info, callback3.callback(), &request3,
703 NetLogWithSource());
704 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
705
706 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
707 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
708 factory_ptr->pending_requests()[0]->script_data()->url());
709 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
710
711 ASSERT_EQ(3u, resolver.pending_jobs().size());
712 // Job order is nondeterministic, as requests are stored in an std::set, so
713 // this loop figures out which one is the correct one to start.
714 int self_deleting_job = 3;
715 for (int i = 0; i < 3; i++) {
716 if (resolver.pending_jobs()[i]->url() == url2) {
717 self_deleting_job = i;
718 break;
719 }
720 ASSERT_LE(i, 2); // The loop should never actually make it to the end.
721 }
722
723 // Set the result in proxy resolver.
724 resolver.pending_jobs()[self_deleting_job]->results()->UseNamedProxy("foopy");
725 resolver.pending_jobs()[self_deleting_job]->CompleteNow(OK);
726
727 ASSERT_EQ(2u, resolver.pending_jobs().size());
728 ASSERT_EQ(0u, resolver.cancelled_jobs().size());
729 ASSERT_EQ(url, resolver.pending_jobs()[0]->url());
730 ASSERT_EQ(url, resolver.pending_jobs()[1]->url());
731 }
732
733 // Test that the ConfiguredProxyResolutionService correctly handles the case
734 // where a request callback deletes its own handle, when triggered by
735 // ConfiguredProxyResolutionService's destructor.
TEST_F(ConfiguredProxyResolutionServiceTest,CallbackDeletesSelfDuringDestructor)736 TEST_F(ConfiguredProxyResolutionServiceTest,
737 CallbackDeletesSelfDuringDestructor) {
738 auto config_service =
739 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
740
741 MockAsyncProxyResolver resolver;
742 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
743
744 std::unique_ptr<ConfiguredProxyResolutionService> service =
745 std::make_unique<ConfiguredProxyResolutionService>(
746 std::move(config_service), std::move(factory), nullptr,
747 /*quick_check_enabled=*/true);
748
749 GURL url("http://www.google.com/");
750 ProxyInfo info;
751
752 std::unique_ptr<ProxyResolutionRequest> request1;
753 TestCompletionCallback callback1;
754 int rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
755 &info, callback1.callback(), &request1,
756 NetLogWithSource());
757 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
758
759 std::unique_ptr<ProxyResolutionRequest> request2;
760 DeletingCallback<ProxyResolutionRequest> callback2(&request2);
761 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
762 &info, callback2.callback(), &request2,
763 NetLogWithSource());
764 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
765
766 std::unique_ptr<ProxyResolutionRequest> request3;
767 TestCompletionCallback callback3;
768 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
769 &info, callback3.callback(), &request3,
770 NetLogWithSource());
771 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
772
773 service.reset();
774
775 EXPECT_THAT(callback1.WaitForResult(),
776 IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
777 EXPECT_THAT(callback2.WaitForResult(),
778 IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
779 EXPECT_THAT(callback3.WaitForResult(),
780 IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
781 }
782
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyServiceDeletedBeforeRequest)783 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyServiceDeletedBeforeRequest) {
784 auto config_service =
785 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
786
787 MockAsyncProxyResolver resolver;
788 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
789 auto* factory_ptr = factory.get();
790
791 GURL url("http://www.google.com/");
792
793 ProxyInfo info;
794 TestCompletionCallback callback;
795 std::unique_ptr<ProxyResolutionRequest> request;
796
797 int rv;
798 {
799 ConfiguredProxyResolutionService service(std::move(config_service),
800 std::move(factory), nullptr,
801 /*quick_check_enabled=*/true);
802 rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
803 &info, callback.callback(), &request,
804 NetLogWithSource::Make(NetLogSourceType::NONE));
805 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
806
807 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->GetLoadState());
808
809 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
810 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
811 factory_ptr->pending_requests()[0]->script_data()->url());
812 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
813 ASSERT_EQ(1u, resolver.pending_jobs().size());
814 }
815
816 ASSERT_EQ(0u, resolver.pending_jobs().size());
817
818 EXPECT_THAT(callback.WaitForResult(), IsOk());
819 }
820
821 // Test that the ConfiguredProxyResolutionService correctly handles the case
822 // where a request callback deletes the service.
TEST_F(ConfiguredProxyResolutionServiceTest,CallbackDeletesService)823 TEST_F(ConfiguredProxyResolutionServiceTest, CallbackDeletesService) {
824 auto config_service =
825 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
826 auto* config_service_ptr = config_service.get();
827
828 MockAsyncProxyResolver resolver;
829 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
830
831 std::unique_ptr<ConfiguredProxyResolutionService> service =
832 std::make_unique<ConfiguredProxyResolutionService>(
833 std::move(config_service), std::move(factory), nullptr,
834 /*quick_check_enabled=*/true);
835
836 GURL url("http://www.google.com/");
837
838 ProxyInfo info;
839
840 DeletingCallback<ConfiguredProxyResolutionService> callback(&service);
841 std::unique_ptr<ProxyResolutionRequest> request1;
842 int rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
843 &info, callback.callback(), &request1,
844 NetLogWithSource());
845 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
846
847 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request1->GetLoadState());
848
849 TestCompletionCallback callback2;
850 std::unique_ptr<ProxyResolutionRequest> request2;
851 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
852 &info, callback2.callback(), &request2,
853 NetLogWithSource());
854 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
855
856 TestCompletionCallback callback3;
857 std::unique_ptr<ProxyResolutionRequest> request3;
858 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
859 &info, callback3.callback(), &request3,
860 NetLogWithSource());
861 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
862
863 config_service_ptr->SetConfig(ProxyConfigWithAnnotation(
864 ProxyConfig::CreateDirect(), TRAFFIC_ANNOTATION_FOR_TESTS));
865
866 ASSERT_EQ(0u, resolver.pending_jobs().size());
867 ASSERT_THAT(callback.WaitForResult(), IsOk());
868 ASSERT_THAT(callback2.WaitForResult(), IsOk());
869 ASSERT_THAT(callback3.WaitForResult(), IsOk());
870 }
871
TEST_F(ConfiguredProxyResolutionServiceTest,PAC)872 TEST_F(ConfiguredProxyResolutionServiceTest, PAC) {
873 auto config_service =
874 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
875
876 MockAsyncProxyResolver resolver;
877 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
878 auto* factory_ptr = factory.get();
879
880 ConfiguredProxyResolutionService service(std::move(config_service),
881 std::move(factory), nullptr,
882 /*quick_check_enabled=*/true);
883
884 GURL url("http://www.google.com/");
885
886 ProxyInfo info;
887 TestCompletionCallback callback;
888 std::unique_ptr<ProxyResolutionRequest> request;
889 RecordingNetLogObserver net_log_observer;
890
891 int rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
892 &info, callback.callback(), &request,
893 NetLogWithSource::Make(NetLogSourceType::NONE));
894 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
895
896 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->GetLoadState());
897
898 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
899 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
900 factory_ptr->pending_requests()[0]->script_data()->url());
901 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
902
903 ASSERT_EQ(1u, resolver.pending_jobs().size());
904 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
905
906 // Set the result in proxy resolver.
907 resolver.pending_jobs()[0]->results()->UseNamedProxy("foopy");
908 resolver.pending_jobs()[0]->CompleteNow(OK);
909
910 EXPECT_THAT(callback.WaitForResult(), IsOk());
911 EXPECT_FALSE(info.is_direct());
912 EXPECT_EQ("foopy:80", ProxyServerToProxyUri(info.proxy_server()));
913
914 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
915 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
916 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
917
918 // Check the NetLog was filled correctly.
919 auto entries = net_log_observer.GetEntries();
920
921 EXPECT_EQ(5u, entries.size());
922 EXPECT_TRUE(LogContainsBeginEvent(entries, 0,
923 NetLogEventType::PROXY_RESOLUTION_SERVICE));
924 EXPECT_TRUE(LogContainsBeginEvent(
925 entries, 1,
926 NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC));
927 EXPECT_TRUE(LogContainsEndEvent(
928 entries, 2,
929 NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC));
930 EXPECT_TRUE(LogContainsEndEvent(entries, 4,
931 NetLogEventType::PROXY_RESOLUTION_SERVICE));
932 }
933
934 // Test that the proxy resolver does not see the URL's username/password
935 // or its reference section.
TEST_F(ConfiguredProxyResolutionServiceTest,PAC_NoIdentityOrHash)936 TEST_F(ConfiguredProxyResolutionServiceTest, PAC_NoIdentityOrHash) {
937 auto config_service =
938 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
939
940 MockAsyncProxyResolver resolver;
941 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
942 auto* factory_ptr = factory.get();
943
944 ConfiguredProxyResolutionService service(std::move(config_service),
945 std::move(factory), nullptr,
946 /*quick_check_enabled=*/true);
947
948 GURL url("http://username:password@www.google.com/?ref#hash#hash");
949
950 ProxyInfo info;
951 TestCompletionCallback callback;
952 std::unique_ptr<ProxyResolutionRequest> request;
953 int rv =
954 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
955 callback.callback(), &request, NetLogWithSource());
956 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
957
958 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
959 factory_ptr->pending_requests()[0]->script_data()->url());
960 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
961
962 ASSERT_EQ(1u, resolver.pending_jobs().size());
963 // The URL should have been simplified, stripping the username/password/hash.
964 EXPECT_EQ(GURL("http://www.google.com/?ref"),
965 resolver.pending_jobs()[0]->url());
966
967 // We end here without ever completing the request -- destruction of
968 // ConfiguredProxyResolutionService will cancel the outstanding request.
969 }
970
TEST_F(ConfiguredProxyResolutionServiceTest,PAC_FailoverWithoutDirect)971 TEST_F(ConfiguredProxyResolutionServiceTest, PAC_FailoverWithoutDirect) {
972 auto config_service =
973 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
974 MockAsyncProxyResolver resolver;
975 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
976 auto* factory_ptr = factory.get();
977
978 ConfiguredProxyResolutionService service(std::move(config_service),
979 std::move(factory), nullptr,
980 /*quick_check_enabled=*/true);
981
982 GURL url("http://www.google.com/");
983
984 ProxyInfo info;
985 TestCompletionCallback callback1;
986 std::unique_ptr<ProxyResolutionRequest> request1;
987 int rv =
988 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
989 callback1.callback(), &request1, NetLogWithSource());
990 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
991
992 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
993 factory_ptr->pending_requests()[0]->script_data()->url());
994 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
995
996 ASSERT_EQ(1u, resolver.pending_jobs().size());
997 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
998
999 // Set the result in proxy resolver.
1000 resolver.pending_jobs()[0]->results()->UseNamedProxy("foopy:8080");
1001 resolver.pending_jobs()[0]->CompleteNow(OK);
1002
1003 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1004 EXPECT_FALSE(info.is_direct());
1005 EXPECT_EQ("foopy:8080", ProxyServerToProxyUri(info.proxy_server()));
1006
1007 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1008 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1009 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1010
1011 // Now, imagine that connecting to foopy:8080 fails: there is nothing
1012 // left to fallback to, since our proxy list was NOT terminated by
1013 // DIRECT.
1014 EXPECT_FALSE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1015 EXPECT_TRUE(info.is_empty());
1016 }
1017
1018 // Test that if the execution of the PAC script fails (i.e. javascript runtime
1019 // error), and the PAC settings are non-mandatory, that we fall-back to direct.
TEST_F(ConfiguredProxyResolutionServiceTest,PAC_RuntimeError)1020 TEST_F(ConfiguredProxyResolutionServiceTest, PAC_RuntimeError) {
1021 auto config_service =
1022 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1023 MockAsyncProxyResolver resolver;
1024 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1025 auto* factory_ptr = factory.get();
1026
1027 ConfiguredProxyResolutionService service(std::move(config_service),
1028 std::move(factory), nullptr,
1029 /*quick_check_enabled=*/true);
1030
1031 GURL url("http://this-causes-js-error/");
1032
1033 ProxyInfo info;
1034 TestCompletionCallback callback1;
1035 std::unique_ptr<ProxyResolutionRequest> request1;
1036 int rv =
1037 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1038 callback1.callback(), &request1, NetLogWithSource());
1039 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1040
1041 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1042 factory_ptr->pending_requests()[0]->script_data()->url());
1043 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1044
1045 ASSERT_EQ(1u, resolver.pending_jobs().size());
1046 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1047
1048 // Simulate a failure in the PAC executor.
1049 resolver.pending_jobs()[0]->CompleteNow(ERR_PAC_SCRIPT_FAILED);
1050
1051 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1052
1053 // Since the PAC script was non-mandatory, we should have fallen-back to
1054 // DIRECT.
1055 EXPECT_TRUE(info.is_direct());
1056
1057 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1058 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1059 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1060 }
1061
1062 // The proxy list could potentially contain the DIRECT fallback choice
1063 // in a location other than the very end of the list, and could even
1064 // specify it multiple times.
1065 //
1066 // This is not a typical usage, but we will obey it.
1067 // (If we wanted to disallow this type of input, the right place to
1068 // enforce it would be in parsing the PAC result string).
1069 //
1070 // This test will use the PAC result string:
1071 //
1072 // "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20"
1073 //
1074 // For which we expect it to try DIRECT, then foobar:10, then DIRECT again,
1075 // then foobar:20, and then give up and error.
1076 //
1077 // The important check of this test is to make sure that DIRECT is not somehow
1078 // cached as being a bad proxy.
TEST_F(ConfiguredProxyResolutionServiceTest,PAC_FailoverAfterDirect)1079 TEST_F(ConfiguredProxyResolutionServiceTest, PAC_FailoverAfterDirect) {
1080 auto config_service =
1081 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1082 MockAsyncProxyResolver resolver;
1083 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1084 auto* factory_ptr = factory.get();
1085
1086 ConfiguredProxyResolutionService service(std::move(config_service),
1087 std::move(factory), nullptr,
1088 /*quick_check_enabled=*/true);
1089
1090 GURL url("http://www.google.com/");
1091
1092 ProxyInfo info;
1093 TestCompletionCallback callback1;
1094 std::unique_ptr<ProxyResolutionRequest> request1;
1095 int rv =
1096 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1097 callback1.callback(), &request1, NetLogWithSource());
1098 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1099
1100 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1101 factory_ptr->pending_requests()[0]->script_data()->url());
1102 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1103
1104 ASSERT_EQ(1u, resolver.pending_jobs().size());
1105 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1106
1107 // Set the result in proxy resolver.
1108 resolver.pending_jobs()[0]->results()->UsePacString(
1109 "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20");
1110 resolver.pending_jobs()[0]->CompleteNow(OK);
1111
1112 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1113 EXPECT_TRUE(info.is_direct());
1114
1115 // Fallback 1.
1116 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1117 EXPECT_FALSE(info.is_direct());
1118 EXPECT_EQ("foobar:10", ProxyServerToProxyUri(info.proxy_server()));
1119
1120 // Fallback 2.
1121 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1122 EXPECT_TRUE(info.is_direct());
1123
1124 // Fallback 3.
1125 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1126 EXPECT_FALSE(info.is_direct());
1127 EXPECT_EQ("foobar:20", ProxyServerToProxyUri(info.proxy_server()));
1128
1129 // Fallback 4 -- Nothing to fall back to!
1130 EXPECT_FALSE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1131 EXPECT_TRUE(info.is_empty());
1132 }
1133
TEST_F(ConfiguredProxyResolutionServiceTest,PAC_ConfigSourcePropagates)1134 TEST_F(ConfiguredProxyResolutionServiceTest, PAC_ConfigSourcePropagates) {
1135 // Test whether the ProxyConfigSource set by the ProxyConfigService is applied
1136 // to ProxyInfo after the proxy is resolved via a PAC script.
1137 ProxyConfig config =
1138 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
1139
1140 auto config_service = std::make_unique<MockProxyConfigService>(config);
1141 MockAsyncProxyResolver resolver;
1142 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1143 auto* factory_ptr = factory.get();
1144 ConfiguredProxyResolutionService service(std::move(config_service),
1145 std::move(factory), nullptr,
1146 /*quick_check_enabled=*/true);
1147
1148 // Resolve something.
1149 GURL url("http://www.google.com/");
1150 ProxyInfo info;
1151 TestCompletionCallback callback;
1152 std::unique_ptr<ProxyResolutionRequest> request;
1153 int rv =
1154 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1155 callback.callback(), &request, NetLogWithSource());
1156 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
1157 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1158 ASSERT_EQ(1u, resolver.pending_jobs().size());
1159
1160 // Set the result in proxy resolver.
1161 resolver.pending_jobs()[0]->results()->UseNamedProxy("foopy");
1162 resolver.pending_jobs()[0]->CompleteNow(OK);
1163
1164 EXPECT_THAT(callback.WaitForResult(), IsOk());
1165 EXPECT_EQ(MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
1166 info.traffic_annotation());
1167
1168 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1169 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1170 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1171 }
1172
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyResolverFails)1173 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyResolverFails) {
1174 // Test what happens when the ProxyResolver fails. The download and setting
1175 // of the PAC script have already succeeded, so this corresponds with a
1176 // javascript runtime error while calling FindProxyForURL().
1177
1178 auto config_service =
1179 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1180
1181 MockAsyncProxyResolver resolver;
1182 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1183 auto* factory_ptr = factory.get();
1184
1185 ConfiguredProxyResolutionService service(std::move(config_service),
1186 std::move(factory), nullptr,
1187 /*quick_check_enabled=*/true);
1188
1189 // Start first resolve request.
1190 GURL url("http://www.google.com/");
1191 ProxyInfo info;
1192 TestCompletionCallback callback1;
1193 std::unique_ptr<ProxyResolutionRequest> request;
1194 int rv =
1195 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1196 callback1.callback(), &request, NetLogWithSource());
1197 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1198
1199 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1200 factory_ptr->pending_requests()[0]->script_data()->url());
1201 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1202
1203 ASSERT_EQ(1u, resolver.pending_jobs().size());
1204 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1205
1206 // Fail the first resolve request in MockAsyncProxyResolver.
1207 resolver.pending_jobs()[0]->CompleteNow(ERR_FAILED);
1208
1209 // Although the proxy resolver failed the request,
1210 // ConfiguredProxyResolutionService implicitly falls-back to DIRECT.
1211 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1212 EXPECT_TRUE(info.is_direct());
1213
1214 // Failed PAC executions still have proxy resolution times.
1215 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1216 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1217 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1218
1219 // The second resolve request will try to run through the proxy resolver,
1220 // regardless of whether the first request failed in it.
1221 TestCompletionCallback callback2;
1222 rv =
1223 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1224 callback2.callback(), &request, NetLogWithSource());
1225 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1226
1227 ASSERT_EQ(1u, resolver.pending_jobs().size());
1228 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1229
1230 // This time we will have the resolver succeed (perhaps the PAC script has
1231 // a dependency on the current time).
1232 resolver.pending_jobs()[0]->results()->UseNamedProxy("foopy_valid:8080");
1233 resolver.pending_jobs()[0]->CompleteNow(OK);
1234
1235 EXPECT_THAT(callback2.WaitForResult(), IsOk());
1236 EXPECT_FALSE(info.is_direct());
1237 EXPECT_EQ("foopy_valid:8080", ProxyServerToProxyUri(info.proxy_server()));
1238 }
1239
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyResolverTerminatedDuringRequest)1240 TEST_F(ConfiguredProxyResolutionServiceTest,
1241 ProxyResolverTerminatedDuringRequest) {
1242 // Test what happens when the ProxyResolver fails with a fatal error while
1243 // a GetProxyForURL() call is in progress.
1244
1245 auto config_service =
1246 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1247
1248 MockAsyncProxyResolver resolver;
1249 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1250 auto* factory_ptr = factory.get();
1251
1252 ConfiguredProxyResolutionService service(std::move(config_service),
1253 std::move(factory), nullptr,
1254 /*quick_check_enabled=*/true);
1255
1256 // Start first resolve request.
1257 GURL url("http://www.google.com/");
1258 ProxyInfo info;
1259 TestCompletionCallback callback1;
1260 std::unique_ptr<ProxyResolutionRequest> request;
1261 int rv =
1262 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1263 callback1.callback(), &request, NetLogWithSource());
1264 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1265
1266 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
1267 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1268 factory_ptr->pending_requests()[0]->script_data()->url());
1269 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1270
1271 ASSERT_EQ(1u, resolver.pending_jobs().size());
1272 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1273
1274 // Fail the first resolve request in MockAsyncProxyResolver.
1275 resolver.pending_jobs()[0]->CompleteNow(ERR_PAC_SCRIPT_TERMINATED);
1276
1277 // Although the proxy resolver failed the request,
1278 // ConfiguredProxyResolutionService implicitly falls-back to DIRECT.
1279 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1280 EXPECT_TRUE(info.is_direct());
1281
1282 // Failed PAC executions still have proxy resolution times.
1283 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1284 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1285 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1286
1287 // With no other requests, the ConfiguredProxyResolutionService waits for a
1288 // new request before initializing a new ProxyResolver.
1289 EXPECT_TRUE(factory_ptr->pending_requests().empty());
1290
1291 TestCompletionCallback callback2;
1292 rv =
1293 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1294 callback2.callback(), &request, NetLogWithSource());
1295 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1296
1297 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
1298 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1299 factory_ptr->pending_requests()[0]->script_data()->url());
1300 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1301
1302 ASSERT_EQ(1u, resolver.pending_jobs().size());
1303 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1304
1305 // This time we will have the resolver succeed.
1306 resolver.pending_jobs()[0]->results()->UseNamedProxy("foopy_valid:8080");
1307 resolver.pending_jobs()[0]->CompleteNow(OK);
1308
1309 EXPECT_THAT(callback2.WaitForResult(), IsOk());
1310 EXPECT_FALSE(info.is_direct());
1311 EXPECT_EQ("foopy_valid:8080", ProxyServerToProxyUri(info.proxy_server()));
1312 }
1313
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyResolverTerminatedDuringRequestWithConcurrentRequest)1314 TEST_F(ConfiguredProxyResolutionServiceTest,
1315 ProxyResolverTerminatedDuringRequestWithConcurrentRequest) {
1316 // Test what happens when the ProxyResolver fails with a fatal error while
1317 // a GetProxyForURL() call is in progress.
1318
1319 auto config_service =
1320 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1321
1322 MockAsyncProxyResolver resolver;
1323 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1324 auto* factory_ptr = factory.get();
1325
1326 ConfiguredProxyResolutionService service(std::move(config_service),
1327 std::move(factory), nullptr,
1328 /*quick_check_enabled=*/true);
1329
1330 // Start two resolve requests.
1331 GURL url1("http://www.google.com/");
1332 GURL url2("https://www.google.com/");
1333 ProxyInfo info;
1334 TestCompletionCallback callback1;
1335 std::unique_ptr<ProxyResolutionRequest> request1, request2;
1336 int rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
1337 &info, callback1.callback(), &request1,
1338 NetLogWithSource());
1339 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1340 TestCompletionCallback callback2;
1341 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
1342 &info, callback2.callback(), &request2,
1343 NetLogWithSource());
1344 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1345
1346 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
1347 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1348 factory_ptr->pending_requests()[0]->script_data()->url());
1349 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1350
1351 JobMap jobs = GetPendingJobsForURLs(resolver, url1, url2);
1352
1353 // Fail the first resolve request in MockAsyncProxyResolver.
1354 jobs[url1]->CompleteNow(ERR_PAC_SCRIPT_TERMINATED);
1355
1356 // Although the proxy resolver failed the request,
1357 // ConfiguredProxyResolutionService implicitly falls-back to DIRECT.
1358 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1359 EXPECT_TRUE(info.is_direct());
1360
1361 // Failed PAC executions still have proxy resolution times.
1362 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1363 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1364 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1365
1366 // The second request is cancelled when the proxy resolver terminates.
1367 jobs = GetCancelledJobsForURLs(resolver, url2);
1368
1369 // Since a second request was in progress, the
1370 // ConfiguredProxyResolutionService starts initializating a new ProxyResolver.
1371 ASSERT_EQ(1u, factory_ptr->pending_requests().size());
1372 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1373 factory_ptr->pending_requests()[0]->script_data()->url());
1374 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1375
1376 jobs = GetPendingJobsForURLs(resolver, url2);
1377
1378 // This request succeeds.
1379 jobs[url2]->results()->UseNamedProxy("foopy_valid:8080");
1380 jobs[url2]->CompleteNow(OK);
1381
1382 EXPECT_THAT(callback2.WaitForResult(), IsOk());
1383 EXPECT_FALSE(info.is_direct());
1384 EXPECT_EQ("foopy_valid:8080", ProxyServerToProxyUri(info.proxy_server()));
1385 }
1386
TEST_F(ConfiguredProxyResolutionServiceTest,PacFileFetcherFailsDownloadingMandatoryPac)1387 TEST_F(ConfiguredProxyResolutionServiceTest,
1388 PacFileFetcherFailsDownloadingMandatoryPac) {
1389 // Test what happens when the ProxyResolver fails to download a mandatory PAC
1390 // script.
1391
1392 ProxyConfig config(
1393 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
1394 config.set_pac_mandatory(true);
1395
1396 auto config_service = std::make_unique<MockProxyConfigService>(config);
1397
1398 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1399 auto* factory_ptr = factory.get();
1400
1401 ConfiguredProxyResolutionService service(std::move(config_service),
1402 std::move(factory), nullptr,
1403 /*quick_check_enabled=*/true);
1404
1405 // Start first resolve request.
1406 GURL url("http://www.google.com/");
1407 ProxyInfo info;
1408 TestCompletionCallback callback1;
1409 std::unique_ptr<ProxyResolutionRequest> request;
1410 int rv =
1411 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1412 callback1.callback(), &request, NetLogWithSource());
1413 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1414
1415 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1416 factory_ptr->pending_requests()[0]->script_data()->url());
1417 factory_ptr->pending_requests()[0]->CompleteNow(ERR_FAILED, nullptr);
1418
1419 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
1420 // As the proxy resolver factory failed the request and is configured for a
1421 // mandatory PAC script, ConfiguredProxyResolutionService must not implicitly
1422 // fall-back to DIRECT.
1423 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
1424 callback1.WaitForResult());
1425 EXPECT_FALSE(info.is_direct());
1426
1427 // As the proxy resolver factory failed the request and is configured for a
1428 // mandatory PAC script, ConfiguredProxyResolutionService must not implicitly
1429 // fall-back to DIRECT.
1430 TestCompletionCallback callback2;
1431 rv =
1432 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1433 callback2.callback(), &request, NetLogWithSource());
1434 EXPECT_THAT(rv, IsError(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
1435 EXPECT_FALSE(info.is_direct());
1436 }
1437
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyResolverFailsParsingJavaScriptMandatoryPac)1438 TEST_F(ConfiguredProxyResolutionServiceTest,
1439 ProxyResolverFailsParsingJavaScriptMandatoryPac) {
1440 // Test what happens when the ProxyResolver fails that is configured to use a
1441 // mandatory PAC script. The download of the PAC script has already
1442 // succeeded but the PAC script contains no valid javascript.
1443
1444 ProxyConfig config(
1445 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
1446 config.set_pac_mandatory(true);
1447
1448 auto config_service = std::make_unique<MockProxyConfigService>(config);
1449
1450 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
1451 auto* factory_ptr = factory.get();
1452
1453 ConfiguredProxyResolutionService service(std::move(config_service),
1454 std::move(factory), nullptr,
1455 /*quick_check_enabled=*/true);
1456
1457 auto fetcher = std::make_unique<MockPacFileFetcher>();
1458 auto* fetcher_ptr = fetcher.get();
1459 service.SetPacFileFetchers(std::move(fetcher),
1460 std::make_unique<DoNothingDhcpPacFileFetcher>());
1461
1462 // Start resolve request.
1463 GURL url("http://www.google.com/");
1464 ProxyInfo info;
1465 TestCompletionCallback callback;
1466 std::unique_ptr<ProxyResolutionRequest> request;
1467 int rv =
1468 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1469 callback.callback(), &request, NetLogWithSource());
1470 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1471
1472 // Check that nothing has been sent to the proxy resolver factory yet.
1473 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
1474
1475 // Downloading the PAC script succeeds.
1476 EXPECT_TRUE(fetcher_ptr->has_pending_request());
1477 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
1478 fetcher_ptr->NotifyFetchCompletion(OK, "invalid-script-contents");
1479
1480 EXPECT_FALSE(fetcher_ptr->has_pending_request());
1481 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
1482
1483 // Since PacFileDecider failed to identify a valid PAC and PAC was
1484 // mandatory for this configuration, the ConfiguredProxyResolutionService must
1485 // not implicitly fall-back to DIRECT.
1486 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, callback.WaitForResult());
1487 EXPECT_FALSE(info.is_direct());
1488 }
1489
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyResolverFailsInJavaScriptMandatoryPac)1490 TEST_F(ConfiguredProxyResolutionServiceTest,
1491 ProxyResolverFailsInJavaScriptMandatoryPac) {
1492 // Test what happens when the ProxyResolver fails that is configured to use a
1493 // mandatory PAC script. The download and setting of the PAC script have
1494 // already succeeded, so this corresponds with a javascript runtime error
1495 // while calling FindProxyForURL().
1496
1497 ProxyConfig config(
1498 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
1499 config.set_pac_mandatory(true);
1500
1501 auto config_service = std::make_unique<MockProxyConfigService>(config);
1502
1503 MockAsyncProxyResolver resolver;
1504 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1505 auto* factory_ptr = factory.get();
1506
1507 ConfiguredProxyResolutionService service(std::move(config_service),
1508 std::move(factory), nullptr,
1509 /*quick_check_enabled=*/true);
1510
1511 // Start first resolve request.
1512 GURL url("http://www.google.com/");
1513 ProxyInfo info;
1514 TestCompletionCallback callback1;
1515 std::unique_ptr<ProxyResolutionRequest> request;
1516 int rv =
1517 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1518 callback1.callback(), &request, NetLogWithSource());
1519 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1520
1521 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1522 factory_ptr->pending_requests()[0]->script_data()->url());
1523 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1524
1525 ASSERT_EQ(1u, resolver.pending_jobs().size());
1526 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1527
1528 // Fail the first resolve request in MockAsyncProxyResolver.
1529 resolver.pending_jobs()[0]->CompleteNow(ERR_FAILED);
1530
1531 // As the proxy resolver failed the request and is configured for a mandatory
1532 // PAC script, ConfiguredProxyResolutionService must not implicitly fall-back
1533 // to DIRECT.
1534 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
1535 callback1.WaitForResult());
1536 EXPECT_FALSE(info.is_direct());
1537
1538 // The second resolve request will try to run through the proxy resolver,
1539 // regardless of whether the first request failed in it.
1540 TestCompletionCallback callback2;
1541 rv =
1542 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1543 callback2.callback(), &request, NetLogWithSource());
1544 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1545
1546 ASSERT_EQ(1u, resolver.pending_jobs().size());
1547 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1548
1549 // This time we will have the resolver succeed (perhaps the PAC script has
1550 // a dependency on the current time).
1551 resolver.pending_jobs()[0]->results()->UseNamedProxy("foopy_valid:8080");
1552 resolver.pending_jobs()[0]->CompleteNow(OK);
1553
1554 EXPECT_THAT(callback2.WaitForResult(), IsOk());
1555 EXPECT_FALSE(info.is_direct());
1556 EXPECT_EQ("foopy_valid:8080", ProxyServerToProxyUri(info.proxy_server()));
1557 }
1558
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyFallback)1559 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyFallback) {
1560 // Test what happens when we specify multiple proxy servers and some of them
1561 // are bad.
1562
1563 auto config_service =
1564 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1565
1566 MockAsyncProxyResolver resolver;
1567 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1568 auto* factory_ptr = factory.get();
1569
1570 ConfiguredProxyResolutionService service(std::move(config_service),
1571 std::move(factory), nullptr,
1572 /*quick_check_enabled=*/true);
1573
1574 GURL url("http://www.google.com/");
1575
1576 // Get the proxy information.
1577 ProxyInfo info;
1578 TestCompletionCallback callback1;
1579 std::unique_ptr<ProxyResolutionRequest> request;
1580 int rv =
1581 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1582 callback1.callback(), &request, NetLogWithSource());
1583 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1584
1585 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1586 factory_ptr->pending_requests()[0]->script_data()->url());
1587 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1588
1589 ASSERT_EQ(1u, resolver.pending_jobs().size());
1590 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1591
1592 // Set the result in proxy resolver.
1593 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1594 "foopy1:8080;foopy2:9090");
1595 resolver.pending_jobs()[0]->CompleteNow(OK);
1596
1597 // The first item is valid.
1598 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1599 EXPECT_FALSE(info.is_direct());
1600 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
1601
1602 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1603 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1604 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1605 base::TimeTicks proxy_resolve_start_time = info.proxy_resolve_start_time();
1606 base::TimeTicks proxy_resolve_end_time = info.proxy_resolve_end_time();
1607
1608 // Fake an error on the proxy.
1609 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1610
1611 // Proxy times should not have been modified by fallback.
1612 EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time());
1613 EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time());
1614
1615 // The second proxy should be specified.
1616 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info.proxy_server()));
1617 // Report back that the second proxy worked. This will globally mark the
1618 // first proxy as bad.
1619 TestProxyFallbackProxyDelegate test_delegate;
1620 service.SetProxyDelegate(&test_delegate);
1621 service.ReportSuccess(info);
1622 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(test_delegate.proxy_server()));
1623 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED,
1624 test_delegate.last_proxy_fallback_net_error());
1625 service.SetProxyDelegate(nullptr);
1626
1627 TestCompletionCallback callback3;
1628 rv =
1629 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1630 callback3.callback(), &request, NetLogWithSource());
1631 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1632
1633 ASSERT_EQ(1u, resolver.pending_jobs().size());
1634 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1635
1636 // Set the result in proxy resolver -- the second result is already known
1637 // to be bad, so we will not try to use it initially.
1638 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1639 "foopy3:7070;foopy1:8080;foopy2:9090");
1640 resolver.pending_jobs()[0]->CompleteNow(OK);
1641
1642 EXPECT_THAT(callback3.WaitForResult(), IsOk());
1643 EXPECT_FALSE(info.is_direct());
1644 EXPECT_EQ("foopy3:7070", ProxyServerToProxyUri(info.proxy_server()));
1645
1646 // Proxy times should have been updated, so get them again.
1647 EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time());
1648 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1649 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1650 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1651 proxy_resolve_start_time = info.proxy_resolve_start_time();
1652 proxy_resolve_end_time = info.proxy_resolve_end_time();
1653
1654 // We fake another error. It should now try the third one.
1655 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1656 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info.proxy_server()));
1657
1658 // We fake another error. At this point we have tried all of the
1659 // proxy servers we thought were valid; next we try the proxy server
1660 // that was in our bad proxies map (foopy1:8080).
1661 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1662 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
1663
1664 // Fake another error, the last proxy is gone, the list should now be empty,
1665 // so there is nothing left to try.
1666 EXPECT_FALSE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1667 EXPECT_FALSE(info.is_direct());
1668 EXPECT_TRUE(info.is_empty());
1669
1670 // Proxy times should not have been modified by fallback.
1671 EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time());
1672 EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time());
1673
1674 // Look up proxies again
1675 TestCompletionCallback callback7;
1676 rv =
1677 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1678 callback7.callback(), &request, NetLogWithSource());
1679 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1680
1681 ASSERT_EQ(1u, resolver.pending_jobs().size());
1682 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1683
1684 // This time, the first 3 results have been found to be bad, but only the
1685 // first proxy has been confirmed ...
1686 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1687 "foopy1:8080;foopy3:7070;foopy2:9090;foopy4:9091");
1688 resolver.pending_jobs()[0]->CompleteNow(OK);
1689
1690 // ... therefore, we should see the second proxy first.
1691 EXPECT_THAT(callback7.WaitForResult(), IsOk());
1692 EXPECT_FALSE(info.is_direct());
1693 EXPECT_EQ("foopy3:7070", ProxyServerToProxyUri(info.proxy_server()));
1694
1695 EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time());
1696 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1697 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1698 // TODO(nsylvain): Test that the proxy can be retried after the delay.
1699 }
1700
1701 // This test is similar to ProxyFallback, but this time we have an explicit
1702 // fallback choice to DIRECT.
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyFallbackToDirect)1703 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyFallbackToDirect) {
1704 auto config_service =
1705 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1706
1707 MockAsyncProxyResolver resolver;
1708 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1709 auto* factory_ptr = factory.get();
1710
1711 ConfiguredProxyResolutionService service(std::move(config_service),
1712 std::move(factory), nullptr,
1713 /*quick_check_enabled=*/true);
1714
1715 GURL url("http://www.google.com/");
1716
1717 // Get the proxy information.
1718 ProxyInfo info;
1719 TestCompletionCallback callback1;
1720 std::unique_ptr<ProxyResolutionRequest> request1;
1721 int rv =
1722 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1723 callback1.callback(), &request1, NetLogWithSource());
1724 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1725
1726 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1727 factory_ptr->pending_requests()[0]->script_data()->url());
1728 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1729
1730 ASSERT_EQ(1u, resolver.pending_jobs().size());
1731 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1732
1733 // Set the result in proxy resolver.
1734 resolver.pending_jobs()[0]->results()->UsePacString(
1735 "PROXY foopy1:8080; PROXY foopy2:9090; DIRECT");
1736 resolver.pending_jobs()[0]->CompleteNow(OK);
1737
1738 // Get the first result.
1739 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1740 EXPECT_FALSE(info.is_direct());
1741 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
1742
1743 // Fake an error on the proxy.
1744 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1745
1746 // Now we get back the second proxy.
1747 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info.proxy_server()));
1748
1749 // Fake an error on this proxy as well.
1750 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1751
1752 // Finally, we get back DIRECT.
1753 EXPECT_TRUE(info.is_direct());
1754
1755 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1756 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1757 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1758
1759 // Now we tell the proxy service that even DIRECT failed.
1760 // There was nothing left to try after DIRECT, so we are out of
1761 // choices.
1762 EXPECT_FALSE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1763 }
1764
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyFallback_BadConfig)1765 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyFallback_BadConfig) {
1766 // Test proxy failover when the configuration is bad.
1767
1768 auto config_service =
1769 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
1770
1771 MockAsyncProxyResolver resolver;
1772 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1773 auto* factory_ptr = factory.get();
1774
1775 ConfiguredProxyResolutionService service(std::move(config_service),
1776 std::move(factory), nullptr,
1777 /*quick_check_enabled=*/true);
1778
1779 GURL url("http://www.google.com/");
1780
1781 // Get the proxy information.
1782 ProxyInfo info;
1783 TestCompletionCallback callback1;
1784 TestResolveProxyDelegate delegate;
1785 std::unique_ptr<ProxyResolutionRequest> request;
1786 service.SetProxyDelegate(&delegate);
1787 int rv =
1788 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1789 callback1.callback(), &request, NetLogWithSource());
1790 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1791
1792 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1793 factory_ptr->pending_requests()[0]->script_data()->url());
1794 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1795 ASSERT_EQ(1u, resolver.pending_jobs().size());
1796 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1797
1798 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1799 "foopy1:8080;foopy2:9090");
1800 resolver.pending_jobs()[0]->CompleteNow(OK);
1801
1802 // The first item is valid.
1803 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1804 EXPECT_FALSE(info.is_direct());
1805 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
1806
1807 // Fake a proxy error.
1808 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1809
1810 // The first proxy is ignored, and the second one is selected.
1811 EXPECT_FALSE(info.is_direct());
1812 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info.proxy_server()));
1813
1814 // Persist foopy1's failure to |service|'s cache of bad proxies, so it will
1815 // be considered by subsequent calls to ResolveProxy().
1816 service.ReportSuccess(info);
1817
1818 // Fake a PAC failure.
1819 ProxyInfo info2;
1820 TestCompletionCallback callback2;
1821 rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
1822 &info2, callback2.callback(), &request,
1823 NetLogWithSource());
1824 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1825
1826 ASSERT_EQ(1u, resolver.pending_jobs().size());
1827 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1828
1829 // This simulates a javascript runtime error in the PAC script.
1830 resolver.pending_jobs()[0]->CompleteNow(ERR_FAILED);
1831
1832 // Although the resolver failed, the ConfiguredProxyResolutionService will
1833 // implicitly fall-back to a DIRECT connection.
1834 EXPECT_THAT(callback2.WaitForResult(), IsOk());
1835 EXPECT_TRUE(info2.is_direct());
1836 EXPECT_FALSE(info2.is_empty());
1837
1838 // The PAC script will work properly next time and successfully return a
1839 // proxy list. Since we have not marked the configuration as bad, it should
1840 // "just work" the next time we call it.
1841 ProxyInfo info3;
1842 TestCompletionCallback callback3;
1843 std::unique_ptr<ProxyResolutionRequest> request3;
1844 rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
1845 &info3, callback3.callback(), &request3,
1846 NetLogWithSource());
1847 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1848
1849 ASSERT_EQ(1u, resolver.pending_jobs().size());
1850 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1851
1852 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1853 "foopy1:8080;foopy2:9090");
1854 resolver.pending_jobs()[0]->CompleteNow(OK);
1855
1856 // The first proxy was deprioritized since it was added to the bad proxies
1857 // list by the earlier ReportSuccess().
1858 EXPECT_THAT(callback3.WaitForResult(), IsOk());
1859 EXPECT_FALSE(info3.is_direct());
1860 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info3.proxy_server()));
1861 EXPECT_EQ(2u, info3.proxy_list().size());
1862
1863 EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1864 EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1865 EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1866
1867 EXPECT_EQ(3, delegate.num_resolve_proxy_called());
1868 }
1869
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyFallback_BadConfigMandatory)1870 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyFallback_BadConfigMandatory) {
1871 // Test proxy failover when the configuration is bad.
1872
1873 ProxyConfig config(
1874 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
1875
1876 config.set_pac_mandatory(true);
1877 auto config_service = std::make_unique<MockProxyConfigService>(config);
1878
1879 MockAsyncProxyResolver resolver;
1880 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
1881 auto* factory_ptr = factory.get();
1882
1883 ConfiguredProxyResolutionService service(std::move(config_service),
1884 std::move(factory), nullptr,
1885 /*quick_check_enabled=*/true);
1886
1887 GURL url("http://www.google.com/");
1888
1889 // Get the proxy information.
1890 ProxyInfo info;
1891 TestCompletionCallback callback1;
1892 std::unique_ptr<ProxyResolutionRequest> request1;
1893 int rv =
1894 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
1895 callback1.callback(), &request1, NetLogWithSource());
1896 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1897
1898 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1899 factory_ptr->pending_requests()[0]->script_data()->url());
1900 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
1901 ASSERT_EQ(1u, resolver.pending_jobs().size());
1902 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1903
1904 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1905 "foopy1:8080;foopy2:9090");
1906 resolver.pending_jobs()[0]->CompleteNow(OK);
1907
1908 // The first item is valid.
1909 EXPECT_THAT(callback1.WaitForResult(), IsOk());
1910 EXPECT_FALSE(info.is_direct());
1911 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
1912
1913 // Fake a proxy error.
1914 EXPECT_TRUE(info.Fallback(ERR_PROXY_CONNECTION_FAILED, NetLogWithSource()));
1915
1916 // The first proxy is ignored, and the second one is selected.
1917 EXPECT_FALSE(info.is_direct());
1918 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info.proxy_server()));
1919
1920 // Persist foopy1's failure to |service|'s cache of bad proxies, so it will
1921 // be considered by subsequent calls to ResolveProxy().
1922 service.ReportSuccess(info);
1923
1924 // Fake a PAC failure.
1925 ProxyInfo info2;
1926 TestCompletionCallback callback3;
1927 std::unique_ptr<ProxyResolutionRequest> request3;
1928 rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
1929 &info2, callback3.callback(), &request3,
1930 NetLogWithSource());
1931 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1932
1933 ASSERT_EQ(1u, resolver.pending_jobs().size());
1934 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1935
1936 // This simulates a javascript runtime error in the PAC script.
1937 resolver.pending_jobs()[0]->CompleteNow(ERR_FAILED);
1938
1939 // Although the resolver failed, the ConfiguredProxyResolutionService will NOT
1940 // fall-back to a DIRECT connection as it is configured as mandatory.
1941 EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
1942 callback3.WaitForResult());
1943 EXPECT_FALSE(info2.is_direct());
1944 EXPECT_TRUE(info2.is_empty());
1945
1946 // The PAC script will work properly next time and successfully return a
1947 // proxy list. Since we have not marked the configuration as bad, it should
1948 // "just work" the next time we call it.
1949 ProxyInfo info3;
1950 TestCompletionCallback callback4;
1951 std::unique_ptr<ProxyResolutionRequest> request4;
1952 rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
1953 &info3, callback4.callback(), &request4,
1954 NetLogWithSource());
1955 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
1956
1957 ASSERT_EQ(1u, resolver.pending_jobs().size());
1958 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
1959
1960 resolver.pending_jobs()[0]->results()->UseNamedProxy(
1961 "foopy1:8080;foopy2:9090");
1962 resolver.pending_jobs()[0]->CompleteNow(OK);
1963
1964 // The first proxy was deprioritized since it was added to the bad proxies
1965 // list by the earlier ReportSuccess().
1966 EXPECT_THAT(callback4.WaitForResult(), IsOk());
1967 EXPECT_FALSE(info3.is_direct());
1968 EXPECT_EQ("foopy2:9090", ProxyServerToProxyUri(info3.proxy_server()));
1969 EXPECT_EQ(2u, info3.proxy_list().size());
1970 }
1971
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyBypassList)1972 TEST_F(ConfiguredProxyResolutionServiceTest, ProxyBypassList) {
1973 // Test that the proxy bypass rules are consulted.
1974
1975 TestCompletionCallback callback[2];
1976 ProxyInfo info[2];
1977 ProxyConfig config;
1978 config.proxy_rules().ParseFromString("foopy1:8080;foopy2:9090");
1979 config.set_auto_detect(false);
1980 config.proxy_rules().bypass_rules.ParseFromString("*.org");
1981
1982 ConfiguredProxyResolutionService service(
1983 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
1984 /*quick_check_enabled=*/true);
1985
1986 int rv;
1987 GURL url1("http://www.webkit.org");
1988 GURL url2("http://www.webkit.com");
1989 std::unique_ptr<ProxyResolutionRequest> request1;
1990 std::unique_ptr<ProxyResolutionRequest> request2;
1991
1992 // Request for a .org domain should bypass proxy.
1993 rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
1994 &info[0], callback[0].callback(), &request1,
1995 NetLogWithSource());
1996 EXPECT_THAT(rv, IsOk());
1997 EXPECT_TRUE(info[0].is_direct());
1998
1999 // Request for a .com domain hits the proxy.
2000 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
2001 &info[1], callback[1].callback(), &request2,
2002 NetLogWithSource());
2003 EXPECT_THAT(rv, IsOk());
2004 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info[1].proxy_server()));
2005 }
2006
TEST_F(ConfiguredProxyResolutionServiceTest,MarkProxiesAsBadTests)2007 TEST_F(ConfiguredProxyResolutionServiceTest, MarkProxiesAsBadTests) {
2008 ProxyConfig config;
2009 config.proxy_rules().ParseFromString(
2010 "http=foopy1:8080;http=foopy2:8080;http=foopy3:8080;http=foopy4:8080");
2011 config.set_auto_detect(false);
2012
2013 ProxyList proxy_list;
2014 std::vector<ProxyServer> additional_bad_proxies;
2015 for (const ProxyServer& proxy_server :
2016 config.proxy_rules().proxies_for_http.GetAll()) {
2017 proxy_list.AddProxyServer(proxy_server);
2018 if (proxy_server == config.proxy_rules().proxies_for_http.Get())
2019 continue;
2020
2021 additional_bad_proxies.push_back(proxy_server);
2022 }
2023
2024 EXPECT_EQ(3u, additional_bad_proxies.size());
2025
2026 ConfiguredProxyResolutionService service(
2027 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2028 /*quick_check_enabled=*/true);
2029 ProxyInfo proxy_info;
2030 proxy_info.UseProxyList(proxy_list);
2031 const ProxyRetryInfoMap& retry_info = service.proxy_retry_info();
2032 service.MarkProxiesAsBadUntil(proxy_info, base::Seconds(1),
2033 additional_bad_proxies, NetLogWithSource());
2034 ASSERT_EQ(4u, retry_info.size());
2035 for (const ProxyServer& proxy_server :
2036 config.proxy_rules().proxies_for_http.GetAll()) {
2037 auto i = retry_info.find(proxy_server.host_port_pair().ToString());
2038 ASSERT_TRUE(i != retry_info.end());
2039 }
2040 }
2041
TEST_F(ConfiguredProxyResolutionServiceTest,PerProtocolProxyTests)2042 TEST_F(ConfiguredProxyResolutionServiceTest, PerProtocolProxyTests) {
2043 ProxyConfig config;
2044 config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080");
2045 config.set_auto_detect(false);
2046 std::unique_ptr<ProxyResolutionRequest> request;
2047 {
2048 ConfiguredProxyResolutionService service(
2049 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2050 /*quick_check_enabled=*/true);
2051 GURL test_url("http://www.msn.com");
2052 ProxyInfo info;
2053 TestCompletionCallback callback;
2054 int rv = service.ResolveProxy(
2055 test_url, std::string(), NetworkAnonymizationKey(), &info,
2056 callback.callback(), &request, NetLogWithSource());
2057 EXPECT_THAT(rv, IsOk());
2058 EXPECT_FALSE(info.is_direct());
2059 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
2060 }
2061 {
2062 ConfiguredProxyResolutionService service(
2063 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2064 /*quick_check_enabled=*/true);
2065 GURL test_url("ftp://ftp.google.com");
2066 ProxyInfo info;
2067 TestCompletionCallback callback;
2068 int rv = service.ResolveProxy(
2069 test_url, std::string(), NetworkAnonymizationKey(), &info,
2070 callback.callback(), &request, NetLogWithSource());
2071 EXPECT_THAT(rv, IsOk());
2072 EXPECT_TRUE(info.is_direct());
2073 EXPECT_EQ("direct://", ProxyServerToProxyUri(info.proxy_server()));
2074 }
2075 {
2076 ConfiguredProxyResolutionService service(
2077 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2078 /*quick_check_enabled=*/true);
2079 GURL test_url("https://webbranch.techcu.com");
2080 ProxyInfo info;
2081 TestCompletionCallback callback;
2082 int rv = service.ResolveProxy(
2083 test_url, std::string(), NetworkAnonymizationKey(), &info,
2084 callback.callback(), &request, NetLogWithSource());
2085 EXPECT_THAT(rv, IsOk());
2086 EXPECT_FALSE(info.is_direct());
2087 EXPECT_EQ("foopy2:8080", ProxyServerToProxyUri(info.proxy_server()));
2088 }
2089 {
2090 config.proxy_rules().ParseFromString("foopy1:8080");
2091 ConfiguredProxyResolutionService service(
2092 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2093 /*quick_check_enabled=*/true);
2094 GURL test_url("http://www.microsoft.com");
2095 ProxyInfo info;
2096 TestCompletionCallback callback;
2097 int rv = service.ResolveProxy(
2098 test_url, std::string(), NetworkAnonymizationKey(), &info,
2099 callback.callback(), &request, NetLogWithSource());
2100 EXPECT_THAT(rv, IsOk());
2101 EXPECT_FALSE(info.is_direct());
2102 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
2103 }
2104 }
2105
TEST_F(ConfiguredProxyResolutionServiceTest,ProxyConfigTrafficAnnotationPropagates)2106 TEST_F(ConfiguredProxyResolutionServiceTest,
2107 ProxyConfigTrafficAnnotationPropagates) {
2108 // Test that the proxy config source is set correctly when resolving proxies
2109 // using manual proxy rules. Namely, the config source should only be set if
2110 // any of the rules were applied.
2111 std::unique_ptr<ProxyResolutionRequest> request;
2112 {
2113 ProxyConfig config;
2114 config.proxy_rules().ParseFromString("https=foopy2:8080");
2115 ConfiguredProxyResolutionService service(
2116 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2117 /*quick_check_enabled=*/true);
2118 GURL test_url("http://www.google.com");
2119 ProxyInfo info;
2120 TestCompletionCallback callback;
2121 int rv = service.ResolveProxy(
2122 test_url, std::string(), NetworkAnonymizationKey(), &info,
2123 callback.callback(), &request, NetLogWithSource());
2124 ASSERT_THAT(rv, IsOk());
2125 // Should be test, even if there are no HTTP proxies configured.
2126 EXPECT_EQ(MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
2127 info.traffic_annotation());
2128 }
2129 {
2130 ProxyConfig config;
2131 config.proxy_rules().ParseFromString("https=foopy2:8080");
2132 ConfiguredProxyResolutionService service(
2133 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2134 /*quick_check_enabled=*/true);
2135 GURL test_url("https://www.google.com");
2136 ProxyInfo info;
2137 TestCompletionCallback callback;
2138 int rv = service.ResolveProxy(
2139 test_url, std::string(), NetworkAnonymizationKey(), &info,
2140 callback.callback(), &request, NetLogWithSource());
2141 ASSERT_THAT(rv, IsOk());
2142 // Used the HTTPS proxy. So traffic annotation should test.
2143 EXPECT_EQ(MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
2144 info.traffic_annotation());
2145 }
2146 {
2147 ProxyConfig config;
2148 ConfiguredProxyResolutionService service(
2149 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2150 /*quick_check_enabled=*/true);
2151 GURL test_url("http://www.google.com");
2152 ProxyInfo info;
2153 TestCompletionCallback callback;
2154 int rv = service.ResolveProxy(
2155 test_url, std::string(), NetworkAnonymizationKey(), &info,
2156 callback.callback(), &request, NetLogWithSource());
2157 ASSERT_THAT(rv, IsOk());
2158 // ProxyConfig is empty. Traffic annotation should still be TEST.
2159 EXPECT_EQ(MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
2160 info.traffic_annotation());
2161 }
2162 }
2163
2164 // If only HTTP and a SOCKS proxy are specified, check if ftp/https queries
2165 // fall back to the SOCKS proxy.
TEST_F(ConfiguredProxyResolutionServiceTest,DefaultProxyFallbackToSOCKS)2166 TEST_F(ConfiguredProxyResolutionServiceTest, DefaultProxyFallbackToSOCKS) {
2167 ProxyConfig config;
2168 config.proxy_rules().ParseFromString("http=foopy1:8080;socks=foopy2:1080");
2169 config.set_auto_detect(false);
2170 EXPECT_EQ(ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
2171 config.proxy_rules().type);
2172
2173 std::unique_ptr<ProxyResolutionRequest> request;
2174 {
2175 ConfiguredProxyResolutionService service(
2176 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2177 /*quick_check_enabled=*/true);
2178 GURL test_url("http://www.msn.com");
2179 ProxyInfo info;
2180 TestCompletionCallback callback;
2181 int rv = service.ResolveProxy(
2182 test_url, std::string(), NetworkAnonymizationKey(), &info,
2183 callback.callback(), &request, NetLogWithSource());
2184 EXPECT_THAT(rv, IsOk());
2185 EXPECT_FALSE(info.is_direct());
2186 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info.proxy_server()));
2187 }
2188 {
2189 ConfiguredProxyResolutionService service(
2190 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2191 /*quick_check_enabled=*/true);
2192 GURL test_url("ftp://ftp.google.com");
2193 ProxyInfo info;
2194 TestCompletionCallback callback;
2195 int rv = service.ResolveProxy(
2196 test_url, std::string(), NetworkAnonymizationKey(), &info,
2197 callback.callback(), &request, NetLogWithSource());
2198 EXPECT_THAT(rv, IsOk());
2199 EXPECT_FALSE(info.is_direct());
2200 EXPECT_EQ("socks4://foopy2:1080",
2201 ProxyServerToProxyUri(info.proxy_server()));
2202 }
2203 {
2204 ConfiguredProxyResolutionService service(
2205 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2206 /*quick_check_enabled=*/true);
2207 GURL test_url("https://webbranch.techcu.com");
2208 ProxyInfo info;
2209 TestCompletionCallback callback;
2210 int rv = service.ResolveProxy(
2211 test_url, std::string(), NetworkAnonymizationKey(), &info,
2212 callback.callback(), &request, NetLogWithSource());
2213 EXPECT_THAT(rv, IsOk());
2214 EXPECT_FALSE(info.is_direct());
2215 EXPECT_EQ("socks4://foopy2:1080",
2216 ProxyServerToProxyUri(info.proxy_server()));
2217 }
2218 {
2219 ConfiguredProxyResolutionService service(
2220 std::make_unique<MockProxyConfigService>(config), nullptr, nullptr,
2221 /*quick_check_enabled=*/true);
2222 GURL test_url("unknown://www.microsoft.com");
2223 ProxyInfo info;
2224 TestCompletionCallback callback;
2225 int rv = service.ResolveProxy(
2226 test_url, std::string(), NetworkAnonymizationKey(), &info,
2227 callback.callback(), &request, NetLogWithSource());
2228 EXPECT_THAT(rv, IsOk());
2229 EXPECT_FALSE(info.is_direct());
2230 EXPECT_EQ("socks4://foopy2:1080",
2231 ProxyServerToProxyUri(info.proxy_server()));
2232 }
2233 }
2234
2235 // Test cancellation of an in-progress request.
TEST_F(ConfiguredProxyResolutionServiceTest,CancelInProgressRequest)2236 TEST_F(ConfiguredProxyResolutionServiceTest, CancelInProgressRequest) {
2237 const GURL url1("http://request1");
2238 const GURL url2("http://request2");
2239 const GURL url3("http://request3");
2240 auto config_service =
2241 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
2242
2243 MockAsyncProxyResolver resolver;
2244 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
2245 auto* factory_ptr = factory.get();
2246
2247 ConfiguredProxyResolutionService service(std::move(config_service),
2248 std::move(factory), nullptr,
2249 /*quick_check_enabled=*/true);
2250
2251 // Start 3 requests.
2252
2253 ProxyInfo info1;
2254 TestCompletionCallback callback1;
2255 std::unique_ptr<ProxyResolutionRequest> request1;
2256 int rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
2257 &info1, callback1.callback(), &request1,
2258 NetLogWithSource());
2259 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2260
2261 // Successfully initialize the PAC script.
2262 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
2263 factory_ptr->pending_requests()[0]->script_data()->url());
2264 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2265
2266 GetPendingJobsForURLs(resolver, url1);
2267
2268 ProxyInfo info2;
2269 TestCompletionCallback callback2;
2270 std::unique_ptr<ProxyResolutionRequest> request2;
2271 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
2272 &info2, callback2.callback(), &request2,
2273 NetLogWithSource());
2274 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2275
2276 GetPendingJobsForURLs(resolver, url1, url2);
2277
2278 ProxyInfo info3;
2279 TestCompletionCallback callback3;
2280 std::unique_ptr<ProxyResolutionRequest> request3;
2281 rv = service.ResolveProxy(url3, std::string(), NetworkAnonymizationKey(),
2282 &info3, callback3.callback(), &request3,
2283 NetLogWithSource());
2284 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2285 GetPendingJobsForURLs(resolver, url1, url2, url3);
2286
2287 // Cancel the second request
2288 request2.reset();
2289
2290 JobMap jobs = GetPendingJobsForURLs(resolver, url1, url3);
2291
2292 // Complete the two un-cancelled jobs.
2293 // We complete the last one first, just to mix it up a bit.
2294 jobs[url3]->results()->UseNamedProxy("request3:80");
2295 jobs[url3]->CompleteNow(OK); // dsaadsasd
2296
2297 jobs[url1]->results()->UseNamedProxy("request1:80");
2298 jobs[url1]->CompleteNow(OK);
2299
2300 EXPECT_EQ(OK, callback1.WaitForResult());
2301 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
2302
2303 EXPECT_FALSE(callback2.have_result()); // Cancelled.
2304 GetCancelledJobsForURLs(resolver, url2);
2305
2306 EXPECT_THAT(callback3.WaitForResult(), IsOk());
2307 EXPECT_EQ("request3:80", ProxyServerToProxyUri(info3.proxy_server()));
2308 }
2309
2310 // Test the initial PAC download for resolver that expects bytes.
TEST_F(ConfiguredProxyResolutionServiceTest,InitialPACScriptDownload)2311 TEST_F(ConfiguredProxyResolutionServiceTest, InitialPACScriptDownload) {
2312 const GURL url1("http://request1");
2313 const GURL url2("http://request2");
2314 const GURL url3("http://request3");
2315 auto config_service =
2316 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
2317
2318 MockAsyncProxyResolver resolver;
2319 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2320 auto* factory_ptr = factory.get();
2321
2322 ConfiguredProxyResolutionService service(std::move(config_service),
2323 std::move(factory), nullptr,
2324 /*quick_check_enabled=*/true);
2325
2326 auto fetcher = std::make_unique<MockPacFileFetcher>();
2327 auto* fetcher_ptr = fetcher.get();
2328 service.SetPacFileFetchers(std::move(fetcher),
2329 std::make_unique<DoNothingDhcpPacFileFetcher>());
2330
2331 // Start 3 requests.
2332
2333 ProxyInfo info1;
2334 TestCompletionCallback callback1;
2335 std::unique_ptr<ProxyResolutionRequest> request1;
2336 int rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
2337 &info1, callback1.callback(), &request1,
2338 NetLogWithSource());
2339 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2340
2341 // The first request should have triggered download of PAC script.
2342 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2343 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2344
2345 ProxyInfo info2;
2346 TestCompletionCallback callback2;
2347 std::unique_ptr<ProxyResolutionRequest> request2;
2348 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
2349 &info2, callback2.callback(), &request2,
2350 NetLogWithSource());
2351 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2352
2353 ProxyInfo info3;
2354 TestCompletionCallback callback3;
2355 std::unique_ptr<ProxyResolutionRequest> request3;
2356 rv = service.ResolveProxy(url3, std::string(), NetworkAnonymizationKey(),
2357 &info3, callback3.callback(), &request3,
2358 NetLogWithSource());
2359 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2360
2361 // Nothing has been sent to the factory yet.
2362 EXPECT_TRUE(factory_ptr->pending_requests().empty());
2363
2364 EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, request1->GetLoadState());
2365 EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, request2->GetLoadState());
2366 EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, request3->GetLoadState());
2367
2368 // At this point the ConfiguredProxyResolutionService should be waiting for
2369 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
2370 // script download completion.
2371 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
2372
2373 // Now that the PAC script is downloaded, it will have been sent to the proxy
2374 // resolver.
2375 EXPECT_EQ(kValidPacScript116,
2376 factory_ptr->pending_requests()[0]->script_data()->utf16());
2377 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2378
2379 JobMap jobs = GetPendingJobsForURLs(resolver, url1, url2, url3);
2380
2381 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request1->GetLoadState());
2382 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request2->GetLoadState());
2383 EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request3->GetLoadState());
2384
2385 // Complete all the jobs (in some order).
2386
2387 jobs[url3]->results()->UseNamedProxy("request3:80");
2388 jobs[url3]->CompleteNow(OK);
2389
2390 jobs[url1]->results()->UseNamedProxy("request1:80");
2391 jobs[url1]->CompleteNow(OK);
2392
2393 jobs[url2]->results()->UseNamedProxy("request2:80");
2394 jobs[url2]->CompleteNow(OK);
2395
2396 // Complete and verify that jobs ran as expected.
2397 EXPECT_EQ(OK, callback1.WaitForResult());
2398 // ProxyResolver::GetProxyForURL() to take a std::unique_ptr<Request>* rather
2399 // than a RequestHandle* (patchset #11 id:200001 of
2400 // https://codereview.chromium.org/1439053002/ )
2401 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
2402 EXPECT_FALSE(info1.proxy_resolve_start_time().is_null());
2403 EXPECT_FALSE(info1.proxy_resolve_end_time().is_null());
2404 EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time());
2405
2406 EXPECT_THAT(callback2.WaitForResult(), IsOk());
2407 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
2408 EXPECT_FALSE(info2.proxy_resolve_start_time().is_null());
2409 EXPECT_FALSE(info2.proxy_resolve_end_time().is_null());
2410 EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time());
2411
2412 EXPECT_THAT(callback3.WaitForResult(), IsOk());
2413 EXPECT_EQ("request3:80", ProxyServerToProxyUri(info3.proxy_server()));
2414 EXPECT_FALSE(info3.proxy_resolve_start_time().is_null());
2415 EXPECT_FALSE(info3.proxy_resolve_end_time().is_null());
2416 EXPECT_LE(info3.proxy_resolve_start_time(), info3.proxy_resolve_end_time());
2417 }
2418
2419 // Test changing the PacFileFetcher while PAC download is in progress.
TEST_F(ConfiguredProxyResolutionServiceTest,ChangeScriptFetcherWhilePACDownloadInProgress)2420 TEST_F(ConfiguredProxyResolutionServiceTest,
2421 ChangeScriptFetcherWhilePACDownloadInProgress) {
2422 const GURL url1("http://request1");
2423 const GURL url2("http://request2");
2424 auto config_service =
2425 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
2426
2427 MockAsyncProxyResolver resolver;
2428 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2429 auto* factory_ptr = factory.get();
2430
2431 ConfiguredProxyResolutionService service(std::move(config_service),
2432 std::move(factory), nullptr,
2433 /*quick_check_enabled=*/true);
2434
2435 auto fetcher = std::make_unique<MockPacFileFetcher>();
2436 auto* fetcher_ptr = fetcher.get();
2437 service.SetPacFileFetchers(std::move(fetcher),
2438 std::make_unique<DoNothingDhcpPacFileFetcher>());
2439
2440 // Start 2 jobs.
2441
2442 ProxyInfo info1;
2443 TestCompletionCallback callback1;
2444 std::unique_ptr<ProxyResolutionRequest> request1;
2445 int rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
2446 &info1, callback1.callback(), &request1,
2447 NetLogWithSource());
2448 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2449
2450 // The first request should have triggered download of PAC script.
2451 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2452 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2453
2454 ProxyInfo info2;
2455 TestCompletionCallback callback2;
2456 std::unique_ptr<ProxyResolutionRequest> request2;
2457 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
2458 &info2, callback2.callback(), &request2,
2459 NetLogWithSource());
2460 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2461
2462 // At this point the ConfiguredProxyResolutionService should be waiting for
2463 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
2464 // script download completion.
2465
2466 // We now change out the ConfiguredProxyResolutionService's script fetcher. We
2467 // should restart the initialization with the new fetcher.
2468
2469 fetcher = std::make_unique<MockPacFileFetcher>();
2470 fetcher_ptr = fetcher.get();
2471 service.SetPacFileFetchers(std::move(fetcher),
2472 std::make_unique<DoNothingDhcpPacFileFetcher>());
2473
2474 // Nothing has been sent to the factory yet.
2475 EXPECT_TRUE(factory_ptr->pending_requests().empty());
2476
2477 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
2478
2479 // Now that the PAC script is downloaded, it will have been sent to the proxy
2480 // resolver.
2481 EXPECT_EQ(kValidPacScript116,
2482 factory_ptr->pending_requests()[0]->script_data()->utf16());
2483 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2484
2485 GetPendingJobsForURLs(resolver, url1, url2);
2486 }
2487
2488 // Test cancellation of a request, while the PAC script is being fetched.
TEST_F(ConfiguredProxyResolutionServiceTest,CancelWhilePACFetching)2489 TEST_F(ConfiguredProxyResolutionServiceTest, CancelWhilePACFetching) {
2490 auto config_service =
2491 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
2492
2493 MockAsyncProxyResolver resolver;
2494 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2495 auto* factory_ptr = factory.get();
2496
2497 ConfiguredProxyResolutionService service(std::move(config_service),
2498 std::move(factory), nullptr,
2499 /*quick_check_enabled=*/true);
2500
2501 auto fetcher = std::make_unique<MockPacFileFetcher>();
2502 auto* fetcher_ptr = fetcher.get();
2503
2504 service.SetPacFileFetchers(std::move(fetcher),
2505 std::make_unique<DoNothingDhcpPacFileFetcher>());
2506
2507 // Start 3 requests.
2508 ProxyInfo info1;
2509 TestCompletionCallback callback1;
2510 std::unique_ptr<ProxyResolutionRequest> request1;
2511 RecordingNetLogObserver net_log_observer;
2512 int rv = service.ResolveProxy(GURL("http://request1"), std::string(),
2513 NetworkAnonymizationKey(), &info1,
2514 callback1.callback(), &request1,
2515 NetLogWithSource::Make(NetLogSourceType::NONE));
2516 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2517
2518 // The first request should have triggered download of PAC script.
2519 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2520 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2521
2522 ProxyInfo info2;
2523 TestCompletionCallback callback2;
2524 std::unique_ptr<ProxyResolutionRequest> request2;
2525 rv = service.ResolveProxy(
2526 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
2527 callback2.callback(), &request2, NetLogWithSource());
2528 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2529
2530 ProxyInfo info3;
2531 TestCompletionCallback callback3;
2532 std::unique_ptr<ProxyResolutionRequest> request3;
2533 rv = service.ResolveProxy(
2534 GURL("http://request3"), std::string(), NetworkAnonymizationKey(), &info3,
2535 callback3.callback(), &request3, NetLogWithSource());
2536 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2537
2538 // Nothing has been sent to the factory yet.
2539 EXPECT_TRUE(factory_ptr->pending_requests().empty());
2540
2541 // Cancel the first 2 jobs.
2542 request1.reset();
2543 request2.reset();
2544
2545 // At this point the ConfiguredProxyResolutionService should be waiting for
2546 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
2547 // script download completion.
2548 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
2549
2550 // Now that the PAC script is downloaded, it will have been sent to the
2551 // proxy resolver.
2552 EXPECT_EQ(kValidPacScript116,
2553 factory_ptr->pending_requests()[0]->script_data()->utf16());
2554 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2555
2556 ASSERT_EQ(1u, resolver.pending_jobs().size());
2557 EXPECT_EQ(GURL("http://request3"), resolver.pending_jobs()[0]->url());
2558
2559 // Complete all the jobs.
2560 resolver.pending_jobs()[0]->results()->UseNamedProxy("request3:80");
2561 resolver.pending_jobs()[0]->CompleteNow(OK);
2562
2563 EXPECT_THAT(callback3.WaitForResult(), IsOk());
2564 EXPECT_EQ("request3:80", ProxyServerToProxyUri(info3.proxy_server()));
2565
2566 EXPECT_TRUE(resolver.cancelled_jobs().empty());
2567
2568 EXPECT_FALSE(callback1.have_result()); // Cancelled.
2569 EXPECT_FALSE(callback2.have_result()); // Cancelled.
2570
2571 auto entries1 = net_log_observer.GetEntries();
2572
2573 // Check the NetLog for request 1 (which was cancelled) got filled properly.
2574 EXPECT_EQ(4u, entries1.size());
2575 EXPECT_TRUE(LogContainsBeginEvent(entries1, 0,
2576 NetLogEventType::PROXY_RESOLUTION_SERVICE));
2577 EXPECT_TRUE(LogContainsBeginEvent(
2578 entries1, 1,
2579 NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC));
2580 // Note that PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC is never completed
2581 // before the cancellation occured.
2582 EXPECT_TRUE(LogContainsEvent(entries1, 2, NetLogEventType::CANCELLED,
2583 NetLogEventPhase::NONE));
2584 EXPECT_TRUE(LogContainsEndEvent(entries1, 3,
2585 NetLogEventType::PROXY_RESOLUTION_SERVICE));
2586 }
2587
2588 // Test that if auto-detect fails, we fall-back to the custom pac.
TEST_F(ConfiguredProxyResolutionServiceTest,FallbackFromAutodetectToCustomPac)2589 TEST_F(ConfiguredProxyResolutionServiceTest,
2590 FallbackFromAutodetectToCustomPac) {
2591 const GURL url1("http://request1");
2592 const GURL url2("http://request2");
2593 ProxyConfig config;
2594 config.set_auto_detect(true);
2595 config.set_pac_url(GURL("http://foopy/proxy.pac"));
2596 config.proxy_rules().ParseFromString("http=foopy:80"); // Won't be used.
2597
2598 auto config_service = std::make_unique<MockProxyConfigService>(config);
2599 MockAsyncProxyResolver resolver;
2600 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2601 auto* factory_ptr = factory.get();
2602 ConfiguredProxyResolutionService service(std::move(config_service),
2603 std::move(factory), nullptr,
2604 /*quick_check_enabled=*/true);
2605
2606 auto fetcher = std::make_unique<MockPacFileFetcher>();
2607 auto* fetcher_ptr = fetcher.get();
2608 service.SetPacFileFetchers(std::move(fetcher),
2609 std::make_unique<DoNothingDhcpPacFileFetcher>());
2610
2611 // Start 2 requests.
2612
2613 ProxyInfo info1;
2614 TestCompletionCallback callback1;
2615 std::unique_ptr<ProxyResolutionRequest> request1;
2616 int rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
2617 &info1, callback1.callback(), &request1,
2618 NetLogWithSource());
2619 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2620
2621 ProxyInfo info2;
2622 TestCompletionCallback callback2;
2623 std::unique_ptr<ProxyResolutionRequest> request2;
2624 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
2625 &info2, callback2.callback(), &request2,
2626 NetLogWithSource());
2627 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2628
2629 // Check that nothing has been sent to the proxy resolver factory yet.
2630 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
2631
2632 // It should be trying to auto-detect first -- FAIL the autodetect during
2633 // the script download.
2634 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2635 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher_ptr->pending_request_url());
2636 fetcher_ptr->NotifyFetchCompletion(ERR_FAILED, std::string());
2637
2638 // Next it should be trying the custom PAC url.
2639 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2640 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2641 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
2642
2643 EXPECT_EQ(kValidPacScript116,
2644 factory_ptr->pending_requests()[0]->script_data()->utf16());
2645 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2646
2647 // Now finally, the pending jobs should have been sent to the resolver
2648 // (which was initialized with custom PAC script).
2649
2650 JobMap jobs = GetPendingJobsForURLs(resolver, url1, url2);
2651
2652 // Complete the pending jobs.
2653 jobs[url2]->results()->UseNamedProxy("request2:80");
2654 jobs[url2]->CompleteNow(OK);
2655 jobs[url1]->results()->UseNamedProxy("request1:80");
2656 jobs[url1]->CompleteNow(OK);
2657
2658 // Verify that jobs ran as expected.
2659 EXPECT_EQ(OK, callback1.WaitForResult());
2660 // ProxyResolver::GetProxyForURL() to take a std::unique_ptr<Request>* rather
2661 // than a RequestHandle* (patchset #11 id:200001 of
2662 // https://codereview.chromium.org/1439053002/ )
2663 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
2664 EXPECT_FALSE(info1.proxy_resolve_start_time().is_null());
2665 EXPECT_FALSE(info1.proxy_resolve_end_time().is_null());
2666 EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time());
2667
2668 EXPECT_THAT(callback2.WaitForResult(), IsOk());
2669 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
2670 EXPECT_FALSE(info2.proxy_resolve_start_time().is_null());
2671 EXPECT_FALSE(info2.proxy_resolve_end_time().is_null());
2672 EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time());
2673 }
2674
2675 // This is the same test as FallbackFromAutodetectToCustomPac, except
2676 // the auto-detect script fails parsing rather than downloading.
TEST_F(ConfiguredProxyResolutionServiceTest,FallbackFromAutodetectToCustomPac2)2677 TEST_F(ConfiguredProxyResolutionServiceTest,
2678 FallbackFromAutodetectToCustomPac2) {
2679 const GURL url1("http://request1");
2680 const GURL url2("http://request2");
2681 ProxyConfig config;
2682 config.set_auto_detect(true);
2683 config.set_pac_url(GURL("http://foopy/proxy.pac"));
2684 config.proxy_rules().ParseFromString("http=foopy:80"); // Won't be used.
2685
2686 auto config_service = std::make_unique<MockProxyConfigService>(config);
2687 MockAsyncProxyResolver resolver;
2688 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2689 auto* factory_ptr = factory.get();
2690 ConfiguredProxyResolutionService service(std::move(config_service),
2691 std::move(factory), nullptr,
2692 /*quick_check_enabled=*/true);
2693
2694 auto fetcher = std::make_unique<MockPacFileFetcher>();
2695 auto* fetcher_ptr = fetcher.get();
2696 service.SetPacFileFetchers(std::move(fetcher),
2697 std::make_unique<DoNothingDhcpPacFileFetcher>());
2698
2699 // Start 2 requests.
2700
2701 ProxyInfo info1;
2702 TestCompletionCallback callback1;
2703 std::unique_ptr<ProxyResolutionRequest> request1;
2704 int rv = service.ResolveProxy(url1, std::string(), NetworkAnonymizationKey(),
2705 &info1, callback1.callback(), &request1,
2706 NetLogWithSource());
2707 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2708
2709 ProxyInfo info2;
2710 TestCompletionCallback callback2;
2711 std::unique_ptr<ProxyResolutionRequest> request2;
2712 rv = service.ResolveProxy(url2, std::string(), NetworkAnonymizationKey(),
2713 &info2, callback2.callback(), &request2,
2714 NetLogWithSource());
2715 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2716
2717 // Check that nothing has been sent to the proxy resolver factory yet.
2718 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
2719
2720 // It should be trying to auto-detect first -- succeed the download.
2721 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2722 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher_ptr->pending_request_url());
2723 fetcher_ptr->NotifyFetchCompletion(OK, "invalid-script-contents");
2724
2725 // The script contents passed failed basic verification step (since didn't
2726 // contain token FindProxyForURL), so it was never passed to the resolver.
2727
2728 // Next it should be trying the custom PAC url.
2729 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2730 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2731 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
2732
2733 EXPECT_EQ(kValidPacScript116,
2734 factory_ptr->pending_requests()[0]->script_data()->utf16());
2735 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2736
2737 // Now finally, the pending jobs should have been sent to the resolver
2738 // (which was initialized with custom PAC script).
2739
2740 JobMap jobs = GetPendingJobsForURLs(resolver, url1, url2);
2741
2742 // Complete the pending jobs.
2743 jobs[url2]->results()->UseNamedProxy("request2:80");
2744 jobs[url2]->CompleteNow(OK);
2745 jobs[url1]->results()->UseNamedProxy("request1:80");
2746 jobs[url1]->CompleteNow(OK);
2747
2748 // Verify that jobs ran as expected.
2749 EXPECT_EQ(OK, callback1.WaitForResult());
2750 // ProxyResolver::GetProxyForURL() to take a std::unique_ptr<Request>* rather
2751 // than a RequestHandle* (patchset #11 id:200001 of
2752 // https://codereview.chromium.org/1439053002/ )
2753 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
2754
2755 EXPECT_THAT(callback2.WaitForResult(), IsOk());
2756 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
2757 }
2758
2759 // Test that if all of auto-detect, a custom PAC script, and manual settings
2760 // are given, then we will try them in that order.
TEST_F(ConfiguredProxyResolutionServiceTest,FallbackFromAutodetectToCustomToManual)2761 TEST_F(ConfiguredProxyResolutionServiceTest,
2762 FallbackFromAutodetectToCustomToManual) {
2763 ProxyConfig config;
2764 config.set_auto_detect(true);
2765 config.set_pac_url(GURL("http://foopy/proxy.pac"));
2766 config.proxy_rules().ParseFromString("http=foopy:80");
2767
2768 auto config_service = std::make_unique<MockProxyConfigService>(config);
2769 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2770 auto* factory_ptr = factory.get();
2771 ConfiguredProxyResolutionService service(std::move(config_service),
2772 std::move(factory), nullptr,
2773 /*quick_check_enabled=*/true);
2774
2775 auto fetcher = std::make_unique<MockPacFileFetcher>();
2776 auto* fetcher_ptr = fetcher.get();
2777 service.SetPacFileFetchers(std::move(fetcher),
2778 std::make_unique<DoNothingDhcpPacFileFetcher>());
2779
2780 // Start 2 jobs.
2781
2782 ProxyInfo info1;
2783 TestCompletionCallback callback1;
2784 std::unique_ptr<ProxyResolutionRequest> request1;
2785 int rv = service.ResolveProxy(
2786 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
2787 callback1.callback(), &request1, NetLogWithSource());
2788 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2789
2790 ProxyInfo info2;
2791 TestCompletionCallback callback2;
2792 std::unique_ptr<ProxyResolutionRequest> request2;
2793 rv = service.ResolveProxy(
2794 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
2795 callback2.callback(), &request2, NetLogWithSource());
2796 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2797
2798 // Check that nothing has been sent to the proxy resolver factory yet.
2799 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
2800
2801 // It should be trying to auto-detect first -- fail the download.
2802 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2803 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher_ptr->pending_request_url());
2804 fetcher_ptr->NotifyFetchCompletion(ERR_FAILED, std::string());
2805
2806 // Next it should be trying the custom PAC url -- fail the download.
2807 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2808 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2809 fetcher_ptr->NotifyFetchCompletion(ERR_FAILED, std::string());
2810
2811 // Since we never managed to initialize a resolver, nothing should have been
2812 // sent to it.
2813 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
2814
2815 // Verify that jobs ran as expected -- they should have fallen back to
2816 // the manual proxy configuration for HTTP urls.
2817 EXPECT_THAT(callback1.WaitForResult(), IsOk());
2818 EXPECT_EQ("foopy:80", ProxyServerToProxyUri(info1.proxy_server()));
2819
2820 EXPECT_THAT(callback2.WaitForResult(), IsOk());
2821 EXPECT_EQ("foopy:80", ProxyServerToProxyUri(info2.proxy_server()));
2822 }
2823
2824 // Test that the bypass rules are NOT applied when using autodetect.
TEST_F(ConfiguredProxyResolutionServiceTest,BypassDoesntApplyToPac)2825 TEST_F(ConfiguredProxyResolutionServiceTest, BypassDoesntApplyToPac) {
2826 ProxyConfig config;
2827 config.set_auto_detect(true);
2828 config.set_pac_url(GURL("http://foopy/proxy.pac"));
2829 config.proxy_rules().ParseFromString("http=foopy:80"); // Not used.
2830 config.proxy_rules().bypass_rules.ParseFromString("www.google.com");
2831
2832 auto config_service = std::make_unique<MockProxyConfigService>(config);
2833 MockAsyncProxyResolver resolver;
2834 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2835 auto* factory_ptr = factory.get();
2836 ConfiguredProxyResolutionService service(std::move(config_service),
2837 std::move(factory), nullptr,
2838 /*quick_check_enabled=*/true);
2839
2840 auto fetcher = std::make_unique<MockPacFileFetcher>();
2841 auto* fetcher_ptr = fetcher.get();
2842 service.SetPacFileFetchers(std::move(fetcher),
2843 std::make_unique<DoNothingDhcpPacFileFetcher>());
2844
2845 // Start 1 requests.
2846
2847 ProxyInfo info1;
2848 TestCompletionCallback callback1;
2849 std::unique_ptr<ProxyResolutionRequest> request1;
2850 int rv = service.ResolveProxy(
2851 GURL("http://www.google.com"), std::string(), NetworkAnonymizationKey(),
2852 &info1, callback1.callback(), &request1, NetLogWithSource());
2853 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2854
2855 // Check that nothing has been sent to the proxy resolver factory yet.
2856 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
2857
2858 // It should be trying to auto-detect first -- succeed the download.
2859 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2860 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher_ptr->pending_request_url());
2861 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
2862
2863 EXPECT_EQ(kValidPacScript116,
2864 factory_ptr->pending_requests()[0]->script_data()->utf16());
2865 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2866
2867 ASSERT_EQ(1u, resolver.pending_jobs().size());
2868 EXPECT_EQ(GURL("http://www.google.com"), resolver.pending_jobs()[0]->url());
2869
2870 // Complete the pending request.
2871 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
2872 resolver.pending_jobs()[0]->CompleteNow(OK);
2873
2874 // Verify that request ran as expected.
2875 EXPECT_THAT(callback1.WaitForResult(), IsOk());
2876 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
2877
2878 // Start another request, it should pickup the bypass item.
2879 ProxyInfo info2;
2880 TestCompletionCallback callback2;
2881 std::unique_ptr<ProxyResolutionRequest> request2;
2882 rv = service.ResolveProxy(
2883 GURL("http://www.google.com"), std::string(), NetworkAnonymizationKey(),
2884 &info2, callback2.callback(), &request2, NetLogWithSource());
2885 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2886
2887 ASSERT_EQ(1u, resolver.pending_jobs().size());
2888 EXPECT_EQ(GURL("http://www.google.com"), resolver.pending_jobs()[0]->url());
2889
2890 // Complete the pending request.
2891 resolver.pending_jobs()[0]->results()->UseNamedProxy("request2:80");
2892 resolver.pending_jobs()[0]->CompleteNow(OK);
2893
2894 EXPECT_THAT(callback2.WaitForResult(), IsOk());
2895 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
2896 }
2897
2898 // Delete the ConfiguredProxyResolutionService while InitProxyResolver has an
2899 // outstanding request to the script fetcher. When run under valgrind, should
2900 // not have any memory errors (used to be that the PacFileFetcher was being
2901 // deleted prior to the InitProxyResolver).
TEST_F(ConfiguredProxyResolutionServiceTest,DeleteWhileInitProxyResolverHasOutstandingFetch)2902 TEST_F(ConfiguredProxyResolutionServiceTest,
2903 DeleteWhileInitProxyResolverHasOutstandingFetch) {
2904 ProxyConfig config =
2905 ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
2906
2907 auto config_service = std::make_unique<MockProxyConfigService>(config);
2908 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
2909 auto* factory_ptr = factory.get();
2910 ConfiguredProxyResolutionService service(std::move(config_service),
2911 std::move(factory), nullptr,
2912 /*quick_check_enabled=*/true);
2913
2914 auto fetcher = std::make_unique<MockPacFileFetcher>();
2915 auto* fetcher_ptr = fetcher.get();
2916 service.SetPacFileFetchers(std::move(fetcher),
2917 std::make_unique<DoNothingDhcpPacFileFetcher>());
2918
2919 // Start 1 request.
2920
2921 ProxyInfo info1;
2922 TestCompletionCallback callback1;
2923 std::unique_ptr<ProxyResolutionRequest> request1;
2924 int rv = service.ResolveProxy(
2925 GURL("http://www.google.com"), std::string(), NetworkAnonymizationKey(),
2926 &info1, callback1.callback(), &request1, NetLogWithSource());
2927 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2928
2929 // Check that nothing has been sent to the proxy resolver factory yet.
2930 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
2931
2932 // InitProxyResolver should have issued a request to the PacFileFetcher
2933 // and be waiting on that to complete.
2934 EXPECT_TRUE(fetcher_ptr->has_pending_request());
2935 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
2936 }
2937
2938 // Delete the ConfiguredProxyResolutionService while InitProxyResolver has an
2939 // outstanding request to the proxy resolver. When run under valgrind, should
2940 // not have any memory errors (used to be that the ProxyResolver was being
2941 // deleted prior to the InitProxyResolver).
TEST_F(ConfiguredProxyResolutionServiceTest,DeleteWhileInitProxyResolverHasOutstandingSet)2942 TEST_F(ConfiguredProxyResolutionServiceTest,
2943 DeleteWhileInitProxyResolverHasOutstandingSet) {
2944 auto config_service =
2945 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
2946
2947 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
2948 auto* factory_ptr = factory.get();
2949
2950 ConfiguredProxyResolutionService service(std::move(config_service),
2951 std::move(factory), nullptr,
2952 /*quick_check_enabled=*/true);
2953
2954 GURL url("http://www.google.com/");
2955
2956 ProxyInfo info;
2957 TestCompletionCallback callback;
2958 std::unique_ptr<ProxyResolutionRequest> request;
2959 int rv =
2960 service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(), &info,
2961 callback.callback(), &request, NetLogWithSource());
2962 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2963
2964 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
2965 factory_ptr->pending_requests()[0]->script_data()->url());
2966 }
2967
2968 // Test that when going from a configuration that required PAC to one
2969 // that does NOT, we unset the variable |should_use_proxy_resolver_|.
TEST_F(ConfiguredProxyResolutionServiceTest,UpdateConfigFromPACToDirect)2970 TEST_F(ConfiguredProxyResolutionServiceTest, UpdateConfigFromPACToDirect) {
2971 ProxyConfig config = ProxyConfig::CreateAutoDetect();
2972
2973 auto config_service = std::make_unique<MockProxyConfigService>(config);
2974 auto* config_service_ptr = config_service.get();
2975 MockAsyncProxyResolver resolver;
2976 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
2977 auto* factory_ptr = factory.get();
2978 ConfiguredProxyResolutionService service(std::move(config_service),
2979 std::move(factory), nullptr,
2980 /*quick_check_enabled=*/true);
2981
2982 // Start 1 request.
2983
2984 ProxyInfo info1;
2985 TestCompletionCallback callback1;
2986 std::unique_ptr<ProxyResolutionRequest> request1;
2987 int rv = service.ResolveProxy(
2988 GURL("http://www.google.com"), std::string(), NetworkAnonymizationKey(),
2989 &info1, callback1.callback(), &request1, NetLogWithSource());
2990 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2991
2992 // Successfully set the autodetect script.
2993 EXPECT_EQ(PacFileData::TYPE_AUTO_DETECT,
2994 factory_ptr->pending_requests()[0]->script_data()->type());
2995 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
2996
2997 // Complete the pending request.
2998 ASSERT_EQ(1u, resolver.pending_jobs().size());
2999 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
3000 resolver.pending_jobs()[0]->CompleteNow(OK);
3001
3002 // Verify that request ran as expected.
3003 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3004 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
3005
3006 // Force the ConfiguredProxyResolutionService to pull down a new proxy
3007 // configuration. (Even though the configuration isn't old/bad).
3008 //
3009 // This new configuration no longer has auto_detect set, so
3010 // jobs should complete synchronously now as direct-connect.
3011 config_service_ptr->SetConfig(ProxyConfigWithAnnotation::CreateDirect());
3012
3013 // Start another request -- the effective configuration has changed.
3014 ProxyInfo info2;
3015 TestCompletionCallback callback2;
3016 std::unique_ptr<ProxyResolutionRequest> request2;
3017 rv = service.ResolveProxy(
3018 GURL("http://www.google.com"), std::string(), NetworkAnonymizationKey(),
3019 &info2, callback2.callback(), &request2, NetLogWithSource());
3020 EXPECT_THAT(rv, IsOk());
3021
3022 EXPECT_TRUE(info2.is_direct());
3023 }
3024
TEST_F(ConfiguredProxyResolutionServiceTest,NetworkChangeTriggersPacRefetch)3025 TEST_F(ConfiguredProxyResolutionServiceTest, NetworkChangeTriggersPacRefetch) {
3026 auto config_service =
3027 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3028
3029 MockAsyncProxyResolver resolver;
3030 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
3031 auto* factory_ptr = factory.get();
3032
3033 RecordingNetLogObserver observer;
3034
3035 ConfiguredProxyResolutionService service(
3036 std::move(config_service), std::move(factory), net::NetLog::Get(),
3037 /*quick_check_enabled=*/true);
3038
3039 auto fetcher = std::make_unique<MockPacFileFetcher>();
3040 auto* fetcher_ptr = fetcher.get();
3041 service.SetPacFileFetchers(std::move(fetcher),
3042 std::make_unique<DoNothingDhcpPacFileFetcher>());
3043
3044 // Disable the "wait after IP address changes" hack, so this unit-test can
3045 // complete quickly.
3046 service.set_stall_proxy_auto_config_delay(base::TimeDelta());
3047
3048 // Start 1 request.
3049
3050 ProxyInfo info1;
3051 TestCompletionCallback callback1;
3052 std::unique_ptr<ProxyResolutionRequest> request1;
3053 int rv = service.ResolveProxy(
3054 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3055 callback1.callback(), &request1, NetLogWithSource());
3056 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3057
3058 // The first request should have triggered initial download of PAC script.
3059 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3060 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3061
3062 // Nothing has been sent to the factory yet.
3063 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3064
3065 // At this point the ConfiguredProxyResolutionService should be waiting for
3066 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
3067 // script download completion.
3068 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3069
3070 // Now that the PAC script is downloaded, the request will have been sent to
3071 // the proxy resolver.
3072 EXPECT_EQ(kValidPacScript116,
3073 factory_ptr->pending_requests()[0]->script_data()->utf16());
3074 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3075
3076 ASSERT_EQ(1u, resolver.pending_jobs().size());
3077 EXPECT_EQ(GURL("http://request1"), resolver.pending_jobs()[0]->url());
3078
3079 // Complete the pending request.
3080 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
3081 resolver.pending_jobs()[0]->CompleteNow(OK);
3082
3083 // Wait for completion callback, and verify that the request ran as expected.
3084 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3085 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
3086
3087 // Now simluate a change in the network. The ProxyConfigService is still
3088 // going to return the same PAC URL as before, but this URL needs to be
3089 // refetched on the new network.
3090 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
3091 base::RunLoop().RunUntilIdle(); // Notification happens async.
3092
3093 // Start a second request.
3094 ProxyInfo info2;
3095 TestCompletionCallback callback2;
3096 std::unique_ptr<ProxyResolutionRequest> request2;
3097 rv = service.ResolveProxy(
3098 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3099 callback2.callback(), &request2, NetLogWithSource());
3100 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3101
3102 // This second request should have triggered the re-download of the PAC
3103 // script (since we marked the network as having changed).
3104 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3105 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3106
3107 // Nothing has been sent to the factory yet.
3108 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3109
3110 // Simulate the PAC script fetch as having completed (this time with
3111 // different data).
3112 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript2);
3113
3114 // Now that the PAC script is downloaded, the second request will have been
3115 // sent to the proxy resolver.
3116 EXPECT_EQ(kValidPacScript216,
3117 factory_ptr->pending_requests()[0]->script_data()->utf16());
3118 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3119
3120 ASSERT_EQ(1u, resolver.pending_jobs().size());
3121 EXPECT_EQ(GURL("http://request2"), resolver.pending_jobs()[0]->url());
3122
3123 // Complete the pending second request.
3124 resolver.pending_jobs()[0]->results()->UseNamedProxy("request2:80");
3125 resolver.pending_jobs()[0]->CompleteNow(OK);
3126
3127 // Wait for completion callback, and verify that the request ran as expected.
3128 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3129 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
3130
3131 // Check that the expected events were output to the log stream. In particular
3132 // PROXY_CONFIG_CHANGED should have only been emitted once (for the initial
3133 // setup), and NOT a second time when the IP address changed.
3134 auto entries = observer.GetEntries();
3135
3136 EXPECT_TRUE(LogContainsEntryWithType(entries, 0,
3137 NetLogEventType::PROXY_CONFIG_CHANGED));
3138 ASSERT_EQ(9u, entries.size());
3139 for (size_t i = 1; i < entries.size(); ++i)
3140 EXPECT_NE(NetLogEventType::PROXY_CONFIG_CHANGED, entries[i].type);
3141 }
3142
3143 // This test verifies that the PAC script specified by the settings is
3144 // periodically polled for changes. Specifically, if the initial fetch fails due
3145 // to a network error, we will eventually re-configure the service to use the
3146 // script once it becomes available.
TEST_F(ConfiguredProxyResolutionServiceTest,PACScriptRefetchAfterFailure)3147 TEST_F(ConfiguredProxyResolutionServiceTest, PACScriptRefetchAfterFailure) {
3148 // Change the retry policy to wait a mere 1 ms before retrying, so the test
3149 // runs quickly.
3150 ImmediatePollPolicy poll_policy;
3151 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3152
3153 auto config_service =
3154 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3155
3156 MockAsyncProxyResolver resolver;
3157 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
3158 auto* factory_ptr = factory.get();
3159
3160 ConfiguredProxyResolutionService service(std::move(config_service),
3161 std::move(factory), nullptr,
3162 /*quick_check_enabled=*/true);
3163
3164 auto fetcher = std::make_unique<MockPacFileFetcher>();
3165 auto* fetcher_ptr = fetcher.get();
3166 service.SetPacFileFetchers(std::move(fetcher),
3167 std::make_unique<DoNothingDhcpPacFileFetcher>());
3168
3169 // Start 1 request.
3170
3171 ProxyInfo info1;
3172 TestCompletionCallback callback1;
3173 std::unique_ptr<ProxyResolutionRequest> request1;
3174 int rv = service.ResolveProxy(
3175 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3176 callback1.callback(), &request1, NetLogWithSource());
3177 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3178
3179 // The first request should have triggered initial download of PAC script.
3180 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3181 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3182
3183 // Nothing has been sent to the factory yet.
3184 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3185
3186 // At this point the ConfiguredProxyResolutionService should be waiting for
3187 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
3188 // script download completion.
3189 //
3190 // We simulate a failed download attempt, the proxy service should now
3191 // fall-back to DIRECT connections.
3192 fetcher_ptr->NotifyFetchCompletion(ERR_FAILED, std::string());
3193
3194 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3195
3196 // Wait for completion callback, and verify it used DIRECT.
3197 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3198 EXPECT_TRUE(info1.is_direct());
3199
3200 // At this point we have initialized the proxy service using a PAC script,
3201 // however it failed and fell-back to DIRECT.
3202 //
3203 // A background task to periodically re-check the PAC script for validity will
3204 // have been started. We will now wait for the next download attempt to start.
3205 //
3206 // Note that we shouldn't have to wait long here, since our test enables a
3207 // special unit-test mode.
3208 fetcher_ptr->WaitUntilFetch();
3209
3210 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3211
3212 // Make sure that our background checker is trying to download the expected
3213 // PAC script (same one as before). This time we will simulate a successful
3214 // download of the script.
3215 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3216 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3217 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3218
3219 base::RunLoop().RunUntilIdle();
3220
3221 // Now that the PAC script is downloaded, it should be used to initialize the
3222 // ProxyResolver. Simulate a successful parse.
3223 EXPECT_EQ(kValidPacScript116,
3224 factory_ptr->pending_requests()[0]->script_data()->utf16());
3225 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3226
3227 // At this point the ConfiguredProxyResolutionService should have
3228 // re-configured itself to use the PAC script (thereby recovering from the
3229 // initial fetch failure). We will verify that the next Resolve request uses
3230 // the resolver rather than DIRECT.
3231
3232 // Start a second request.
3233 ProxyInfo info2;
3234 TestCompletionCallback callback2;
3235 std::unique_ptr<ProxyResolutionRequest> request2;
3236 rv = service.ResolveProxy(
3237 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3238 callback2.callback(), &request2, NetLogWithSource());
3239 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3240
3241 // Check that it was sent to the resolver.
3242 ASSERT_EQ(1u, resolver.pending_jobs().size());
3243 EXPECT_EQ(GURL("http://request2"), resolver.pending_jobs()[0]->url());
3244
3245 // Complete the pending second request.
3246 resolver.pending_jobs()[0]->results()->UseNamedProxy("request2:80");
3247 resolver.pending_jobs()[0]->CompleteNow(OK);
3248
3249 // Wait for completion callback, and verify that the request ran as expected.
3250 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3251 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
3252 }
3253
3254 // This test verifies that the PAC script specified by the settings is
3255 // periodically polled for changes. Specifically, if the initial fetch succeeds,
3256 // however at a later time its *contents* change, we will eventually
3257 // re-configure the service to use the new script.
TEST_F(ConfiguredProxyResolutionServiceTest,PACScriptRefetchAfterContentChange)3258 TEST_F(ConfiguredProxyResolutionServiceTest,
3259 PACScriptRefetchAfterContentChange) {
3260 // Change the retry policy to wait a mere 1 ms before retrying, so the test
3261 // runs quickly.
3262 ImmediatePollPolicy poll_policy;
3263 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3264
3265 auto config_service =
3266 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3267
3268 MockAsyncProxyResolver resolver;
3269 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
3270 auto* factory_ptr = factory.get();
3271
3272 ConfiguredProxyResolutionService service(std::move(config_service),
3273 std::move(factory), nullptr,
3274 /*quick_check_enabled=*/true);
3275
3276 auto fetcher = std::make_unique<MockPacFileFetcher>();
3277 auto* fetcher_ptr = fetcher.get();
3278 service.SetPacFileFetchers(std::move(fetcher),
3279 std::make_unique<DoNothingDhcpPacFileFetcher>());
3280
3281 // Start 1 request.
3282
3283 ProxyInfo info1;
3284 TestCompletionCallback callback1;
3285 std::unique_ptr<ProxyResolutionRequest> request1;
3286 int rv = service.ResolveProxy(
3287 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3288 callback1.callback(), &request1, NetLogWithSource());
3289 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3290
3291 // The first request should have triggered initial download of PAC script.
3292 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3293 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3294
3295 // Nothing has been sent to the factory yet.
3296 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3297
3298 // At this point the ConfiguredProxyResolutionService should be waiting for
3299 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
3300 // script download completion.
3301 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3302
3303 // Now that the PAC script is downloaded, the request will have been sent to
3304 // the proxy resolver.
3305 EXPECT_EQ(kValidPacScript116,
3306 factory_ptr->pending_requests()[0]->script_data()->utf16());
3307 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3308
3309 ASSERT_EQ(1u, resolver.pending_jobs().size());
3310 EXPECT_EQ(GURL("http://request1"), resolver.pending_jobs()[0]->url());
3311
3312 // Complete the pending request.
3313 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
3314 resolver.pending_jobs()[0]->CompleteNow(OK);
3315
3316 // Wait for completion callback, and verify that the request ran as expected.
3317 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3318 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
3319
3320 // At this point we have initialized the proxy service using a PAC script.
3321 //
3322 // A background task to periodically re-check the PAC script for validity will
3323 // have been started. We will now wait for the next download attempt to start.
3324 //
3325 // Note that we shouldn't have to wait long here, since our test enables a
3326 // special unit-test mode.
3327 fetcher_ptr->WaitUntilFetch();
3328
3329 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3330 ASSERT_TRUE(resolver.pending_jobs().empty());
3331
3332 // Make sure that our background checker is trying to download the expected
3333 // PAC script (same one as before). This time we will simulate a successful
3334 // download of a DIFFERENT script.
3335 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3336 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3337 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript2);
3338
3339 base::RunLoop().RunUntilIdle();
3340
3341 // Now that the PAC script is downloaded, it should be used to initialize the
3342 // ProxyResolver. Simulate a successful parse.
3343 EXPECT_EQ(kValidPacScript216,
3344 factory_ptr->pending_requests()[0]->script_data()->utf16());
3345 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3346
3347 // At this point the ConfiguredProxyResolutionService should have
3348 // re-configured itself to use the new PAC script.
3349
3350 // Start a second request.
3351 ProxyInfo info2;
3352 TestCompletionCallback callback2;
3353 std::unique_ptr<ProxyResolutionRequest> request2;
3354 rv = service.ResolveProxy(
3355 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3356 callback2.callback(), &request2, NetLogWithSource());
3357 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3358
3359 // Check that it was sent to the resolver.
3360 ASSERT_EQ(1u, resolver.pending_jobs().size());
3361 EXPECT_EQ(GURL("http://request2"), resolver.pending_jobs()[0]->url());
3362
3363 // Complete the pending second request.
3364 resolver.pending_jobs()[0]->results()->UseNamedProxy("request2:80");
3365 resolver.pending_jobs()[0]->CompleteNow(OK);
3366
3367 // Wait for completion callback, and verify that the request ran as expected.
3368 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3369 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
3370 }
3371
3372 // This test verifies that the PAC script specified by the settings is
3373 // periodically polled for changes. Specifically, if the initial fetch succeeds
3374 // and so does the next poll, however the contents of the downloaded script
3375 // have NOT changed, then we do not bother to re-initialize the proxy resolver.
TEST_F(ConfiguredProxyResolutionServiceTest,PACScriptRefetchAfterContentUnchanged)3376 TEST_F(ConfiguredProxyResolutionServiceTest,
3377 PACScriptRefetchAfterContentUnchanged) {
3378 // Change the retry policy to wait a mere 1 ms before retrying, so the test
3379 // runs quickly.
3380 ImmediatePollPolicy poll_policy;
3381 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3382
3383 auto config_service =
3384 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3385
3386 MockAsyncProxyResolver resolver;
3387 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
3388 auto* factory_ptr = factory.get();
3389
3390 ConfiguredProxyResolutionService service(std::move(config_service),
3391 std::move(factory), nullptr,
3392 /*quick_check_enabled=*/true);
3393
3394 auto fetcher = std::make_unique<MockPacFileFetcher>();
3395 auto* fetcher_ptr = fetcher.get();
3396 service.SetPacFileFetchers(std::move(fetcher),
3397 std::make_unique<DoNothingDhcpPacFileFetcher>());
3398
3399 // Start 1 request.
3400
3401 ProxyInfo info1;
3402 TestCompletionCallback callback1;
3403 std::unique_ptr<ProxyResolutionRequest> request1;
3404 int rv = service.ResolveProxy(
3405 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3406 callback1.callback(), &request1, NetLogWithSource());
3407 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3408
3409 // The first request should have triggered initial download of PAC script.
3410 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3411 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3412
3413 // Nothing has been sent to the factory yet.
3414 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3415
3416 // At this point the ConfiguredProxyResolutionService should be waiting for
3417 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
3418 // script download completion.
3419 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3420
3421 // Now that the PAC script is downloaded, the request will have been sent to
3422 // the proxy resolver.
3423 EXPECT_EQ(kValidPacScript116,
3424 factory_ptr->pending_requests()[0]->script_data()->utf16());
3425 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3426
3427 ASSERT_EQ(1u, resolver.pending_jobs().size());
3428 EXPECT_EQ(GURL("http://request1"), resolver.pending_jobs()[0]->url());
3429
3430 // Complete the pending request.
3431 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
3432 resolver.pending_jobs()[0]->CompleteNow(OK);
3433
3434 // Wait for completion callback, and verify that the request ran as expected.
3435 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3436 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
3437
3438 // At this point we have initialized the proxy service using a PAC script.
3439 //
3440 // A background task to periodically re-check the PAC script for validity will
3441 // have been started. We will now wait for the next download attempt to start.
3442 //
3443 // Note that we shouldn't have to wait long here, since our test enables a
3444 // special unit-test mode.
3445 fetcher_ptr->WaitUntilFetch();
3446
3447 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3448 ASSERT_TRUE(resolver.pending_jobs().empty());
3449
3450 // Make sure that our background checker is trying to download the expected
3451 // PAC script (same one as before). We will simulate the same response as
3452 // last time (i.e. the script is unchanged).
3453 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3454 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3455 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3456
3457 base::RunLoop().RunUntilIdle();
3458
3459 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3460 ASSERT_TRUE(resolver.pending_jobs().empty());
3461
3462 // At this point the ConfiguredProxyResolutionService is still running the
3463 // same PAC script as before.
3464
3465 // Start a second request.
3466 ProxyInfo info2;
3467 TestCompletionCallback callback2;
3468 std::unique_ptr<ProxyResolutionRequest> request2;
3469 rv = service.ResolveProxy(
3470 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3471 callback2.callback(), &request2, NetLogWithSource());
3472 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3473
3474 // Check that it was sent to the resolver.
3475 ASSERT_EQ(1u, resolver.pending_jobs().size());
3476 EXPECT_EQ(GURL("http://request2"), resolver.pending_jobs()[0]->url());
3477
3478 // Complete the pending second request.
3479 resolver.pending_jobs()[0]->results()->UseNamedProxy("request2:80");
3480 resolver.pending_jobs()[0]->CompleteNow(OK);
3481
3482 // Wait for completion callback, and verify that the request ran as expected.
3483 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3484 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
3485 }
3486
3487 // This test verifies that the PAC script specified by the settings is
3488 // periodically polled for changes. Specifically, if the initial fetch succeeds,
3489 // however at a later time it starts to fail, we should re-configure the
3490 // ConfiguredProxyResolutionService to stop using that PAC script.
TEST_F(ConfiguredProxyResolutionServiceTest,PACScriptRefetchAfterSuccess)3491 TEST_F(ConfiguredProxyResolutionServiceTest, PACScriptRefetchAfterSuccess) {
3492 // Change the retry policy to wait a mere 1 ms before retrying, so the test
3493 // runs quickly.
3494 ImmediatePollPolicy poll_policy;
3495 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3496
3497 auto config_service =
3498 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3499
3500 MockAsyncProxyResolver resolver;
3501 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
3502 auto* factory_ptr = factory.get();
3503
3504 ConfiguredProxyResolutionService service(std::move(config_service),
3505 std::move(factory), nullptr,
3506 /*quick_check_enabled=*/true);
3507
3508 auto fetcher = std::make_unique<MockPacFileFetcher>();
3509 auto* fetcher_ptr = fetcher.get();
3510 service.SetPacFileFetchers(std::move(fetcher),
3511 std::make_unique<DoNothingDhcpPacFileFetcher>());
3512
3513 // Start 1 request.
3514
3515 ProxyInfo info1;
3516 TestCompletionCallback callback1;
3517 std::unique_ptr<ProxyResolutionRequest> request1;
3518 int rv = service.ResolveProxy(
3519 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3520 callback1.callback(), &request1, NetLogWithSource());
3521 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3522
3523 // The first request should have triggered initial download of PAC script.
3524 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3525 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3526
3527 // Nothing has been sent to the factory yet.
3528 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3529
3530 // At this point the ConfiguredProxyResolutionService should be waiting for
3531 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
3532 // script download completion.
3533 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3534
3535 // Now that the PAC script is downloaded, the request will have been sent to
3536 // the proxy resolver.
3537 EXPECT_EQ(kValidPacScript116,
3538 factory_ptr->pending_requests()[0]->script_data()->utf16());
3539 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3540
3541 ASSERT_EQ(1u, resolver.pending_jobs().size());
3542 EXPECT_EQ(GURL("http://request1"), resolver.pending_jobs()[0]->url());
3543
3544 // Complete the pending request.
3545 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
3546 resolver.pending_jobs()[0]->CompleteNow(OK);
3547
3548 // Wait for completion callback, and verify that the request ran as expected.
3549 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3550 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
3551
3552 // At this point we have initialized the proxy service using a PAC script.
3553 //
3554 // A background task to periodically re-check the PAC script for validity will
3555 // have been started. We will now wait for the next download attempt to start.
3556 //
3557 // Note that we shouldn't have to wait long here, since our test enables a
3558 // special unit-test mode.
3559 fetcher_ptr->WaitUntilFetch();
3560
3561 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3562 ASSERT_TRUE(resolver.pending_jobs().empty());
3563
3564 // Make sure that our background checker is trying to download the expected
3565 // PAC script (same one as before). This time we will simulate a failure
3566 // to download the script.
3567 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3568 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3569 fetcher_ptr->NotifyFetchCompletion(ERR_FAILED, std::string());
3570
3571 base::RunLoop().RunUntilIdle();
3572
3573 // At this point the ConfiguredProxyResolutionService should have
3574 // re-configured itself to use DIRECT connections rather than the given proxy
3575 // resolver.
3576
3577 // Start a second request.
3578 ProxyInfo info2;
3579 TestCompletionCallback callback2;
3580 std::unique_ptr<ProxyResolutionRequest> request2;
3581 rv = service.ResolveProxy(
3582 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3583 callback2.callback(), &request2, NetLogWithSource());
3584 EXPECT_THAT(rv, IsOk());
3585 EXPECT_TRUE(info2.is_direct());
3586 }
3587
3588 // Tests that the code which decides at what times to poll the PAC
3589 // script follows the expected policy.
TEST_F(ConfiguredProxyResolutionServiceTest,PACScriptPollingPolicy)3590 TEST_F(ConfiguredProxyResolutionServiceTest, PACScriptPollingPolicy) {
3591 // Retrieve the internal polling policy implementation used by
3592 // ConfiguredProxyResolutionService.
3593 std::unique_ptr<ConfiguredProxyResolutionService::PacPollPolicy> policy =
3594 ConfiguredProxyResolutionService::CreateDefaultPacPollPolicy();
3595
3596 int error;
3597 ConfiguredProxyResolutionService::PacPollPolicy::Mode mode;
3598 const base::TimeDelta initial_delay = base::Milliseconds(-1);
3599 base::TimeDelta delay = initial_delay;
3600
3601 // --------------------------------------------------
3602 // Test the poll sequence in response to a failure.
3603 // --------------------------------------------------
3604 error = ERR_NAME_NOT_RESOLVED;
3605
3606 // Poll #0
3607 mode = policy->GetNextDelay(error, initial_delay, &delay);
3608 EXPECT_EQ(8, delay.InSeconds());
3609 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::MODE_USE_TIMER,
3610 mode);
3611
3612 // Poll #1
3613 mode = policy->GetNextDelay(error, delay, &delay);
3614 EXPECT_EQ(32, delay.InSeconds());
3615 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3616 MODE_START_AFTER_ACTIVITY,
3617 mode);
3618
3619 // Poll #2
3620 mode = policy->GetNextDelay(error, delay, &delay);
3621 EXPECT_EQ(120, delay.InSeconds());
3622 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3623 MODE_START_AFTER_ACTIVITY,
3624 mode);
3625
3626 // Poll #3
3627 mode = policy->GetNextDelay(error, delay, &delay);
3628 EXPECT_EQ(14400, delay.InSeconds());
3629 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3630 MODE_START_AFTER_ACTIVITY,
3631 mode);
3632
3633 // Poll #4
3634 mode = policy->GetNextDelay(error, delay, &delay);
3635 EXPECT_EQ(14400, delay.InSeconds());
3636 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3637 MODE_START_AFTER_ACTIVITY,
3638 mode);
3639
3640 // --------------------------------------------------
3641 // Test the poll sequence in response to a success.
3642 // --------------------------------------------------
3643 error = OK;
3644
3645 // Poll #0
3646 mode = policy->GetNextDelay(error, initial_delay, &delay);
3647 EXPECT_EQ(43200, delay.InSeconds());
3648 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3649 MODE_START_AFTER_ACTIVITY,
3650 mode);
3651
3652 // Poll #1
3653 mode = policy->GetNextDelay(error, delay, &delay);
3654 EXPECT_EQ(43200, delay.InSeconds());
3655 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3656 MODE_START_AFTER_ACTIVITY,
3657 mode);
3658
3659 // Poll #2
3660 mode = policy->GetNextDelay(error, delay, &delay);
3661 EXPECT_EQ(43200, delay.InSeconds());
3662 EXPECT_EQ(ConfiguredProxyResolutionService::PacPollPolicy::
3663 MODE_START_AFTER_ACTIVITY,
3664 mode);
3665 }
3666
3667 // This tests the polling of the PAC script. Specifically, it tests that
3668 // polling occurs in response to user activity.
TEST_F(ConfiguredProxyResolutionServiceTest,PACScriptRefetchAfterActivity)3669 TEST_F(ConfiguredProxyResolutionServiceTest, PACScriptRefetchAfterActivity) {
3670 ImmediateAfterActivityPollPolicy poll_policy;
3671 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3672
3673 auto config_service =
3674 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3675
3676 MockAsyncProxyResolver resolver;
3677 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
3678 auto* factory_ptr = factory.get();
3679
3680 ConfiguredProxyResolutionService service(std::move(config_service),
3681 std::move(factory), nullptr,
3682 /*quick_check_enabled=*/true);
3683
3684 auto fetcher = std::make_unique<MockPacFileFetcher>();
3685 auto* fetcher_ptr = fetcher.get();
3686 service.SetPacFileFetchers(std::move(fetcher),
3687 std::make_unique<DoNothingDhcpPacFileFetcher>());
3688
3689 // Start 1 request.
3690
3691 ProxyInfo info1;
3692 TestCompletionCallback callback1;
3693 std::unique_ptr<ProxyResolutionRequest> request1;
3694 int rv = service.ResolveProxy(
3695 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3696 callback1.callback(), &request1, NetLogWithSource());
3697 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3698
3699 // The first request should have triggered initial download of PAC script.
3700 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3701 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3702
3703 // Nothing has been sent to the factory yet.
3704 EXPECT_TRUE(factory_ptr->pending_requests().empty());
3705
3706 // At this point the ConfiguredProxyResolutionService should be waiting for
3707 // the PacFileFetcher to invoke its completion callback, notifying it of PAC
3708 // script download completion.
3709 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3710
3711 // Now that the PAC script is downloaded, the request will have been sent to
3712 // the proxy resolver.
3713 EXPECT_EQ(kValidPacScript116,
3714 factory_ptr->pending_requests()[0]->script_data()->utf16());
3715 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3716
3717 ASSERT_EQ(1u, resolver.pending_jobs().size());
3718 EXPECT_EQ(GURL("http://request1"), resolver.pending_jobs()[0]->url());
3719
3720 // Complete the pending request.
3721 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
3722 resolver.pending_jobs()[0]->CompleteNow(OK);
3723
3724 // Wait for completion callback, and verify that the request ran as expected.
3725 EXPECT_THAT(callback1.WaitForResult(), IsOk());
3726 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
3727
3728 // At this point we have initialized the proxy service using a PAC script.
3729 // Our PAC poller is set to update ONLY in response to network activity,
3730 // (i.e. another call to ResolveProxy()).
3731
3732 ASSERT_FALSE(fetcher_ptr->has_pending_request());
3733 ASSERT_TRUE(factory_ptr->pending_requests().empty());
3734 ASSERT_TRUE(resolver.pending_jobs().empty());
3735
3736 // Start a second request.
3737 ProxyInfo info2;
3738 TestCompletionCallback callback2;
3739 std::unique_ptr<ProxyResolutionRequest> request2;
3740 rv = service.ResolveProxy(
3741 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3742 callback2.callback(), &request2, NetLogWithSource());
3743 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3744
3745 // This request should have sent work to the resolver; complete it.
3746 ASSERT_EQ(1u, resolver.pending_jobs().size());
3747 EXPECT_EQ(GURL("http://request2"), resolver.pending_jobs()[0]->url());
3748 resolver.pending_jobs()[0]->results()->UseNamedProxy("request2:80");
3749 resolver.pending_jobs()[0]->CompleteNow(OK);
3750
3751 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3752 EXPECT_EQ("request2:80", ProxyServerToProxyUri(info2.proxy_server()));
3753
3754 // In response to getting that resolve request, the poller should have
3755 // started the next poll, and made it as far as to request the download.
3756
3757 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3758 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
3759
3760 // This time we will fail the download, to simulate a PAC script change.
3761 fetcher_ptr->NotifyFetchCompletion(ERR_FAILED, std::string());
3762
3763 // Drain the message loop, so ConfiguredProxyResolutionService is notified of
3764 // the change and has a chance to re-configure itself.
3765 base::RunLoop().RunUntilIdle();
3766
3767 // Start a third request -- this time we expect to get a direct connection
3768 // since the PAC script poller experienced a failure.
3769 ProxyInfo info3;
3770 TestCompletionCallback callback3;
3771 std::unique_ptr<ProxyResolutionRequest> request3;
3772 rv = service.ResolveProxy(
3773 GURL("http://request3"), std::string(), NetworkAnonymizationKey(), &info3,
3774 callback3.callback(), &request3, NetLogWithSource());
3775 EXPECT_THAT(rv, IsOk());
3776 EXPECT_TRUE(info3.is_direct());
3777 }
3778
TEST_F(ConfiguredProxyResolutionServiceTest,IpAddressChangeResetsProxy)3779 TEST_F(ConfiguredProxyResolutionServiceTest, IpAddressChangeResetsProxy) {
3780 NeverPollPolicy poll_policy;
3781 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3782
3783 MockAsyncProxyResolver resolver;
3784 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(
3785 /*resolvers_expect_pac_bytes=*/true);
3786 MockAsyncProxyResolverFactory* factory_ptr = factory.get();
3787 ConfiguredProxyResolutionService service(
3788 std::make_unique<MockProxyConfigService>(ProxyConfig::CreateAutoDetect()),
3789 std::move(factory),
3790 /*net_log=*/nullptr, /*quick_check_enabled=*/true);
3791 auto fetcher = std::make_unique<MockPacFileFetcher>();
3792 MockPacFileFetcher* fetcher_ptr = fetcher.get();
3793 service.SetPacFileFetchers(std::move(fetcher),
3794 std::make_unique<DoNothingDhcpPacFileFetcher>());
3795
3796 const base::TimeDelta kConfigDelay = base::Seconds(5);
3797 service.set_stall_proxy_auto_config_delay(kConfigDelay);
3798
3799 // Initialize by making and completing a proxy request.
3800 ProxyInfo info1;
3801 TestCompletionCallback callback1;
3802 std::unique_ptr<ProxyResolutionRequest> request1;
3803 int rv = service.ResolveProxy(
3804 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3805 callback1.callback(), &request1, NetLogWithSource());
3806 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
3807 ASSERT_TRUE(fetcher_ptr->has_pending_request());
3808 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3809 ASSERT_THAT(factory_ptr->pending_requests(), testing::SizeIs(1));
3810 EXPECT_EQ(kValidPacScript116,
3811 factory_ptr->pending_requests()[0]->script_data()->utf16());
3812 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3813 ASSERT_THAT(resolver.pending_jobs(), testing::SizeIs(1));
3814 resolver.pending_jobs()[0]->CompleteNow(OK);
3815 ASSERT_THAT(callback1.WaitForResult(), IsOk());
3816 EXPECT_FALSE(fetcher_ptr->has_pending_request());
3817
3818 // Expect IP address notification to trigger a fetch after wait period.
3819 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
3820 FastForwardBy(kConfigDelay - base::Milliseconds(2));
3821 EXPECT_FALSE(fetcher_ptr->has_pending_request());
3822 FastForwardBy(base::Milliseconds(2));
3823 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3824
3825 // Leave pending fetch hanging.
3826
3827 // Expect proxy requests are blocked on completion of change-triggered fetch.
3828 ProxyInfo info2;
3829 TestCompletionCallback callback2;
3830 std::unique_ptr<ProxyResolutionRequest> request2;
3831 rv = service.ResolveProxy(
3832 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info2,
3833 callback2.callback(), &request2, NetLogWithSource());
3834 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3835 EXPECT_THAT(resolver.pending_jobs(), testing::IsEmpty());
3836
3837 // Finish pending fetch and expect proxy request to be able to complete.
3838 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript2);
3839 ASSERT_THAT(factory_ptr->pending_requests(), testing::SizeIs(1));
3840 EXPECT_EQ(kValidPacScript216,
3841 factory_ptr->pending_requests()[0]->script_data()->utf16());
3842 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3843 ASSERT_THAT(resolver.pending_jobs(), testing::SizeIs(1));
3844 resolver.pending_jobs()[0]->CompleteNow(OK);
3845 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3846 EXPECT_FALSE(fetcher_ptr->has_pending_request());
3847 }
3848
TEST_F(ConfiguredProxyResolutionServiceTest,DnsChangeTriggersPoll)3849 TEST_F(ConfiguredProxyResolutionServiceTest, DnsChangeTriggersPoll) {
3850 ImmediateAfterActivityPollPolicy poll_policy;
3851 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3852
3853 MockAsyncProxyResolver resolver;
3854 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(
3855 /*resolvers_expect_pac_bytes=*/true);
3856 MockAsyncProxyResolverFactory* factory_ptr = factory.get();
3857 ConfiguredProxyResolutionService service(
3858 std::make_unique<MockProxyConfigService>(ProxyConfig::CreateAutoDetect()),
3859 std::move(factory),
3860 /*net_log=*/nullptr, /*quick_check_enabled=*/true);
3861 auto fetcher = std::make_unique<MockPacFileFetcher>();
3862 MockPacFileFetcher* fetcher_ptr = fetcher.get();
3863 service.SetPacFileFetchers(std::move(fetcher),
3864 std::make_unique<DoNothingDhcpPacFileFetcher>());
3865
3866 // Initialize config and poller by making and completing a proxy request.
3867 ProxyInfo info1;
3868 TestCompletionCallback callback1;
3869 std::unique_ptr<ProxyResolutionRequest> request1;
3870 int rv = service.ResolveProxy(
3871 GURL("http://request1"), std::string(), NetworkAnonymizationKey(), &info1,
3872 callback1.callback(), &request1, NetLogWithSource());
3873 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
3874 ASSERT_TRUE(fetcher_ptr->has_pending_request());
3875 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
3876 ASSERT_THAT(factory_ptr->pending_requests(), testing::SizeIs(1));
3877 EXPECT_EQ(kValidPacScript116,
3878 factory_ptr->pending_requests()[0]->script_data()->utf16());
3879 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3880 ASSERT_THAT(resolver.pending_jobs(), testing::SizeIs(1));
3881 resolver.pending_jobs()[0]->CompleteNow(OK);
3882 ASSERT_THAT(callback1.WaitForResult(), IsOk());
3883 EXPECT_FALSE(fetcher_ptr->has_pending_request());
3884
3885 // Expect DNS notification to trigger a fetch.
3886 NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests();
3887 fetcher_ptr->WaitUntilFetch();
3888 EXPECT_TRUE(fetcher_ptr->has_pending_request());
3889
3890 // Leave pending fetch hanging.
3891
3892 // Expect proxy requests are not blocked on completion of DNS-triggered fetch.
3893 ProxyInfo info2;
3894 TestCompletionCallback callback2;
3895 std::unique_ptr<ProxyResolutionRequest> request2;
3896 rv = service.ResolveProxy(
3897 GURL("http://request2"), std::string(), NetworkAnonymizationKey(), &info2,
3898 callback2.callback(), &request2, NetLogWithSource());
3899 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3900 ASSERT_THAT(resolver.pending_jobs(), testing::SizeIs(1));
3901 resolver.pending_jobs()[0]->CompleteNow(OK);
3902 EXPECT_THAT(callback2.WaitForResult(), IsOk());
3903
3904 // Complete DNS-triggered fetch.
3905 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript2);
3906 RunUntilIdle();
3907
3908 // Expect further proxy requests to use the new fetch result.
3909 ProxyInfo info3;
3910 TestCompletionCallback callback3;
3911 std::unique_ptr<ProxyResolutionRequest> request3;
3912 rv = service.ResolveProxy(
3913 GURL("http://request3"), std::string(), NetworkAnonymizationKey(), &info3,
3914 callback3.callback(), &request3, NetLogWithSource());
3915 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
3916 ASSERT_THAT(factory_ptr->pending_requests(), testing::SizeIs(1));
3917 EXPECT_EQ(kValidPacScript216,
3918 factory_ptr->pending_requests()[0]->script_data()->utf16());
3919 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3920 ASSERT_THAT(resolver.pending_jobs(), testing::SizeIs(1));
3921 resolver.pending_jobs()[0]->CompleteNow(OK);
3922 ASSERT_THAT(callback3.WaitForResult(), IsOk());
3923 EXPECT_FALSE(fetcher_ptr->has_pending_request());
3924 }
3925
TEST_F(ConfiguredProxyResolutionServiceTest,DnsChangeNoopWithoutResolver)3926 TEST_F(ConfiguredProxyResolutionServiceTest, DnsChangeNoopWithoutResolver) {
3927 ImmediateAfterActivityPollPolicy poll_policy;
3928 ConfiguredProxyResolutionService::set_pac_script_poll_policy(&poll_policy);
3929
3930 MockAsyncProxyResolver resolver;
3931 ConfiguredProxyResolutionService service(
3932 std::make_unique<MockProxyConfigService>(ProxyConfig::CreateAutoDetect()),
3933 std::make_unique<MockAsyncProxyResolverFactory>(
3934 /*resolvers_expect_pac_bytes=*/true),
3935 /*net_log=*/nullptr, /*quick_check_enabled=*/true);
3936 auto fetcher = std::make_unique<MockPacFileFetcher>();
3937 MockPacFileFetcher* fetcher_ptr = fetcher.get();
3938 service.SetPacFileFetchers(std::move(fetcher),
3939 std::make_unique<DoNothingDhcpPacFileFetcher>());
3940
3941 // Expect DNS notification to do nothing because no proxy requests have yet
3942 // been made.
3943 NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests();
3944 RunUntilIdle();
3945 EXPECT_FALSE(fetcher_ptr->has_pending_request());
3946 }
3947
3948 // Helper class to exercise URL sanitization by submitting URLs to the
3949 // ConfiguredProxyResolutionService and returning the URL passed to the
3950 // ProxyResolver.
3951 class SanitizeUrlHelper {
3952 public:
SanitizeUrlHelper()3953 SanitizeUrlHelper() {
3954 auto config_service =
3955 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
3956 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(false);
3957 auto* factory_ptr = factory.get();
3958 service_ = std::make_unique<ConfiguredProxyResolutionService>(
3959 std::move(config_service), std::move(factory), nullptr,
3960 /*quick_check_enabled=*/true);
3961
3962 // Do an initial request to initialize the service (configure the PAC
3963 // script).
3964 GURL url("http://example.com");
3965
3966 ProxyInfo info;
3967 TestCompletionCallback callback;
3968 std::unique_ptr<ProxyResolutionRequest> request;
3969 int rv = service_->ResolveProxy(
3970 url, std::string(), NetworkAnonymizationKey(), &info,
3971 callback.callback(), &request, NetLogWithSource());
3972 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3973
3974 // First step is to download the PAC script.
3975 EXPECT_EQ(GURL("http://foopy/proxy.pac"),
3976 factory_ptr->pending_requests()[0]->script_data()->url());
3977 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
3978
3979 EXPECT_EQ(1u, resolver.pending_jobs().size());
3980 EXPECT_EQ(url, resolver.pending_jobs()[0]->url());
3981
3982 // Complete the request.
3983 resolver.pending_jobs()[0]->results()->UsePacString("DIRECT");
3984 resolver.pending_jobs()[0]->CompleteNow(OK);
3985 EXPECT_THAT(callback.WaitForResult(), IsOk());
3986 EXPECT_TRUE(info.is_direct());
3987 }
3988
3989 // Makes a proxy resolution request through the
3990 // ConfiguredProxyResolutionService, and returns the URL that was submitted to
3991 // the Proxy Resolver.
SanitizeUrl(const GURL & raw_url)3992 GURL SanitizeUrl(const GURL& raw_url) {
3993 // Issue a request and see what URL is sent to the proxy resolver.
3994 ProxyInfo info;
3995 TestCompletionCallback callback;
3996 std::unique_ptr<ProxyResolutionRequest> request1;
3997 int rv = service_->ResolveProxy(
3998 raw_url, std::string(), NetworkAnonymizationKey(), &info,
3999 callback.callback(), &request1, NetLogWithSource());
4000 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
4001
4002 EXPECT_EQ(1u, resolver.pending_jobs().size());
4003
4004 GURL sanitized_url = resolver.pending_jobs()[0]->url();
4005
4006 // Complete the request.
4007 resolver.pending_jobs()[0]->results()->UsePacString("DIRECT");
4008 resolver.pending_jobs()[0]->CompleteNow(OK);
4009 EXPECT_THAT(callback.WaitForResult(), IsOk());
4010 EXPECT_TRUE(info.is_direct());
4011
4012 return sanitized_url;
4013 }
4014
4015 private:
4016 MockAsyncProxyResolver resolver;
4017 std::unique_ptr<ConfiguredProxyResolutionService> service_;
4018 };
4019
4020 // Tests that input URLs to proxy resolution are sanitized before being passed
4021 // on to the ProxyResolver (i.e. PAC script evaluator). For instance PAC
4022 // scripts should not be able to see the path for https:// URLs.
TEST_F(ConfiguredProxyResolutionServiceTest,SanitizeUrlForPacScript)4023 TEST_F(ConfiguredProxyResolutionServiceTest, SanitizeUrlForPacScript) {
4024 const struct {
4025 const char* raw_url;
4026 const char* sanitized_url;
4027 } kTests[] = {
4028 // ---------------------------------
4029 // Sanitize cryptographic URLs.
4030 // ---------------------------------
4031
4032 // Embedded identity is stripped.
4033 {
4034 "https://foo:bar@example.com/",
4035 "https://example.com/",
4036 },
4037 // Fragments and path are stripped.
4038 {
4039 "https://example.com/blah#hello",
4040 "https://example.com/",
4041 },
4042 // Query is stripped.
4043 {
4044 "https://example.com/?hello",
4045 "https://example.com/",
4046 },
4047 // The embedded identity and fragment are stripped.
4048 {
4049 "https://foo:bar@example.com/foo/bar/baz?hello#sigh",
4050 "https://example.com/",
4051 },
4052 // The URL's port should not be stripped.
4053 {
4054 "https://example.com:88/hi",
4055 "https://example.com:88/",
4056 },
4057 // Try a wss:// URL, to make sure it is treated as a cryptographic schemed
4058 // URL.
4059 {
4060 "wss://example.com:88/hi",
4061 "wss://example.com:88/",
4062 },
4063
4064 // ---------------------------------
4065 // Sanitize non-cryptographic URLs.
4066 // ---------------------------------
4067
4068 // Embedded identity is stripped.
4069 {
4070 "http://foo:bar@example.com/",
4071 "http://example.com/",
4072 },
4073 {
4074 "ftp://foo:bar@example.com/",
4075 "ftp://example.com/",
4076 },
4077 {
4078 "ftp://example.com/some/path/here",
4079 "ftp://example.com/some/path/here",
4080 },
4081 // Reference fragment is stripped.
4082 {
4083 "http://example.com/blah#hello",
4084 "http://example.com/blah",
4085 },
4086 // Query parameters are NOT stripped.
4087 {
4088 "http://example.com/foo/bar/baz?hello",
4089 "http://example.com/foo/bar/baz?hello",
4090 },
4091 // Fragment is stripped, but path and query are left intact.
4092 {
4093 "http://foo:bar@example.com/foo/bar/baz?hello#sigh",
4094 "http://example.com/foo/bar/baz?hello",
4095 },
4096 // Port numbers are not affected.
4097 {
4098 "http://example.com:88/hi",
4099 "http://example.com:88/hi",
4100 },
4101 };
4102
4103 SanitizeUrlHelper helper;
4104
4105 for (const auto& test : kTests) {
4106 GURL raw_url(test.raw_url);
4107 ASSERT_TRUE(raw_url.is_valid());
4108
4109 EXPECT_EQ(GURL(test.sanitized_url), helper.SanitizeUrl(raw_url));
4110 }
4111 }
4112
TEST_F(ConfiguredProxyResolutionServiceTest,OnShutdownWithLiveRequest)4113 TEST_F(ConfiguredProxyResolutionServiceTest, OnShutdownWithLiveRequest) {
4114 auto config_service =
4115 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
4116
4117 MockAsyncProxyResolver resolver;
4118 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
4119
4120 ConfiguredProxyResolutionService service(std::move(config_service),
4121 std::move(factory), nullptr,
4122 /*quick_check_enabled=*/true);
4123
4124 auto fetcher = std::make_unique<MockPacFileFetcher>();
4125 auto* fetcher_ptr = fetcher.get();
4126 service.SetPacFileFetchers(std::move(fetcher),
4127 std::make_unique<DoNothingDhcpPacFileFetcher>());
4128
4129 ProxyInfo info;
4130 TestCompletionCallback callback;
4131 std::unique_ptr<ProxyResolutionRequest> request;
4132 int rv = service.ResolveProxy(
4133 GURL("http://request/"), std::string(), NetworkAnonymizationKey(), &info,
4134 callback.callback(), &request, NetLogWithSource());
4135 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
4136
4137 // The first request should have triggered download of PAC script.
4138 EXPECT_TRUE(fetcher_ptr->has_pending_request());
4139 EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher_ptr->pending_request_url());
4140
4141 service.OnShutdown();
4142 base::RunLoop().RunUntilIdle();
4143 EXPECT_FALSE(callback.have_result());
4144 EXPECT_FALSE(fetcher_ptr->has_pending_request());
4145 }
4146
TEST_F(ConfiguredProxyResolutionServiceTest,OnShutdownFollowedByRequest)4147 TEST_F(ConfiguredProxyResolutionServiceTest, OnShutdownFollowedByRequest) {
4148 auto config_service =
4149 std::make_unique<MockProxyConfigService>("http://foopy/proxy.pac");
4150
4151 MockAsyncProxyResolver resolver;
4152 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
4153
4154 ConfiguredProxyResolutionService service(std::move(config_service),
4155 std::move(factory), nullptr,
4156 /*quick_check_enabled=*/true);
4157
4158 auto fetcher = std::make_unique<MockPacFileFetcher>();
4159 auto* fetcher_ptr = fetcher.get();
4160 service.SetPacFileFetchers(std::move(fetcher),
4161 std::make_unique<DoNothingDhcpPacFileFetcher>());
4162
4163 service.OnShutdown();
4164
4165 ProxyInfo info;
4166 TestCompletionCallback callback;
4167 std::unique_ptr<ProxyResolutionRequest> request;
4168 int rv = service.ResolveProxy(
4169 GURL("http://request/"), std::string(), NetworkAnonymizationKey(), &info,
4170 callback.callback(), &request, NetLogWithSource());
4171 EXPECT_THAT(rv, IsOk());
4172 EXPECT_FALSE(fetcher_ptr->has_pending_request());
4173 EXPECT_TRUE(info.is_direct());
4174 }
4175
4176 const char* kImplicityBypassedHosts[] = {
4177 "localhost",
4178 "localhost.",
4179 "foo.localhost",
4180 "127.0.0.1",
4181 "127.100.0.2",
4182 "[::1]",
4183 "169.254.3.2",
4184 "169.254.100.1",
4185 "[FE80::8]",
4186 "[feb8::1]",
4187 };
4188
4189 const char* kUrlSchemes[] = {"http://", "https://", "ftp://"};
4190
TEST_F(ConfiguredProxyResolutionServiceTest,ImplicitlyBypassWithManualSettings)4191 TEST_F(ConfiguredProxyResolutionServiceTest,
4192 ImplicitlyBypassWithManualSettings) {
4193 // Use manual proxy settings that specify a single proxy for all traffic.
4194 ProxyConfig config;
4195 config.proxy_rules().ParseFromString("foopy1:8080");
4196 config.set_auto_detect(false);
4197
4198 auto service = ConfiguredProxyResolutionService::CreateFixedForTest(
4199 ProxyConfigWithAnnotation(config, TRAFFIC_ANNOTATION_FOR_TESTS));
4200
4201 // A normal request should use the proxy.
4202 std::unique_ptr<ProxyResolutionRequest> request1;
4203 ProxyInfo info1;
4204 TestCompletionCallback callback1;
4205 int rv = service->ResolveProxy(
4206 GURL("http://www.example.com"), std::string(), NetworkAnonymizationKey(),
4207 &info1, callback1.callback(), &request1, NetLogWithSource());
4208 EXPECT_THAT(rv, IsOk());
4209 EXPECT_EQ("foopy1:8080", ProxyServerToProxyUri(info1.proxy_server()));
4210
4211 // Test that localhost and link-local URLs bypass the proxy (independent of
4212 // the URL scheme).
4213 for (auto* host : kImplicityBypassedHosts) {
4214 for (auto* scheme : kUrlSchemes) {
4215 auto url = GURL(std::string(scheme) + std::string(host));
4216
4217 std::unique_ptr<ProxyResolutionRequest> request;
4218 ProxyInfo info;
4219 TestCompletionCallback callback;
4220 rv = service->ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
4221 &info, callback.callback(), &request,
4222 NetLogWithSource());
4223 EXPECT_THAT(rv, IsOk());
4224 EXPECT_TRUE(info.is_direct());
4225 }
4226 }
4227 }
4228
4229 // Test that the when using a PAC script (sourced via auto-detect) certain
4230 // localhost names are implicitly bypassed.
TEST_F(ConfiguredProxyResolutionServiceTest,ImplicitlyBypassWithPac)4231 TEST_F(ConfiguredProxyResolutionServiceTest, ImplicitlyBypassWithPac) {
4232 ProxyConfig config;
4233 config.set_auto_detect(true);
4234
4235 auto config_service = std::make_unique<MockProxyConfigService>(config);
4236 MockAsyncProxyResolver resolver;
4237 auto factory = std::make_unique<MockAsyncProxyResolverFactory>(true);
4238 auto* factory_ptr = factory.get();
4239 ConfiguredProxyResolutionService service(std::move(config_service),
4240 std::move(factory), nullptr,
4241 /*quick_check_enabled=*/true);
4242
4243 auto fetcher = std::make_unique<MockPacFileFetcher>();
4244 auto* fetcher_ptr = fetcher.get();
4245 service.SetPacFileFetchers(std::move(fetcher),
4246 std::make_unique<DoNothingDhcpPacFileFetcher>());
4247
4248 // Start 1 requests.
4249
4250 ProxyInfo info1;
4251 TestCompletionCallback callback1;
4252 std::unique_ptr<ProxyResolutionRequest> request1;
4253 int rv = service.ResolveProxy(
4254 GURL("http://www.google.com"), std::string(), NetworkAnonymizationKey(),
4255 &info1, callback1.callback(), &request1, NetLogWithSource());
4256 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
4257
4258 // This started auto-detect; complete it.
4259 ASSERT_EQ(0u, factory_ptr->pending_requests().size());
4260 EXPECT_TRUE(fetcher_ptr->has_pending_request());
4261 EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher_ptr->pending_request_url());
4262 fetcher_ptr->NotifyFetchCompletion(OK, kValidPacScript1);
4263
4264 EXPECT_EQ(kValidPacScript116,
4265 factory_ptr->pending_requests()[0]->script_data()->utf16());
4266 factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
4267
4268 ASSERT_EQ(1u, resolver.pending_jobs().size());
4269 EXPECT_EQ(GURL("http://www.google.com"), resolver.pending_jobs()[0]->url());
4270
4271 // Complete the pending request.
4272 resolver.pending_jobs()[0]->results()->UseNamedProxy("request1:80");
4273 resolver.pending_jobs()[0]->CompleteNow(OK);
4274
4275 // Verify that request ran as expected.
4276 EXPECT_THAT(callback1.WaitForResult(), IsOk());
4277 EXPECT_EQ("request1:80", ProxyServerToProxyUri(info1.proxy_server()));
4278
4279 // Test that localhost and link-local URLs bypass the use of PAC script
4280 // (independent of the URL scheme).
4281 for (auto* host : kImplicityBypassedHosts) {
4282 for (auto* scheme : kUrlSchemes) {
4283 auto url = GURL(std::string(scheme) + std::string(host));
4284
4285 std::unique_ptr<ProxyResolutionRequest> request;
4286 ProxyInfo info;
4287 TestCompletionCallback callback;
4288 rv = service.ResolveProxy(url, std::string(), NetworkAnonymizationKey(),
4289 &info, callback.callback(), &request,
4290 NetLogWithSource());
4291 EXPECT_THAT(rv, IsOk());
4292 EXPECT_TRUE(info.is_direct());
4293 }
4294 }
4295 }
4296
TEST_F(ConfiguredProxyResolutionServiceTest,CastToConfiguredProxyResolutionService)4297 TEST_F(ConfiguredProxyResolutionServiceTest,
4298 CastToConfiguredProxyResolutionService) {
4299 auto config_service =
4300 std::make_unique<MockProxyConfigService>(ProxyConfig::CreateDirect());
4301
4302 ConfiguredProxyResolutionService service(
4303 std::move(config_service),
4304 std::make_unique<MockAsyncProxyResolverFactory>(false), nullptr,
4305 /*quick_check_enabled=*/true);
4306
4307 ConfiguredProxyResolutionService* casted_service = nullptr;
4308 EXPECT_TRUE(service.CastToConfiguredProxyResolutionService(&casted_service));
4309 EXPECT_EQ(&service, casted_service);
4310 }
4311
4312 } // namespace net
4313