1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/proxy/proxy_service.h"
6
7#include <vector>
8
9#include "base/format_macros.h"
10#include "base/logging.h"
11#include "base/strings/string_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "net/base/net_errors.h"
14#include "net/base/net_log.h"
15#include "net/base/net_log_unittest.h"
16#include "net/base/test_completion_callback.h"
17#include "net/proxy/dhcp_proxy_script_fetcher.h"
18#include "net/proxy/mock_proxy_resolver.h"
19#include "net/proxy/mock_proxy_script_fetcher.h"
20#include "net/proxy/proxy_config_service.h"
21#include "net/proxy/proxy_resolver.h"
22#include "net/proxy/proxy_script_fetcher.h"
23#include "testing/gtest/include/gtest/gtest.h"
24#include "url/gurl.h"
25
26// TODO(eroman): Write a test which exercises
27//              ProxyService::SuspendAllPendingRequests().
28namespace net {
29namespace {
30
31// This polling policy will decide to poll every 1 ms.
32class ImmediatePollPolicy : public ProxyService::PacPollPolicy {
33 public:
34  ImmediatePollPolicy() {}
35
36  virtual Mode GetNextDelay(int error, base::TimeDelta current_delay,
37                            base::TimeDelta* next_delay) const OVERRIDE {
38    *next_delay = base::TimeDelta::FromMilliseconds(1);
39    return MODE_USE_TIMER;
40  }
41
42 private:
43  DISALLOW_COPY_AND_ASSIGN(ImmediatePollPolicy);
44};
45
46// This polling policy chooses a fantastically large delay. In other words, it
47// will never trigger a poll
48class NeverPollPolicy : public ProxyService::PacPollPolicy {
49 public:
50  NeverPollPolicy() {}
51
52  virtual Mode GetNextDelay(int error, base::TimeDelta current_delay,
53                            base::TimeDelta* next_delay) const OVERRIDE {
54    *next_delay = base::TimeDelta::FromDays(60);
55    return MODE_USE_TIMER;
56  }
57
58 private:
59  DISALLOW_COPY_AND_ASSIGN(NeverPollPolicy);
60};
61
62// This polling policy starts a poll immediately after network activity.
63class ImmediateAfterActivityPollPolicy : public ProxyService::PacPollPolicy {
64 public:
65  ImmediateAfterActivityPollPolicy() {}
66
67  virtual Mode GetNextDelay(int error, base::TimeDelta current_delay,
68                            base::TimeDelta* next_delay) const OVERRIDE {
69    *next_delay = base::TimeDelta();
70    return MODE_START_AFTER_ACTIVITY;
71  }
72
73 private:
74  DISALLOW_COPY_AND_ASSIGN(ImmediateAfterActivityPollPolicy);
75};
76
77// This test fixture is used to partially disable the background polling done by
78// the ProxyService (which it uses to detect whenever its PAC script contents or
79// WPAD results have changed).
80//
81// We disable the feature by setting the poll interval to something really
82// large, so it will never actually be reached even on the slowest bots that run
83// these tests.
84//
85// We disable the polling in order to avoid any timing dependencies in the
86// tests. If the bot were to run the tests very slowly and we hadn't disabled
87// polling, then it might start a background re-try in the middle of our test
88// and confuse our expectations leading to flaky failures.
89//
90// The tests which verify the polling code re-enable the polling behavior but
91// are careful to avoid timing problems.
92class ProxyServiceTest : public testing::Test {
93 protected:
94  virtual void SetUp() OVERRIDE {
95    testing::Test::SetUp();
96    previous_policy_ =
97        ProxyService::set_pac_script_poll_policy(&never_poll_policy_);
98  }
99
100  virtual void TearDown() OVERRIDE {
101    // Restore the original policy.
102    ProxyService::set_pac_script_poll_policy(previous_policy_);
103    testing::Test::TearDown();
104  }
105
106 private:
107  NeverPollPolicy never_poll_policy_;
108  const ProxyService::PacPollPolicy* previous_policy_;
109};
110
111const char kValidPacScript1[] = "pac-script-v1-FindProxyForURL";
112const char kValidPacScript2[] = "pac-script-v2-FindProxyForURL";
113
114class MockProxyConfigService: public ProxyConfigService {
115 public:
116  explicit MockProxyConfigService(const ProxyConfig& config)
117      : availability_(CONFIG_VALID),
118        config_(config) {
119  }
120
121  explicit MockProxyConfigService(const std::string& pac_url)
122      : availability_(CONFIG_VALID),
123        config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url))) {
124  }
125
126  virtual void AddObserver(Observer* observer) OVERRIDE {
127    observers_.AddObserver(observer);
128  }
129
130  virtual void RemoveObserver(Observer* observer) OVERRIDE {
131    observers_.RemoveObserver(observer);
132  }
133
134  virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* results)
135      OVERRIDE {
136    if (availability_ == CONFIG_VALID)
137      *results = config_;
138    return availability_;
139  }
140
141  void SetConfig(const ProxyConfig& config) {
142    availability_ = CONFIG_VALID;
143    config_ = config;
144    FOR_EACH_OBSERVER(Observer, observers_,
145                      OnProxyConfigChanged(config_, availability_));
146  }
147
148 private:
149  ConfigAvailability availability_;
150  ProxyConfig config_;
151  ObserverList<Observer, true> observers_;
152};
153
154}  // namespace
155
156TEST_F(ProxyServiceTest, Direct) {
157  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
158  ProxyService service(new MockProxyConfigService(
159          ProxyConfig::CreateDirect()), resolver, NULL);
160
161  GURL url("http://www.google.com/");
162
163  ProxyInfo info;
164  TestCompletionCallback callback;
165  CapturingBoundNetLog log;
166  int rv = service.ResolveProxy(
167      url, &info, callback.callback(), NULL, log.bound());
168  EXPECT_EQ(OK, rv);
169  EXPECT_TRUE(resolver->pending_requests().empty());
170
171  EXPECT_TRUE(info.is_direct());
172  EXPECT_TRUE(info.proxy_resolve_start_time().is_null());
173  EXPECT_TRUE(info.proxy_resolve_end_time().is_null());
174
175  // Check the NetLog was filled correctly.
176  CapturingNetLog::CapturedEntryList entries;
177  log.GetEntries(&entries);
178
179  EXPECT_EQ(3u, entries.size());
180  EXPECT_TRUE(LogContainsBeginEvent(
181      entries, 0, NetLog::TYPE_PROXY_SERVICE));
182  EXPECT_TRUE(LogContainsEvent(
183      entries, 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
184      NetLog::PHASE_NONE));
185  EXPECT_TRUE(LogContainsEndEvent(
186      entries, 2, NetLog::TYPE_PROXY_SERVICE));
187}
188
189TEST_F(ProxyServiceTest, PAC) {
190  MockProxyConfigService* config_service =
191      new MockProxyConfigService("http://foopy/proxy.pac");
192
193  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
194
195  ProxyService service(config_service, resolver, NULL);
196
197  GURL url("http://www.google.com/");
198
199  ProxyInfo info;
200  TestCompletionCallback callback;
201  ProxyService::PacRequest* request;
202  CapturingBoundNetLog log;
203
204  int rv = service.ResolveProxy(
205      url, &info, callback.callback(), &request, log.bound());
206  EXPECT_EQ(ERR_IO_PENDING, rv);
207
208  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request));
209
210  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
211            resolver->pending_set_pac_script_request()->script_data()->url());
212  resolver->pending_set_pac_script_request()->CompleteNow(OK);
213
214  ASSERT_EQ(1u, resolver->pending_requests().size());
215  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
216
217  // Set the result in proxy resolver.
218  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy");
219  resolver->pending_requests()[0]->CompleteNow(OK);
220
221  EXPECT_EQ(OK, callback.WaitForResult());
222  EXPECT_FALSE(info.is_direct());
223  EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
224  EXPECT_TRUE(info.did_use_pac_script());
225
226  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
227  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
228  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
229
230  // Check the NetLog was filled correctly.
231  CapturingNetLog::CapturedEntryList entries;
232  log.GetEntries(&entries);
233
234  EXPECT_EQ(5u, entries.size());
235  EXPECT_TRUE(LogContainsBeginEvent(
236      entries, 0, NetLog::TYPE_PROXY_SERVICE));
237  EXPECT_TRUE(LogContainsBeginEvent(
238      entries, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
239  EXPECT_TRUE(LogContainsEndEvent(
240      entries, 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
241  EXPECT_TRUE(LogContainsEndEvent(
242      entries, 4, NetLog::TYPE_PROXY_SERVICE));
243}
244
245// Test that the proxy resolver does not see the URL's username/password
246// or its reference section.
247TEST_F(ProxyServiceTest, PAC_NoIdentityOrHash) {
248  MockProxyConfigService* config_service =
249      new MockProxyConfigService("http://foopy/proxy.pac");
250
251  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
252
253  ProxyService service(config_service, resolver, NULL);
254
255  GURL url("http://username:password@www.google.com/?ref#hash#hash");
256
257  ProxyInfo info;
258  TestCompletionCallback callback;
259  int rv = service.ResolveProxy(
260      url, &info, callback.callback(), NULL, BoundNetLog());
261  EXPECT_EQ(ERR_IO_PENDING, rv);
262
263  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
264            resolver->pending_set_pac_script_request()->script_data()->url());
265  resolver->pending_set_pac_script_request()->CompleteNow(OK);
266
267  ASSERT_EQ(1u, resolver->pending_requests().size());
268  // The URL should have been simplified, stripping the username/password/hash.
269  EXPECT_EQ(GURL("http://www.google.com/?ref"),
270                 resolver->pending_requests()[0]->url());
271
272  // We end here without ever completing the request -- destruction of
273  // ProxyService will cancel the outstanding request.
274}
275
276TEST_F(ProxyServiceTest, PAC_FailoverWithoutDirect) {
277  MockProxyConfigService* config_service =
278      new MockProxyConfigService("http://foopy/proxy.pac");
279  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
280
281  ProxyService service(config_service, resolver, NULL);
282
283  GURL url("http://www.google.com/");
284
285  ProxyInfo info;
286  TestCompletionCallback callback1;
287  int rv = service.ResolveProxy(
288      url, &info, callback1.callback(), NULL, BoundNetLog());
289  EXPECT_EQ(ERR_IO_PENDING, rv);
290
291  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
292            resolver->pending_set_pac_script_request()->script_data()->url());
293  resolver->pending_set_pac_script_request()->CompleteNow(OK);
294
295  ASSERT_EQ(1u, resolver->pending_requests().size());
296  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
297
298  // Set the result in proxy resolver.
299  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy:8080");
300  resolver->pending_requests()[0]->CompleteNow(OK);
301
302  EXPECT_EQ(OK, callback1.WaitForResult());
303  EXPECT_FALSE(info.is_direct());
304  EXPECT_EQ("foopy:8080", info.proxy_server().ToURI());
305  EXPECT_TRUE(info.did_use_pac_script());
306
307  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
308  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
309  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
310
311  // Now, imagine that connecting to foopy:8080 fails: there is nothing
312  // left to fallback to, since our proxy list was NOT terminated by
313  // DIRECT.
314  TestCompletionCallback callback2;
315  rv = service.ReconsiderProxyAfterError(
316      url, &info, callback2.callback(), NULL, BoundNetLog());
317  // ReconsiderProxyAfterError returns error indicating nothing left.
318  EXPECT_EQ(ERR_FAILED, rv);
319  EXPECT_TRUE(info.is_empty());
320}
321
322// Test that if the execution of the PAC script fails (i.e. javascript runtime
323// error), and the PAC settings are non-mandatory, that we fall-back to direct.
324TEST_F(ProxyServiceTest, PAC_RuntimeError) {
325  MockProxyConfigService* config_service =
326      new MockProxyConfigService("http://foopy/proxy.pac");
327  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
328
329  ProxyService service(config_service, resolver, NULL);
330
331  GURL url("http://this-causes-js-error/");
332
333  ProxyInfo info;
334  TestCompletionCallback callback1;
335  int rv = service.ResolveProxy(
336      url, &info, callback1.callback(), NULL, BoundNetLog());
337  EXPECT_EQ(ERR_IO_PENDING, rv);
338
339  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
340            resolver->pending_set_pac_script_request()->script_data()->url());
341  resolver->pending_set_pac_script_request()->CompleteNow(OK);
342
343  ASSERT_EQ(1u, resolver->pending_requests().size());
344  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
345
346  // Simulate a failure in the PAC executor.
347  resolver->pending_requests()[0]->CompleteNow(ERR_PAC_SCRIPT_FAILED);
348
349  EXPECT_EQ(OK, callback1.WaitForResult());
350
351  // Since the PAC script was non-mandatory, we should have fallen-back to
352  // DIRECT.
353  EXPECT_TRUE(info.is_direct());
354  EXPECT_TRUE(info.did_use_pac_script());
355  EXPECT_EQ(1, info.config_id());
356
357  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
358  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
359  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
360}
361
362// The proxy list could potentially contain the DIRECT fallback choice
363// in a location other than the very end of the list, and could even
364// specify it multiple times.
365//
366// This is not a typical usage, but we will obey it.
367// (If we wanted to disallow this type of input, the right place to
368// enforce it would be in parsing the PAC result string).
369//
370// This test will use the PAC result string:
371//
372//   "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20"
373//
374// For which we expect it to try DIRECT, then foobar:10, then DIRECT again,
375// then foobar:20, and then give up and error.
376//
377// The important check of this test is to make sure that DIRECT is not somehow
378// cached as being a bad proxy.
379TEST_F(ProxyServiceTest, PAC_FailoverAfterDirect) {
380  MockProxyConfigService* config_service =
381      new MockProxyConfigService("http://foopy/proxy.pac");
382  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
383
384  ProxyService service(config_service, resolver, NULL);
385
386  GURL url("http://www.google.com/");
387
388  ProxyInfo info;
389  TestCompletionCallback callback1;
390  int rv = service.ResolveProxy(
391      url, &info, callback1.callback(), NULL, BoundNetLog());
392  EXPECT_EQ(ERR_IO_PENDING, rv);
393
394  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
395            resolver->pending_set_pac_script_request()->script_data()->url());
396  resolver->pending_set_pac_script_request()->CompleteNow(OK);
397
398  ASSERT_EQ(1u, resolver->pending_requests().size());
399  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
400
401  // Set the result in proxy resolver.
402  resolver->pending_requests()[0]->results()->UsePacString(
403      "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20");
404  resolver->pending_requests()[0]->CompleteNow(OK);
405
406  EXPECT_EQ(OK, callback1.WaitForResult());
407  EXPECT_TRUE(info.is_direct());
408
409  // Fallback 1.
410  TestCompletionCallback callback2;
411  rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL,
412                                         BoundNetLog());
413  EXPECT_EQ(OK, rv);
414  EXPECT_FALSE(info.is_direct());
415  EXPECT_EQ("foobar:10", info.proxy_server().ToURI());
416
417  // Fallback 2.
418  TestCompletionCallback callback3;
419  rv = service.ReconsiderProxyAfterError(url, &info, callback3.callback(), NULL,
420                                         BoundNetLog());
421  EXPECT_EQ(OK, rv);
422  EXPECT_TRUE(info.is_direct());
423
424  // Fallback 3.
425  TestCompletionCallback callback4;
426  rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL,
427                                         BoundNetLog());
428  EXPECT_EQ(OK, rv);
429  EXPECT_FALSE(info.is_direct());
430  EXPECT_EQ("foobar:20", info.proxy_server().ToURI());
431
432  // Fallback 4 -- Nothing to fall back to!
433  TestCompletionCallback callback5;
434  rv = service.ReconsiderProxyAfterError(url, &info, callback5.callback(), NULL,
435                                         BoundNetLog());
436  EXPECT_EQ(ERR_FAILED, rv);
437  EXPECT_TRUE(info.is_empty());
438}
439
440TEST_F(ProxyServiceTest, PAC_ConfigSourcePropagates) {
441  // Test whether the ProxyConfigSource set by the ProxyConfigService is applied
442  // to ProxyInfo after the proxy is resolved via a PAC script.
443  ProxyConfig config =
444      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
445  config.set_source(PROXY_CONFIG_SOURCE_TEST);
446
447  MockProxyConfigService* config_service = new MockProxyConfigService(config);
448  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
449  ProxyService service(config_service, resolver, NULL);
450
451  // Resolve something.
452  GURL url("http://www.google.com/");
453  ProxyInfo info;
454  TestCompletionCallback callback;
455  int rv = service.ResolveProxy(
456      url, &info, callback.callback(), NULL, BoundNetLog());
457  ASSERT_EQ(ERR_IO_PENDING, rv);
458  resolver->pending_set_pac_script_request()->CompleteNow(OK);
459  ASSERT_EQ(1u, resolver->pending_requests().size());
460
461  // Set the result in proxy resolver.
462  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy");
463  resolver->pending_requests()[0]->CompleteNow(OK);
464
465  EXPECT_EQ(OK, callback.WaitForResult());
466  EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
467  EXPECT_TRUE(info.did_use_pac_script());
468
469  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
470  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
471  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
472}
473
474TEST_F(ProxyServiceTest, ProxyResolverFails) {
475  // Test what happens when the ProxyResolver fails. The download and setting
476  // of the PAC script have already succeeded, so this corresponds with a
477  // javascript runtime error while calling FindProxyForURL().
478
479  MockProxyConfigService* config_service =
480      new MockProxyConfigService("http://foopy/proxy.pac");
481
482  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
483
484  ProxyService service(config_service, resolver, NULL);
485
486  // Start first resolve request.
487  GURL url("http://www.google.com/");
488  ProxyInfo info;
489  TestCompletionCallback callback1;
490  int rv = service.ResolveProxy(
491      url, &info, callback1.callback(), NULL, BoundNetLog());
492  EXPECT_EQ(ERR_IO_PENDING, rv);
493
494  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
495            resolver->pending_set_pac_script_request()->script_data()->url());
496  resolver->pending_set_pac_script_request()->CompleteNow(OK);
497
498  ASSERT_EQ(1u, resolver->pending_requests().size());
499  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
500
501  // Fail the first resolve request in MockAsyncProxyResolver.
502  resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
503
504  // Although the proxy resolver failed the request, ProxyService implicitly
505  // falls-back to DIRECT.
506  EXPECT_EQ(OK, callback1.WaitForResult());
507  EXPECT_TRUE(info.is_direct());
508
509  // Failed PAC executions still have proxy resolution times.
510  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
511  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
512  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
513
514  // The second resolve request will try to run through the proxy resolver,
515  // regardless of whether the first request failed in it.
516  TestCompletionCallback callback2;
517  rv = service.ResolveProxy(
518      url, &info, callback2.callback(), NULL, BoundNetLog());
519  EXPECT_EQ(ERR_IO_PENDING, rv);
520
521  ASSERT_EQ(1u, resolver->pending_requests().size());
522  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
523
524  // This time we will have the resolver succeed (perhaps the PAC script has
525  // a dependency on the current time).
526  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
527  resolver->pending_requests()[0]->CompleteNow(OK);
528
529  EXPECT_EQ(OK, callback2.WaitForResult());
530  EXPECT_FALSE(info.is_direct());
531  EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
532}
533
534TEST_F(ProxyServiceTest, ProxyScriptFetcherFailsDownloadingMandatoryPac) {
535  // Test what happens when the ProxyScriptResolver fails to download a
536  // mandatory PAC script.
537
538  ProxyConfig config(
539      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
540  config.set_pac_mandatory(true);
541
542  MockProxyConfigService* config_service = new MockProxyConfigService(config);
543
544  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
545
546  ProxyService service(config_service, resolver, NULL);
547
548  // Start first resolve request.
549  GURL url("http://www.google.com/");
550  ProxyInfo info;
551  TestCompletionCallback callback1;
552  int rv = service.ResolveProxy(
553      url, &info, callback1.callback(), NULL, BoundNetLog());
554  EXPECT_EQ(ERR_IO_PENDING, rv);
555
556  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
557            resolver->pending_set_pac_script_request()->script_data()->url());
558  resolver->pending_set_pac_script_request()->CompleteNow(ERR_FAILED);
559
560  ASSERT_EQ(0u, resolver->pending_requests().size());
561
562  // As the proxy resolver failed the request and is configured for a mandatory
563  // PAC script, ProxyService must not implicitly fall-back to DIRECT.
564  EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
565            callback1.WaitForResult());
566  EXPECT_FALSE(info.is_direct());
567
568  // As the proxy resolver failed the request and is configured for a mandatory
569  // PAC script, ProxyService must not implicitly fall-back to DIRECT.
570  TestCompletionCallback callback2;
571  rv = service.ResolveProxy(
572      url, &info, callback2.callback(), NULL, BoundNetLog());
573  EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED, rv);
574  EXPECT_FALSE(info.is_direct());
575}
576
577TEST_F(ProxyServiceTest, ProxyResolverFailsParsingJavaScriptMandatoryPac) {
578  // Test what happens when the ProxyResolver fails that is configured to use a
579  // mandatory PAC script. The download of the PAC script has already
580  // succeeded but the PAC script contains no valid javascript.
581
582  ProxyConfig config(
583      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
584  config.set_pac_mandatory(true);
585
586  MockProxyConfigService* config_service = new MockProxyConfigService(config);
587
588  MockAsyncProxyResolverExpectsBytes* resolver =
589      new MockAsyncProxyResolverExpectsBytes;
590
591  ProxyService service(config_service, resolver, NULL);
592
593  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
594  DhcpProxyScriptFetcher* dhcp_fetcher = new DoNothingDhcpProxyScriptFetcher();
595  service.SetProxyScriptFetchers(fetcher, dhcp_fetcher);
596
597  // Start resolve request.
598  GURL url("http://www.google.com/");
599  ProxyInfo info;
600  TestCompletionCallback callback;
601  int rv = service.ResolveProxy(
602      url, &info, callback.callback(), NULL, BoundNetLog());
603  EXPECT_EQ(ERR_IO_PENDING, rv);
604
605  // Check that nothing has been sent to the proxy resolver yet.
606  ASSERT_EQ(0u, resolver->pending_requests().size());
607
608  // Downloading the PAC script succeeds.
609  EXPECT_TRUE(fetcher->has_pending_request());
610  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
611  fetcher->NotifyFetchCompletion(OK, "invalid-script-contents");
612
613  EXPECT_FALSE(fetcher->has_pending_request());
614  ASSERT_EQ(0u, resolver->pending_requests().size());
615
616  // Since ProxyScriptDecider failed to identify a valid PAC and PAC was
617  // mandatory for this configuration, the ProxyService must not implicitly
618  // fall-back to DIRECT.
619  EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
620            callback.WaitForResult());
621  EXPECT_FALSE(info.is_direct());
622}
623
624TEST_F(ProxyServiceTest, ProxyResolverFailsInJavaScriptMandatoryPac) {
625  // Test what happens when the ProxyResolver fails that is configured to use a
626  // mandatory PAC script. The download and setting of the PAC script have
627  // already succeeded, so this corresponds with a javascript runtime error
628  // while calling FindProxyForURL().
629
630  ProxyConfig config(
631      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
632  config.set_pac_mandatory(true);
633
634  MockProxyConfigService* config_service = new MockProxyConfigService(config);
635
636  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
637
638  ProxyService service(config_service, resolver, NULL);
639
640  // Start first resolve request.
641  GURL url("http://www.google.com/");
642  ProxyInfo info;
643  TestCompletionCallback callback1;
644  int rv = service.ResolveProxy(
645      url, &info, callback1.callback(), NULL, BoundNetLog());
646  EXPECT_EQ(ERR_IO_PENDING, rv);
647
648  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
649            resolver->pending_set_pac_script_request()->script_data()->url());
650  resolver->pending_set_pac_script_request()->CompleteNow(OK);
651
652  ASSERT_EQ(1u, resolver->pending_requests().size());
653  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
654
655  // Fail the first resolve request in MockAsyncProxyResolver.
656  resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
657
658  // As the proxy resolver failed the request and is configured for a mandatory
659  // PAC script, ProxyService must not implicitly fall-back to DIRECT.
660  EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
661            callback1.WaitForResult());
662  EXPECT_FALSE(info.is_direct());
663
664  // The second resolve request will try to run through the proxy resolver,
665  // regardless of whether the first request failed in it.
666  TestCompletionCallback callback2;
667  rv = service.ResolveProxy(
668      url, &info, callback2.callback(), NULL, BoundNetLog());
669  EXPECT_EQ(ERR_IO_PENDING, rv);
670
671  ASSERT_EQ(1u, resolver->pending_requests().size());
672  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
673
674  // This time we will have the resolver succeed (perhaps the PAC script has
675  // a dependency on the current time).
676  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
677  resolver->pending_requests()[0]->CompleteNow(OK);
678
679  EXPECT_EQ(OK, callback2.WaitForResult());
680  EXPECT_FALSE(info.is_direct());
681  EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
682}
683
684TEST_F(ProxyServiceTest, ProxyFallback) {
685  // Test what happens when we specify multiple proxy servers and some of them
686  // are bad.
687
688  MockProxyConfigService* config_service =
689      new MockProxyConfigService("http://foopy/proxy.pac");
690
691  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
692
693  ProxyService service(config_service, resolver, NULL);
694
695  GURL url("http://www.google.com/");
696
697  // Get the proxy information.
698  ProxyInfo info;
699  TestCompletionCallback callback1;
700  int rv = service.ResolveProxy(
701      url, &info, callback1.callback(), NULL, BoundNetLog());
702  EXPECT_EQ(ERR_IO_PENDING, rv);
703
704  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
705            resolver->pending_set_pac_script_request()->script_data()->url());
706  resolver->pending_set_pac_script_request()->CompleteNow(OK);
707
708  ASSERT_EQ(1u, resolver->pending_requests().size());
709  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
710
711  // Set the result in proxy resolver.
712  resolver->pending_requests()[0]->results()->UseNamedProxy(
713      "foopy1:8080;foopy2:9090");
714  resolver->pending_requests()[0]->CompleteNow(OK);
715
716  // The first item is valid.
717  EXPECT_EQ(OK, callback1.WaitForResult());
718  EXPECT_FALSE(info.is_direct());
719  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
720
721  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
722  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
723  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
724  base::TimeTicks proxy_resolve_start_time = info.proxy_resolve_start_time();
725  base::TimeTicks proxy_resolve_end_time = info.proxy_resolve_end_time();
726
727  // Fake an error on the proxy.
728  TestCompletionCallback callback2;
729  rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL,
730                                         BoundNetLog());
731  EXPECT_EQ(OK, rv);
732
733  // Proxy times should not have been modified by fallback.
734  EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time());
735  EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time());
736
737  // The second proxy should be specified.
738  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
739  // Report back that the second proxy worked.  This will globally mark the
740  // first proxy as bad.
741  service.ReportSuccess(info);
742
743  TestCompletionCallback callback3;
744  rv = service.ResolveProxy(
745      url, &info, callback3.callback(), NULL, BoundNetLog());
746  EXPECT_EQ(ERR_IO_PENDING, rv);
747
748  ASSERT_EQ(1u, resolver->pending_requests().size());
749  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
750
751  // Set the result in proxy resolver -- the second result is already known
752  // to be bad, so we will not try to use it initially.
753  resolver->pending_requests()[0]->results()->UseNamedProxy(
754      "foopy3:7070;foopy1:8080;foopy2:9090");
755  resolver->pending_requests()[0]->CompleteNow(OK);
756
757  EXPECT_EQ(OK, callback3.WaitForResult());
758  EXPECT_FALSE(info.is_direct());
759  EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI());
760
761  // Proxy times should have been updated, so get them again.
762  EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time());
763  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
764  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
765  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
766  proxy_resolve_start_time = info.proxy_resolve_start_time();
767  proxy_resolve_end_time = info.proxy_resolve_end_time();
768
769  // We fake another error. It should now try the third one.
770  TestCompletionCallback callback4;
771  rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL,
772                                         BoundNetLog());
773  EXPECT_EQ(OK, rv);
774  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
775
776  // We fake another error. At this point we have tried all of the
777  // proxy servers we thought were valid; next we try the proxy server
778  // that was in our bad proxies map (foopy1:8080).
779  TestCompletionCallback callback5;
780  rv = service.ReconsiderProxyAfterError(url, &info, callback5.callback(), NULL,
781                                         BoundNetLog());
782  EXPECT_EQ(OK, rv);
783  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
784
785  // Fake another error, the last proxy is gone, the list should now be empty,
786  // so there is nothing left to try.
787  TestCompletionCallback callback6;
788  rv = service.ReconsiderProxyAfterError(url, &info, callback6.callback(), NULL,
789                                         BoundNetLog());
790  EXPECT_EQ(ERR_FAILED, rv);
791  EXPECT_FALSE(info.is_direct());
792  EXPECT_TRUE(info.is_empty());
793
794  // Proxy times should not have been modified by fallback.
795  EXPECT_EQ(proxy_resolve_start_time, info.proxy_resolve_start_time());
796  EXPECT_EQ(proxy_resolve_end_time, info.proxy_resolve_end_time());
797
798  // Look up proxies again
799  TestCompletionCallback callback7;
800  rv = service.ResolveProxy(url, &info, callback7.callback(), NULL,
801                            BoundNetLog());
802  EXPECT_EQ(ERR_IO_PENDING, rv);
803
804  ASSERT_EQ(1u, resolver->pending_requests().size());
805  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
806
807  // This time, the first 3 results have been found to be bad, but only the
808  // first proxy has been confirmed ...
809  resolver->pending_requests()[0]->results()->UseNamedProxy(
810      "foopy1:8080;foopy3:7070;foopy2:9090;foopy4:9091");
811  resolver->pending_requests()[0]->CompleteNow(OK);
812
813  // ... therefore, we should see the second proxy first.
814  EXPECT_EQ(OK, callback7.WaitForResult());
815  EXPECT_FALSE(info.is_direct());
816  EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI());
817
818  EXPECT_LE(proxy_resolve_end_time, info.proxy_resolve_start_time());
819  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
820  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
821  // TODO(nsylvain): Test that the proxy can be retried after the delay.
822}
823
824// This test is similar to ProxyFallback, but this time we have an explicit
825// fallback choice to DIRECT.
826TEST_F(ProxyServiceTest, ProxyFallbackToDirect) {
827  MockProxyConfigService* config_service =
828      new MockProxyConfigService("http://foopy/proxy.pac");
829
830  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
831
832  ProxyService service(config_service, resolver, NULL);
833
834  GURL url("http://www.google.com/");
835
836  // Get the proxy information.
837  ProxyInfo info;
838  TestCompletionCallback callback1;
839  int rv = service.ResolveProxy(
840      url, &info, callback1.callback(), NULL, BoundNetLog());
841  EXPECT_EQ(ERR_IO_PENDING, rv);
842
843  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
844            resolver->pending_set_pac_script_request()->script_data()->url());
845  resolver->pending_set_pac_script_request()->CompleteNow(OK);
846
847  ASSERT_EQ(1u, resolver->pending_requests().size());
848  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
849
850  // Set the result in proxy resolver.
851  resolver->pending_requests()[0]->results()->UsePacString(
852      "PROXY foopy1:8080; PROXY foopy2:9090; DIRECT");
853  resolver->pending_requests()[0]->CompleteNow(OK);
854
855  // Get the first result.
856  EXPECT_EQ(OK, callback1.WaitForResult());
857  EXPECT_FALSE(info.is_direct());
858  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
859
860  // Fake an error on the proxy.
861  TestCompletionCallback callback2;
862  rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL,
863                                         BoundNetLog());
864  EXPECT_EQ(OK, rv);
865
866  // Now we get back the second proxy.
867  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
868
869  // Fake an error on this proxy as well.
870  TestCompletionCallback callback3;
871  rv = service.ReconsiderProxyAfterError(url, &info, callback3.callback(), NULL,
872                                         BoundNetLog());
873  EXPECT_EQ(OK, rv);
874
875  // Finally, we get back DIRECT.
876  EXPECT_TRUE(info.is_direct());
877
878  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
879  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
880  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
881
882  // Now we tell the proxy service that even DIRECT failed.
883  TestCompletionCallback callback4;
884  rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL,
885                                         BoundNetLog());
886  // There was nothing left to try after DIRECT, so we are out of
887  // choices.
888  EXPECT_EQ(ERR_FAILED, rv);
889}
890
891TEST_F(ProxyServiceTest, ProxyFallback_NewSettings) {
892  // Test proxy failover when new settings are available.
893
894  MockProxyConfigService* config_service =
895      new MockProxyConfigService("http://foopy/proxy.pac");
896
897  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
898
899  ProxyService service(config_service, resolver, NULL);
900
901  GURL url("http://www.google.com/");
902
903  // Get the proxy information.
904  ProxyInfo info;
905  TestCompletionCallback callback1;
906  int rv = service.ResolveProxy(
907      url, &info, callback1.callback(), NULL, BoundNetLog());
908  EXPECT_EQ(ERR_IO_PENDING, rv);
909
910  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
911            resolver->pending_set_pac_script_request()->script_data()->url());
912  resolver->pending_set_pac_script_request()->CompleteNow(OK);
913
914  ASSERT_EQ(1u, resolver->pending_requests().size());
915  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
916
917  // Set the result in proxy resolver.
918  resolver->pending_requests()[0]->results()->UseNamedProxy(
919      "foopy1:8080;foopy2:9090");
920  resolver->pending_requests()[0]->CompleteNow(OK);
921
922  // The first item is valid.
923  EXPECT_EQ(OK, callback1.WaitForResult());
924  EXPECT_FALSE(info.is_direct());
925  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
926
927  // Fake an error on the proxy, and also a new configuration on the proxy.
928  config_service->SetConfig(
929      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy-new/proxy.pac")));
930
931  TestCompletionCallback callback2;
932  rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL,
933                                         BoundNetLog());
934  EXPECT_EQ(ERR_IO_PENDING, rv);
935
936  EXPECT_EQ(GURL("http://foopy-new/proxy.pac"),
937            resolver->pending_set_pac_script_request()->script_data()->url());
938  resolver->pending_set_pac_script_request()->CompleteNow(OK);
939
940  ASSERT_EQ(1u, resolver->pending_requests().size());
941  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
942
943  resolver->pending_requests()[0]->results()->UseNamedProxy(
944      "foopy1:8080;foopy2:9090");
945  resolver->pending_requests()[0]->CompleteNow(OK);
946
947  // The first proxy is still there since the configuration changed.
948  EXPECT_EQ(OK, callback2.WaitForResult());
949  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
950
951  // We fake another error. It should now ignore the first one.
952  TestCompletionCallback callback3;
953  rv = service.ReconsiderProxyAfterError(url, &info, callback3.callback(), NULL,
954                                         BoundNetLog());
955  EXPECT_EQ(OK, rv);
956  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
957
958  // We simulate a new configuration.
959  config_service->SetConfig(
960      ProxyConfig::CreateFromCustomPacURL(
961          GURL("http://foopy-new2/proxy.pac")));
962
963  // We fake another error. It should go back to the first proxy.
964  TestCompletionCallback callback4;
965  rv = service.ReconsiderProxyAfterError(url, &info, callback4.callback(), NULL,
966                                         BoundNetLog());
967  EXPECT_EQ(ERR_IO_PENDING, rv);
968
969  EXPECT_EQ(GURL("http://foopy-new2/proxy.pac"),
970            resolver->pending_set_pac_script_request()->script_data()->url());
971  resolver->pending_set_pac_script_request()->CompleteNow(OK);
972
973  ASSERT_EQ(1u, resolver->pending_requests().size());
974  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
975
976  resolver->pending_requests()[0]->results()->UseNamedProxy(
977      "foopy1:8080;foopy2:9090");
978  resolver->pending_requests()[0]->CompleteNow(OK);
979
980  EXPECT_EQ(OK, callback4.WaitForResult());
981  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
982
983  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
984  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
985  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
986}
987
988TEST_F(ProxyServiceTest, ProxyFallback_BadConfig) {
989  // Test proxy failover when the configuration is bad.
990
991  MockProxyConfigService* config_service =
992      new MockProxyConfigService("http://foopy/proxy.pac");
993
994  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
995
996  ProxyService service(config_service, resolver, NULL);
997
998  GURL url("http://www.google.com/");
999
1000  // Get the proxy information.
1001  ProxyInfo info;
1002  TestCompletionCallback callback1;
1003  int rv = service.ResolveProxy(
1004      url, &info, callback1.callback(), NULL, BoundNetLog());
1005  EXPECT_EQ(ERR_IO_PENDING, rv);
1006
1007  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1008            resolver->pending_set_pac_script_request()->script_data()->url());
1009  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1010  ASSERT_EQ(1u, resolver->pending_requests().size());
1011  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
1012
1013  resolver->pending_requests()[0]->results()->UseNamedProxy(
1014      "foopy1:8080;foopy2:9090");
1015  resolver->pending_requests()[0]->CompleteNow(OK);
1016
1017  // The first item is valid.
1018  EXPECT_EQ(OK, callback1.WaitForResult());
1019  EXPECT_FALSE(info.is_direct());
1020  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
1021
1022  // Fake a proxy error.
1023  TestCompletionCallback callback2;
1024  rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL,
1025                                         BoundNetLog());
1026  EXPECT_EQ(OK, rv);
1027
1028  // The first proxy is ignored, and the second one is selected.
1029  EXPECT_FALSE(info.is_direct());
1030  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
1031
1032  // Fake a PAC failure.
1033  ProxyInfo info2;
1034  TestCompletionCallback callback3;
1035  rv = service.ResolveProxy(
1036      url, &info2, callback3.callback(), NULL, BoundNetLog());
1037  EXPECT_EQ(ERR_IO_PENDING, rv);
1038
1039  ASSERT_EQ(1u, resolver->pending_requests().size());
1040  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
1041
1042  // This simulates a javascript runtime error in the PAC script.
1043  resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
1044
1045  // Although the resolver failed, the ProxyService will implicitly fall-back
1046  // to a DIRECT connection.
1047  EXPECT_EQ(OK, callback3.WaitForResult());
1048  EXPECT_TRUE(info2.is_direct());
1049  EXPECT_FALSE(info2.is_empty());
1050
1051  // The PAC script will work properly next time and successfully return a
1052  // proxy list. Since we have not marked the configuration as bad, it should
1053  // "just work" the next time we call it.
1054  ProxyInfo info3;
1055  TestCompletionCallback callback4;
1056  rv = service.ReconsiderProxyAfterError(url, &info3, callback4.callback(),
1057                                         NULL, BoundNetLog());
1058  EXPECT_EQ(ERR_IO_PENDING, rv);
1059
1060  ASSERT_EQ(1u, resolver->pending_requests().size());
1061  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
1062
1063  resolver->pending_requests()[0]->results()->UseNamedProxy(
1064      "foopy1:8080;foopy2:9090");
1065  resolver->pending_requests()[0]->CompleteNow(OK);
1066
1067  // The first proxy is not there since the it was added to the bad proxies
1068  // list by the earlier ReconsiderProxyAfterError().
1069  EXPECT_EQ(OK, callback4.WaitForResult());
1070  EXPECT_FALSE(info3.is_direct());
1071  EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
1072
1073  EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
1074  EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
1075  EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
1076}
1077
1078TEST_F(ProxyServiceTest, ProxyFallback_BadConfigMandatory) {
1079  // Test proxy failover when the configuration is bad.
1080
1081  ProxyConfig config(
1082      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac")));
1083
1084  config.set_pac_mandatory(true);
1085  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1086
1087  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
1088
1089  ProxyService service(config_service, resolver, NULL);
1090
1091  GURL url("http://www.google.com/");
1092
1093  // Get the proxy information.
1094  ProxyInfo info;
1095  TestCompletionCallback callback1;
1096  int rv = service.ResolveProxy(
1097      url, &info, callback1.callback(), NULL, BoundNetLog());
1098  EXPECT_EQ(ERR_IO_PENDING, rv);
1099
1100  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1101            resolver->pending_set_pac_script_request()->script_data()->url());
1102  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1103  ASSERT_EQ(1u, resolver->pending_requests().size());
1104  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
1105
1106  resolver->pending_requests()[0]->results()->UseNamedProxy(
1107      "foopy1:8080;foopy2:9090");
1108  resolver->pending_requests()[0]->CompleteNow(OK);
1109
1110  // The first item is valid.
1111  EXPECT_EQ(OK, callback1.WaitForResult());
1112  EXPECT_FALSE(info.is_direct());
1113  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
1114
1115  // Fake a proxy error.
1116  TestCompletionCallback callback2;
1117  rv = service.ReconsiderProxyAfterError(url, &info, callback2.callback(), NULL,
1118                                         BoundNetLog());
1119  EXPECT_EQ(OK, rv);
1120
1121  // The first proxy is ignored, and the second one is selected.
1122  EXPECT_FALSE(info.is_direct());
1123  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
1124
1125  // Fake a PAC failure.
1126  ProxyInfo info2;
1127  TestCompletionCallback callback3;
1128  rv = service.ResolveProxy(
1129      url, &info2, callback3.callback(), NULL, BoundNetLog());
1130  EXPECT_EQ(ERR_IO_PENDING, rv);
1131
1132  ASSERT_EQ(1u, resolver->pending_requests().size());
1133  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
1134
1135  // This simulates a javascript runtime error in the PAC script.
1136  resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
1137
1138  // Although the resolver failed, the ProxyService will NOT fall-back
1139  // to a DIRECT connection as it is configured as mandatory.
1140  EXPECT_EQ(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED,
1141            callback3.WaitForResult());
1142  EXPECT_FALSE(info2.is_direct());
1143  EXPECT_TRUE(info2.is_empty());
1144
1145  // The PAC script will work properly next time and successfully return a
1146  // proxy list. Since we have not marked the configuration as bad, it should
1147  // "just work" the next time we call it.
1148  ProxyInfo info3;
1149  TestCompletionCallback callback4;
1150  rv = service.ReconsiderProxyAfterError(url, &info3, callback4.callback(),
1151                                         NULL, BoundNetLog());
1152  EXPECT_EQ(ERR_IO_PENDING, rv);
1153
1154  ASSERT_EQ(1u, resolver->pending_requests().size());
1155  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
1156
1157  resolver->pending_requests()[0]->results()->UseNamedProxy(
1158      "foopy1:8080;foopy2:9090");
1159  resolver->pending_requests()[0]->CompleteNow(OK);
1160
1161  // The first proxy is not there since the it was added to the bad proxies
1162  // list by the earlier ReconsiderProxyAfterError().
1163  EXPECT_EQ(OK, callback4.WaitForResult());
1164  EXPECT_FALSE(info3.is_direct());
1165  EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
1166}
1167
1168TEST_F(ProxyServiceTest, ProxyBypassList) {
1169  // Test that the proxy bypass rules are consulted.
1170
1171  TestCompletionCallback callback[2];
1172  ProxyInfo info[2];
1173  ProxyConfig config;
1174  config.proxy_rules().ParseFromString("foopy1:8080;foopy2:9090");
1175  config.set_auto_detect(false);
1176  config.proxy_rules().bypass_rules.ParseFromString("*.org");
1177
1178  ProxyService service(
1179      new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1180
1181  int rv;
1182  GURL url1("http://www.webkit.org");
1183  GURL url2("http://www.webkit.com");
1184
1185  // Request for a .org domain should bypass proxy.
1186  rv = service.ResolveProxy(
1187      url1, &info[0], callback[0].callback(), NULL, BoundNetLog());
1188  EXPECT_EQ(OK, rv);
1189  EXPECT_TRUE(info[0].is_direct());
1190
1191  // Request for a .com domain hits the proxy.
1192  rv = service.ResolveProxy(
1193      url2, &info[1], callback[1].callback(), NULL, BoundNetLog());
1194  EXPECT_EQ(OK, rv);
1195  EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI());
1196}
1197
1198
1199TEST_F(ProxyServiceTest, PerProtocolProxyTests) {
1200  ProxyConfig config;
1201  config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080");
1202  config.set_auto_detect(false);
1203  {
1204    ProxyService service(
1205        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1206    GURL test_url("http://www.msn.com");
1207    ProxyInfo info;
1208    TestCompletionCallback callback;
1209    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1210                                  BoundNetLog());
1211    EXPECT_EQ(OK, rv);
1212    EXPECT_FALSE(info.is_direct());
1213    EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
1214  }
1215  {
1216    ProxyService service(
1217        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1218    GURL test_url("ftp://ftp.google.com");
1219    ProxyInfo info;
1220    TestCompletionCallback callback;
1221    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1222                                  BoundNetLog());
1223    EXPECT_EQ(OK, rv);
1224    EXPECT_TRUE(info.is_direct());
1225    EXPECT_EQ("direct://", info.proxy_server().ToURI());
1226  }
1227  {
1228    ProxyService service(
1229        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1230    GURL test_url("https://webbranch.techcu.com");
1231    ProxyInfo info;
1232    TestCompletionCallback callback;
1233    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1234                                  BoundNetLog());
1235    EXPECT_EQ(OK, rv);
1236    EXPECT_FALSE(info.is_direct());
1237    EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
1238  }
1239  {
1240    config.proxy_rules().ParseFromString("foopy1:8080");
1241    ProxyService service(
1242        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1243    GURL test_url("http://www.microsoft.com");
1244    ProxyInfo info;
1245    TestCompletionCallback callback;
1246    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1247                                  BoundNetLog());
1248    EXPECT_EQ(OK, rv);
1249    EXPECT_FALSE(info.is_direct());
1250    EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
1251  }
1252}
1253
1254TEST_F(ProxyServiceTest, ProxyConfigSourcePropagates) {
1255  // Test that the proxy config source is set correctly when resolving proxies
1256  // using manual proxy rules. Namely, the config source should only be set if
1257  // any of the rules were applied.
1258  {
1259    ProxyConfig config;
1260    config.set_source(PROXY_CONFIG_SOURCE_TEST);
1261    config.proxy_rules().ParseFromString("https=foopy2:8080");
1262    ProxyService service(
1263        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1264    GURL test_url("http://www.google.com");
1265    ProxyInfo info;
1266    TestCompletionCallback callback;
1267    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1268                                  BoundNetLog());
1269    ASSERT_EQ(OK, rv);
1270    // Should be SOURCE_TEST, even if there are no HTTP proxies configured.
1271    EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
1272  }
1273  {
1274    ProxyConfig config;
1275    config.set_source(PROXY_CONFIG_SOURCE_TEST);
1276    config.proxy_rules().ParseFromString("https=foopy2:8080");
1277    ProxyService service(
1278        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1279    GURL test_url("https://www.google.com");
1280    ProxyInfo info;
1281    TestCompletionCallback callback;
1282    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1283                                  BoundNetLog());
1284    ASSERT_EQ(OK, rv);
1285    // Used the HTTPS proxy. So source should be TEST.
1286    EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
1287  }
1288  {
1289    ProxyConfig config;
1290    config.set_source(PROXY_CONFIG_SOURCE_TEST);
1291    ProxyService service(
1292        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1293    GURL test_url("http://www.google.com");
1294    ProxyInfo info;
1295    TestCompletionCallback callback;
1296    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1297                                  BoundNetLog());
1298    ASSERT_EQ(OK, rv);
1299    // ProxyConfig is empty. Source should still be TEST.
1300    EXPECT_EQ(PROXY_CONFIG_SOURCE_TEST, info.config_source());
1301  }
1302}
1303
1304// If only HTTP and a SOCKS proxy are specified, check if ftp/https queries
1305// fall back to the SOCKS proxy.
1306TEST_F(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
1307  ProxyConfig config;
1308  config.proxy_rules().ParseFromString("http=foopy1:8080;socks=foopy2:1080");
1309  config.set_auto_detect(false);
1310  EXPECT_EQ(ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME,
1311            config.proxy_rules().type);
1312
1313  {
1314    ProxyService service(
1315        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1316    GURL test_url("http://www.msn.com");
1317    ProxyInfo info;
1318    TestCompletionCallback callback;
1319    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1320                                  BoundNetLog());
1321    EXPECT_EQ(OK, rv);
1322    EXPECT_FALSE(info.is_direct());
1323    EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
1324  }
1325  {
1326    ProxyService service(
1327        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1328    GURL test_url("ftp://ftp.google.com");
1329    ProxyInfo info;
1330    TestCompletionCallback callback;
1331    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1332                                  BoundNetLog());
1333    EXPECT_EQ(OK, rv);
1334    EXPECT_FALSE(info.is_direct());
1335    EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
1336  }
1337  {
1338    ProxyService service(
1339        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1340    GURL test_url("https://webbranch.techcu.com");
1341    ProxyInfo info;
1342    TestCompletionCallback callback;
1343    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1344                                  BoundNetLog());
1345    EXPECT_EQ(OK, rv);
1346    EXPECT_FALSE(info.is_direct());
1347    EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
1348  }
1349  {
1350    ProxyService service(
1351        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL);
1352    GURL test_url("unknown://www.microsoft.com");
1353    ProxyInfo info;
1354    TestCompletionCallback callback;
1355    int rv = service.ResolveProxy(test_url, &info, callback.callback(), NULL,
1356                                  BoundNetLog());
1357    EXPECT_EQ(OK, rv);
1358    EXPECT_FALSE(info.is_direct());
1359    EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
1360  }
1361}
1362
1363// Test cancellation of an in-progress request.
1364TEST_F(ProxyServiceTest, CancelInProgressRequest) {
1365  MockProxyConfigService* config_service =
1366      new MockProxyConfigService("http://foopy/proxy.pac");
1367
1368  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
1369
1370  ProxyService service(config_service, resolver, NULL);
1371
1372  // Start 3 requests.
1373
1374  ProxyInfo info1;
1375  TestCompletionCallback callback1;
1376  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1377                                callback1.callback(), NULL, BoundNetLog());
1378  EXPECT_EQ(ERR_IO_PENDING, rv);
1379
1380  // Nothing has been sent to the proxy resolver yet, since the proxy
1381  // resolver has not been configured yet.
1382  ASSERT_EQ(0u, resolver->pending_requests().size());
1383
1384  // Successfully initialize the PAC script.
1385  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1386            resolver->pending_set_pac_script_request()->script_data()->url());
1387  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1388
1389  ASSERT_EQ(1u, resolver->pending_requests().size());
1390  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1391
1392  ProxyInfo info2;
1393  TestCompletionCallback callback2;
1394  ProxyService::PacRequest* request2;
1395  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1396                            callback2.callback(), &request2, BoundNetLog());
1397  EXPECT_EQ(ERR_IO_PENDING, rv);
1398  ASSERT_EQ(2u, resolver->pending_requests().size());
1399  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1400
1401  ProxyInfo info3;
1402  TestCompletionCallback callback3;
1403  rv = service.ResolveProxy(GURL("http://request3"), &info3,
1404                            callback3.callback(), NULL, BoundNetLog());
1405  EXPECT_EQ(ERR_IO_PENDING, rv);
1406  ASSERT_EQ(3u, resolver->pending_requests().size());
1407  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url());
1408
1409  // Cancel the second request
1410  service.CancelPacRequest(request2);
1411
1412  ASSERT_EQ(2u, resolver->pending_requests().size());
1413  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1414  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[1]->url());
1415
1416  // Complete the two un-cancelled requests.
1417  // We complete the last one first, just to mix it up a bit.
1418  resolver->pending_requests()[1]->results()->UseNamedProxy("request3:80");
1419  resolver->pending_requests()[1]->CompleteNow(OK);
1420
1421  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1422  resolver->pending_requests()[0]->CompleteNow(OK);
1423
1424  // Complete and verify that requests ran as expected.
1425  EXPECT_EQ(OK, callback1.WaitForResult());
1426  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1427
1428  EXPECT_FALSE(callback2.have_result());  // Cancelled.
1429  ASSERT_EQ(1u, resolver->cancelled_requests().size());
1430  EXPECT_EQ(GURL("http://request2"), resolver->cancelled_requests()[0]->url());
1431
1432  EXPECT_EQ(OK, callback3.WaitForResult());
1433  EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
1434}
1435
1436// Test the initial PAC download for resolver that expects bytes.
1437TEST_F(ProxyServiceTest, InitialPACScriptDownload) {
1438  MockProxyConfigService* config_service =
1439      new MockProxyConfigService("http://foopy/proxy.pac");
1440
1441  MockAsyncProxyResolverExpectsBytes* resolver =
1442      new MockAsyncProxyResolverExpectsBytes;
1443
1444  ProxyService service(config_service, resolver, NULL);
1445
1446  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1447  service.SetProxyScriptFetchers(fetcher,
1448                                 new DoNothingDhcpProxyScriptFetcher());
1449
1450  // Start 3 requests.
1451
1452  ProxyInfo info1;
1453  TestCompletionCallback callback1;
1454  ProxyService::PacRequest* request1;
1455  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1456                                callback1.callback(), &request1, BoundNetLog());
1457  EXPECT_EQ(ERR_IO_PENDING, rv);
1458
1459  // The first request should have triggered download of PAC script.
1460  EXPECT_TRUE(fetcher->has_pending_request());
1461  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1462
1463  ProxyInfo info2;
1464  TestCompletionCallback callback2;
1465  ProxyService::PacRequest* request2;
1466  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1467                            callback2.callback(), &request2, BoundNetLog());
1468  EXPECT_EQ(ERR_IO_PENDING, rv);
1469
1470  ProxyInfo info3;
1471  TestCompletionCallback callback3;
1472  ProxyService::PacRequest* request3;
1473  rv = service.ResolveProxy(GURL("http://request3"), &info3,
1474                            callback3.callback(), &request3, BoundNetLog());
1475  EXPECT_EQ(ERR_IO_PENDING, rv);
1476
1477  // Nothing has been sent to the resolver yet.
1478  EXPECT_TRUE(resolver->pending_requests().empty());
1479
1480  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT,
1481            service.GetLoadState(request1));
1482  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT,
1483            service.GetLoadState(request2));
1484  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT,
1485            service.GetLoadState(request3));
1486
1487  // At this point the ProxyService should be waiting for the
1488  // ProxyScriptFetcher to invoke its completion callback, notifying it of
1489  // PAC script download completion.
1490  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
1491
1492  // Now that the PAC script is downloaded, it will have been sent to the proxy
1493  // resolver.
1494  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
1495            resolver->pending_set_pac_script_request()->script_data()->utf16());
1496  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1497
1498  ASSERT_EQ(3u, resolver->pending_requests().size());
1499  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1500  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1501  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url());
1502
1503  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request1));
1504  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request2));
1505  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request3));
1506
1507  // Complete all the requests (in some order).
1508  // Note that as we complete requests, they shift up in |pending_requests()|.
1509
1510  resolver->pending_requests()[2]->results()->UseNamedProxy("request3:80");
1511  resolver->pending_requests()[2]->CompleteNow(OK);
1512
1513  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1514  resolver->pending_requests()[0]->CompleteNow(OK);
1515
1516  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
1517  resolver->pending_requests()[0]->CompleteNow(OK);
1518
1519  // Complete and verify that requests ran as expected.
1520  EXPECT_EQ(OK, callback1.WaitForResult());
1521  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1522  EXPECT_FALSE(info1.proxy_resolve_start_time().is_null());
1523  EXPECT_FALSE(info1.proxy_resolve_end_time().is_null());
1524  EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time());
1525
1526  EXPECT_EQ(OK, callback2.WaitForResult());
1527  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1528  EXPECT_FALSE(info2.proxy_resolve_start_time().is_null());
1529  EXPECT_FALSE(info2.proxy_resolve_end_time().is_null());
1530  EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time());
1531
1532  EXPECT_EQ(OK, callback3.WaitForResult());
1533  EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
1534  EXPECT_FALSE(info3.proxy_resolve_start_time().is_null());
1535  EXPECT_FALSE(info3.proxy_resolve_end_time().is_null());
1536  EXPECT_LE(info3.proxy_resolve_start_time(), info3.proxy_resolve_end_time());
1537}
1538
1539// Test changing the ProxyScriptFetcher while PAC download is in progress.
1540TEST_F(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) {
1541  MockProxyConfigService* config_service =
1542      new MockProxyConfigService("http://foopy/proxy.pac");
1543
1544  MockAsyncProxyResolverExpectsBytes* resolver =
1545      new MockAsyncProxyResolverExpectsBytes;
1546
1547  ProxyService service(config_service, resolver, NULL);
1548
1549  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1550  service.SetProxyScriptFetchers(fetcher,
1551                                 new DoNothingDhcpProxyScriptFetcher());
1552
1553  // Start 2 requests.
1554
1555  ProxyInfo info1;
1556  TestCompletionCallback callback1;
1557  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1558                                callback1.callback(), NULL, BoundNetLog());
1559  EXPECT_EQ(ERR_IO_PENDING, rv);
1560
1561  // The first request should have triggered download of PAC script.
1562  EXPECT_TRUE(fetcher->has_pending_request());
1563  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1564
1565  ProxyInfo info2;
1566  TestCompletionCallback callback2;
1567  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1568                            callback2.callback(), NULL, BoundNetLog());
1569  EXPECT_EQ(ERR_IO_PENDING, rv);
1570
1571  // At this point the ProxyService should be waiting for the
1572  // ProxyScriptFetcher to invoke its completion callback, notifying it of
1573  // PAC script download completion.
1574
1575  // We now change out the ProxyService's script fetcher. We should restart
1576  // the initialization with the new fetcher.
1577
1578  fetcher = new MockProxyScriptFetcher;
1579  service.SetProxyScriptFetchers(fetcher,
1580                                 new DoNothingDhcpProxyScriptFetcher());
1581
1582  // Nothing has been sent to the resolver yet.
1583  EXPECT_TRUE(resolver->pending_requests().empty());
1584
1585  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
1586
1587  // Now that the PAC script is downloaded, it will have been sent to the proxy
1588  // resolver.
1589  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
1590            resolver->pending_set_pac_script_request()->script_data()->utf16());
1591  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1592
1593  ASSERT_EQ(2u, resolver->pending_requests().size());
1594  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1595  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1596}
1597
1598// Test cancellation of a request, while the PAC script is being fetched.
1599TEST_F(ProxyServiceTest, CancelWhilePACFetching) {
1600  MockProxyConfigService* config_service =
1601      new MockProxyConfigService("http://foopy/proxy.pac");
1602
1603  MockAsyncProxyResolverExpectsBytes* resolver =
1604      new MockAsyncProxyResolverExpectsBytes;
1605
1606  ProxyService service(config_service, resolver, NULL);
1607
1608  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1609  service.SetProxyScriptFetchers(fetcher,
1610                                 new DoNothingDhcpProxyScriptFetcher());
1611
1612  // Start 3 requests.
1613  ProxyInfo info1;
1614  TestCompletionCallback callback1;
1615  ProxyService::PacRequest* request1;
1616  CapturingBoundNetLog log1;
1617  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1618                                callback1.callback(), &request1, log1.bound());
1619  EXPECT_EQ(ERR_IO_PENDING, rv);
1620
1621  // The first request should have triggered download of PAC script.
1622  EXPECT_TRUE(fetcher->has_pending_request());
1623  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1624
1625  ProxyInfo info2;
1626  TestCompletionCallback callback2;
1627  ProxyService::PacRequest* request2;
1628  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1629                            callback2.callback(), &request2, BoundNetLog());
1630  EXPECT_EQ(ERR_IO_PENDING, rv);
1631
1632  ProxyInfo info3;
1633  TestCompletionCallback callback3;
1634  rv = service.ResolveProxy(GURL("http://request3"), &info3,
1635                            callback3.callback(), NULL, BoundNetLog());
1636  EXPECT_EQ(ERR_IO_PENDING, rv);
1637
1638  // Nothing has been sent to the resolver yet.
1639  EXPECT_TRUE(resolver->pending_requests().empty());
1640
1641  // Cancel the first 2 requests.
1642  service.CancelPacRequest(request1);
1643  service.CancelPacRequest(request2);
1644
1645  // At this point the ProxyService should be waiting for the
1646  // ProxyScriptFetcher to invoke its completion callback, notifying it of
1647  // PAC script download completion.
1648  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
1649
1650  // Now that the PAC script is downloaded, it will have been sent to the
1651  // proxy resolver.
1652  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
1653            resolver->pending_set_pac_script_request()->script_data()->utf16());
1654  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1655
1656  ASSERT_EQ(1u, resolver->pending_requests().size());
1657  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[0]->url());
1658
1659  // Complete all the requests.
1660  resolver->pending_requests()[0]->results()->UseNamedProxy("request3:80");
1661  resolver->pending_requests()[0]->CompleteNow(OK);
1662
1663  EXPECT_EQ(OK, callback3.WaitForResult());
1664  EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
1665
1666  EXPECT_TRUE(resolver->cancelled_requests().empty());
1667
1668  EXPECT_FALSE(callback1.have_result());  // Cancelled.
1669  EXPECT_FALSE(callback2.have_result());  // Cancelled.
1670
1671  CapturingNetLog::CapturedEntryList entries1;
1672  log1.GetEntries(&entries1);
1673
1674  // Check the NetLog for request 1 (which was cancelled) got filled properly.
1675  EXPECT_EQ(4u, entries1.size());
1676  EXPECT_TRUE(LogContainsBeginEvent(
1677      entries1, 0, NetLog::TYPE_PROXY_SERVICE));
1678  EXPECT_TRUE(LogContainsBeginEvent(
1679      entries1, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
1680  // Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
1681  // the cancellation occured.
1682  EXPECT_TRUE(LogContainsEvent(
1683      entries1, 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
1684  EXPECT_TRUE(LogContainsEndEvent(
1685      entries1, 3, NetLog::TYPE_PROXY_SERVICE));
1686}
1687
1688// Test that if auto-detect fails, we fall-back to the custom pac.
1689TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac) {
1690  ProxyConfig config;
1691  config.set_auto_detect(true);
1692  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1693  config.proxy_rules().ParseFromString("http=foopy:80");  // Won't be used.
1694
1695  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1696  MockAsyncProxyResolverExpectsBytes* resolver =
1697      new MockAsyncProxyResolverExpectsBytes;
1698  ProxyService service(config_service, resolver, NULL);
1699
1700  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1701  service.SetProxyScriptFetchers(fetcher,
1702                                 new DoNothingDhcpProxyScriptFetcher());
1703
1704  // Start 2 requests.
1705
1706  ProxyInfo info1;
1707  TestCompletionCallback callback1;
1708  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1709                                callback1.callback(), NULL, BoundNetLog());
1710  EXPECT_EQ(ERR_IO_PENDING, rv);
1711
1712  ProxyInfo info2;
1713  TestCompletionCallback callback2;
1714  ProxyService::PacRequest* request2;
1715  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1716                            callback2.callback(), &request2, BoundNetLog());
1717  EXPECT_EQ(ERR_IO_PENDING, rv);
1718
1719  // Check that nothing has been sent to the proxy resolver yet.
1720  ASSERT_EQ(0u, resolver->pending_requests().size());
1721
1722  // It should be trying to auto-detect first -- FAIL the autodetect during
1723  // the script download.
1724  EXPECT_TRUE(fetcher->has_pending_request());
1725  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1726  fetcher->NotifyFetchCompletion(ERR_FAILED, std::string());
1727
1728  // Next it should be trying the custom PAC url.
1729  EXPECT_TRUE(fetcher->has_pending_request());
1730  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1731  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
1732
1733  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
1734            resolver->pending_set_pac_script_request()->script_data()->utf16());
1735  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1736
1737  // Now finally, the pending requests should have been sent to the resolver
1738  // (which was initialized with custom PAC script).
1739
1740  ASSERT_EQ(2u, resolver->pending_requests().size());
1741  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1742  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1743
1744  // Complete the pending requests.
1745  resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80");
1746  resolver->pending_requests()[1]->CompleteNow(OK);
1747  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1748  resolver->pending_requests()[0]->CompleteNow(OK);
1749
1750  // Verify that requests ran as expected.
1751  EXPECT_EQ(OK, callback1.WaitForResult());
1752  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1753  EXPECT_FALSE(info1.proxy_resolve_start_time().is_null());
1754  EXPECT_FALSE(info1.proxy_resolve_end_time().is_null());
1755  EXPECT_LE(info1.proxy_resolve_start_time(), info1.proxy_resolve_end_time());
1756
1757  EXPECT_EQ(OK, callback2.WaitForResult());
1758  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1759  EXPECT_FALSE(info2.proxy_resolve_start_time().is_null());
1760  EXPECT_FALSE(info2.proxy_resolve_end_time().is_null());
1761  EXPECT_LE(info2.proxy_resolve_start_time(), info2.proxy_resolve_end_time());
1762}
1763
1764// This is the same test as FallbackFromAutodetectToCustomPac, except
1765// the auto-detect script fails parsing rather than downloading.
1766TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) {
1767  ProxyConfig config;
1768  config.set_auto_detect(true);
1769  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1770  config.proxy_rules().ParseFromString("http=foopy:80");  // Won't be used.
1771
1772  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1773  MockAsyncProxyResolverExpectsBytes* resolver =
1774      new MockAsyncProxyResolverExpectsBytes;
1775  ProxyService service(config_service, resolver, NULL);
1776
1777  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1778  service.SetProxyScriptFetchers(fetcher,
1779                                 new DoNothingDhcpProxyScriptFetcher());
1780
1781  // Start 2 requests.
1782
1783  ProxyInfo info1;
1784  TestCompletionCallback callback1;
1785  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1786                                callback1.callback(), NULL, BoundNetLog());
1787  EXPECT_EQ(ERR_IO_PENDING, rv);
1788
1789  ProxyInfo info2;
1790  TestCompletionCallback callback2;
1791  ProxyService::PacRequest* request2;
1792  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1793                            callback2.callback(), &request2, BoundNetLog());
1794  EXPECT_EQ(ERR_IO_PENDING, rv);
1795
1796  // Check that nothing has been sent to the proxy resolver yet.
1797  ASSERT_EQ(0u, resolver->pending_requests().size());
1798
1799  // It should be trying to auto-detect first -- succeed the download.
1800  EXPECT_TRUE(fetcher->has_pending_request());
1801  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1802  fetcher->NotifyFetchCompletion(OK, "invalid-script-contents");
1803
1804  // The script contents passed failed basic verification step (since didn't
1805  // contain token FindProxyForURL), so it was never passed to the resolver.
1806
1807  // Next it should be trying the custom PAC url.
1808  EXPECT_TRUE(fetcher->has_pending_request());
1809  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1810  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
1811
1812  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
1813            resolver->pending_set_pac_script_request()->script_data()->utf16());
1814  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1815
1816  // Now finally, the pending requests should have been sent to the resolver
1817  // (which was initialized with custom PAC script).
1818
1819  ASSERT_EQ(2u, resolver->pending_requests().size());
1820  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1821  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1822
1823  // Complete the pending requests.
1824  resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80");
1825  resolver->pending_requests()[1]->CompleteNow(OK);
1826  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1827  resolver->pending_requests()[0]->CompleteNow(OK);
1828
1829  // Verify that requests ran as expected.
1830  EXPECT_EQ(OK, callback1.WaitForResult());
1831  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1832
1833  EXPECT_EQ(OK, callback2.WaitForResult());
1834  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1835}
1836
1837// Test that if all of auto-detect, a custom PAC script, and manual settings
1838// are given, then we will try them in that order.
1839TEST_F(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) {
1840  ProxyConfig config;
1841  config.set_auto_detect(true);
1842  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1843  config.proxy_rules().ParseFromString("http=foopy:80");
1844
1845  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1846  MockAsyncProxyResolverExpectsBytes* resolver =
1847      new MockAsyncProxyResolverExpectsBytes;
1848  ProxyService service(config_service, resolver, NULL);
1849
1850  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1851  service.SetProxyScriptFetchers(fetcher,
1852                                 new DoNothingDhcpProxyScriptFetcher());
1853
1854  // Start 2 requests.
1855
1856  ProxyInfo info1;
1857  TestCompletionCallback callback1;
1858  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
1859                                callback1.callback(), NULL, BoundNetLog());
1860  EXPECT_EQ(ERR_IO_PENDING, rv);
1861
1862  ProxyInfo info2;
1863  TestCompletionCallback callback2;
1864  ProxyService::PacRequest* request2;
1865  rv = service.ResolveProxy(GURL("http://request2"), &info2,
1866                            callback2.callback(), &request2, BoundNetLog());
1867  EXPECT_EQ(ERR_IO_PENDING, rv);
1868
1869  // Check that nothing has been sent to the proxy resolver yet.
1870  ASSERT_EQ(0u, resolver->pending_requests().size());
1871
1872  // It should be trying to auto-detect first -- fail the download.
1873  EXPECT_TRUE(fetcher->has_pending_request());
1874  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1875  fetcher->NotifyFetchCompletion(ERR_FAILED, std::string());
1876
1877  // Next it should be trying the custom PAC url -- fail the download.
1878  EXPECT_TRUE(fetcher->has_pending_request());
1879  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1880  fetcher->NotifyFetchCompletion(ERR_FAILED, std::string());
1881
1882  // Since we never managed to initialize a ProxyResolver, nothing should have
1883  // been sent to it.
1884  ASSERT_EQ(0u, resolver->pending_requests().size());
1885
1886  // Verify that requests ran as expected -- they should have fallen back to
1887  // the manual proxy configuration for HTTP urls.
1888  EXPECT_EQ(OK, callback1.WaitForResult());
1889  EXPECT_EQ("foopy:80", info1.proxy_server().ToURI());
1890
1891  EXPECT_EQ(OK, callback2.WaitForResult());
1892  EXPECT_EQ("foopy:80", info2.proxy_server().ToURI());
1893}
1894
1895// Test that the bypass rules are NOT applied when using autodetect.
1896TEST_F(ProxyServiceTest, BypassDoesntApplyToPac) {
1897  ProxyConfig config;
1898  config.set_auto_detect(true);
1899  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1900  config.proxy_rules().ParseFromString("http=foopy:80");  // Not used.
1901  config.proxy_rules().bypass_rules.ParseFromString("www.google.com");
1902
1903  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1904  MockAsyncProxyResolverExpectsBytes* resolver =
1905      new MockAsyncProxyResolverExpectsBytes;
1906  ProxyService service(config_service, resolver, NULL);
1907
1908  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1909  service.SetProxyScriptFetchers(fetcher,
1910                                 new DoNothingDhcpProxyScriptFetcher());
1911
1912  // Start 1 requests.
1913
1914  ProxyInfo info1;
1915  TestCompletionCallback callback1;
1916  int rv = service.ResolveProxy(
1917      GURL("http://www.google.com"), &info1, callback1.callback(), NULL,
1918      BoundNetLog());
1919  EXPECT_EQ(ERR_IO_PENDING, rv);
1920
1921  // Check that nothing has been sent to the proxy resolver yet.
1922  ASSERT_EQ(0u, resolver->pending_requests().size());
1923
1924  // It should be trying to auto-detect first -- succeed the download.
1925  EXPECT_TRUE(fetcher->has_pending_request());
1926  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1927  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
1928
1929  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
1930            resolver->pending_set_pac_script_request()->script_data()->utf16());
1931  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1932
1933  ASSERT_EQ(1u, resolver->pending_requests().size());
1934  EXPECT_EQ(GURL("http://www.google.com"),
1935            resolver->pending_requests()[0]->url());
1936
1937  // Complete the pending request.
1938  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1939  resolver->pending_requests()[0]->CompleteNow(OK);
1940
1941  // Verify that request ran as expected.
1942  EXPECT_EQ(OK, callback1.WaitForResult());
1943  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1944
1945  // Start another request, it should pickup the bypass item.
1946  ProxyInfo info2;
1947  TestCompletionCallback callback2;
1948  rv = service.ResolveProxy(GURL("http://www.google.com"), &info2,
1949                            callback2.callback(), NULL, BoundNetLog());
1950  EXPECT_EQ(ERR_IO_PENDING, rv);
1951
1952  ASSERT_EQ(1u, resolver->pending_requests().size());
1953  EXPECT_EQ(GURL("http://www.google.com"),
1954            resolver->pending_requests()[0]->url());
1955
1956  // Complete the pending request.
1957  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
1958  resolver->pending_requests()[0]->CompleteNow(OK);
1959
1960  EXPECT_EQ(OK, callback2.WaitForResult());
1961  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1962}
1963
1964// Delete the ProxyService while InitProxyResolver has an outstanding
1965// request to the script fetcher. When run under valgrind, should not
1966// have any memory errors (used to be that the ProxyScriptFetcher was
1967// being deleted prior to the InitProxyResolver).
1968TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) {
1969  ProxyConfig config =
1970    ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
1971
1972  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1973  MockAsyncProxyResolverExpectsBytes* resolver =
1974      new MockAsyncProxyResolverExpectsBytes;
1975  ProxyService service(config_service, resolver, NULL);
1976
1977  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1978  service.SetProxyScriptFetchers(fetcher,
1979                                 new DoNothingDhcpProxyScriptFetcher());
1980
1981  // Start 1 request.
1982
1983  ProxyInfo info1;
1984  TestCompletionCallback callback1;
1985  int rv = service.ResolveProxy(GURL("http://www.google.com"), &info1,
1986                                callback1.callback(), NULL, BoundNetLog());
1987  EXPECT_EQ(ERR_IO_PENDING, rv);
1988
1989  // Check that nothing has been sent to the proxy resolver yet.
1990  ASSERT_EQ(0u, resolver->pending_requests().size());
1991
1992  // InitProxyResolver should have issued a request to the ProxyScriptFetcher
1993  // and be waiting on that to complete.
1994  EXPECT_TRUE(fetcher->has_pending_request());
1995  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1996}
1997
1998// Delete the ProxyService while InitProxyResolver has an outstanding
1999// request to the proxy resolver. When run under valgrind, should not
2000// have any memory errors (used to be that the ProxyResolver was
2001// being deleted prior to the InitProxyResolver).
2002TEST_F(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingSet) {
2003  MockProxyConfigService* config_service =
2004      new MockProxyConfigService("http://foopy/proxy.pac");
2005
2006  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
2007
2008  ProxyService service(config_service, resolver, NULL);
2009
2010  GURL url("http://www.google.com/");
2011
2012  ProxyInfo info;
2013  TestCompletionCallback callback;
2014  int rv = service.ResolveProxy(
2015      url, &info, callback.callback(), NULL, BoundNetLog());
2016  EXPECT_EQ(ERR_IO_PENDING, rv);
2017
2018  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
2019            resolver->pending_set_pac_script_request()->script_data()->url());
2020}
2021
2022TEST_F(ProxyServiceTest, ResetProxyConfigService) {
2023  ProxyConfig config1;
2024  config1.proxy_rules().ParseFromString("foopy1:8080");
2025  config1.set_auto_detect(false);
2026  ProxyService service(
2027      new MockProxyConfigService(config1),
2028      new MockAsyncProxyResolverExpectsBytes, NULL);
2029
2030  ProxyInfo info;
2031  TestCompletionCallback callback1;
2032  int rv = service.ResolveProxy(GURL("http://request1"), &info,
2033                                callback1.callback(), NULL, BoundNetLog());
2034  EXPECT_EQ(OK, rv);
2035  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
2036
2037  ProxyConfig config2;
2038  config2.proxy_rules().ParseFromString("foopy2:8080");
2039  config2.set_auto_detect(false);
2040  service.ResetConfigService(new MockProxyConfigService(config2));
2041  TestCompletionCallback callback2;
2042  rv = service.ResolveProxy(GURL("http://request2"), &info,
2043                            callback2.callback(), NULL, BoundNetLog());
2044  EXPECT_EQ(OK, rv);
2045  EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
2046}
2047
2048// Test that when going from a configuration that required PAC to one
2049// that does NOT, we unset the variable |should_use_proxy_resolver_|.
2050TEST_F(ProxyServiceTest, UpdateConfigFromPACToDirect) {
2051  ProxyConfig config = ProxyConfig::CreateAutoDetect();
2052
2053  MockProxyConfigService* config_service = new MockProxyConfigService(config);
2054  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
2055  ProxyService service(config_service, resolver, NULL);
2056
2057  // Start 1 request.
2058
2059  ProxyInfo info1;
2060  TestCompletionCallback callback1;
2061  int rv = service.ResolveProxy(GURL("http://www.google.com"), &info1,
2062                                callback1.callback(), NULL, BoundNetLog());
2063  EXPECT_EQ(ERR_IO_PENDING, rv);
2064
2065  // Check that nothing has been sent to the proxy resolver yet.
2066  ASSERT_EQ(0u, resolver->pending_requests().size());
2067
2068  // Successfully set the autodetect script.
2069  EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT,
2070            resolver->pending_set_pac_script_request()->script_data()->type());
2071  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2072
2073  // Complete the pending request.
2074  ASSERT_EQ(1u, resolver->pending_requests().size());
2075  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
2076  resolver->pending_requests()[0]->CompleteNow(OK);
2077
2078  // Verify that request ran as expected.
2079  EXPECT_EQ(OK, callback1.WaitForResult());
2080  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
2081
2082  // Force the ProxyService to pull down a new proxy configuration.
2083  // (Even though the configuration isn't old/bad).
2084  //
2085  // This new configuration no longer has auto_detect set, so
2086  // requests should complete synchronously now as direct-connect.
2087  config_service->SetConfig(ProxyConfig::CreateDirect());
2088
2089  // Start another request -- the effective configuration has changed.
2090  ProxyInfo info2;
2091  TestCompletionCallback callback2;
2092  rv = service.ResolveProxy(GURL("http://www.google.com"), &info2,
2093                            callback2.callback(), NULL, BoundNetLog());
2094  EXPECT_EQ(OK, rv);
2095
2096  EXPECT_TRUE(info2.is_direct());
2097}
2098
2099TEST_F(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
2100  MockProxyConfigService* config_service =
2101      new MockProxyConfigService("http://foopy/proxy.pac");
2102
2103  MockAsyncProxyResolverExpectsBytes* resolver =
2104      new MockAsyncProxyResolverExpectsBytes;
2105
2106  CapturingNetLog log;
2107
2108  ProxyService service(config_service, resolver, &log);
2109
2110  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
2111  service.SetProxyScriptFetchers(fetcher,
2112                                 new DoNothingDhcpProxyScriptFetcher());
2113
2114  // Disable the "wait after IP address changes" hack, so this unit-test can
2115  // complete quickly.
2116  service.set_stall_proxy_auto_config_delay(base::TimeDelta());
2117
2118  // Start 1 request.
2119
2120  ProxyInfo info1;
2121  TestCompletionCallback callback1;
2122  int rv = service.ResolveProxy(GURL("http://request1"), &info1,
2123                                callback1.callback(), NULL, BoundNetLog());
2124  EXPECT_EQ(ERR_IO_PENDING, rv);
2125
2126  // The first request should have triggered initial download of PAC script.
2127  EXPECT_TRUE(fetcher->has_pending_request());
2128  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2129
2130  // Nothing has been sent to the resolver yet.
2131  EXPECT_TRUE(resolver->pending_requests().empty());
2132
2133  // At this point the ProxyService should be waiting for the
2134  // ProxyScriptFetcher to invoke its completion callback, notifying it of
2135  // PAC script download completion.
2136  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2137
2138  // Now that the PAC script is downloaded, the request will have been sent to
2139  // the proxy resolver.
2140  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
2141            resolver->pending_set_pac_script_request()->script_data()->utf16());
2142  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2143
2144  ASSERT_EQ(1u, resolver->pending_requests().size());
2145  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
2146
2147  // Complete the pending request.
2148  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
2149  resolver->pending_requests()[0]->CompleteNow(OK);
2150
2151  // Wait for completion callback, and verify that the request ran as expected.
2152  EXPECT_EQ(OK, callback1.WaitForResult());
2153  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
2154
2155  // Now simluate a change in the network. The ProxyConfigService is still
2156  // going to return the same PAC URL as before, but this URL needs to be
2157  // refetched on the new network.
2158  NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
2159  base::MessageLoop::current()->RunUntilIdle();  // Notification happens async.
2160
2161  // Start a second request.
2162  ProxyInfo info2;
2163  TestCompletionCallback callback2;
2164  rv = service.ResolveProxy(GURL("http://request2"), &info2,
2165                            callback2.callback(), NULL, BoundNetLog());
2166  EXPECT_EQ(ERR_IO_PENDING, rv);
2167
2168  // This second request should have triggered the re-download of the PAC
2169  // script (since we marked the network as having changed).
2170  EXPECT_TRUE(fetcher->has_pending_request());
2171  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2172
2173  // Nothing has been sent to the resolver yet.
2174  EXPECT_TRUE(resolver->pending_requests().empty());
2175
2176  // Simulate the PAC script fetch as having completed (this time with
2177  // different data).
2178  fetcher->NotifyFetchCompletion(OK, kValidPacScript2);
2179
2180  // Now that the PAC script is downloaded, the second request will have been
2181  // sent to the proxy resolver.
2182  EXPECT_EQ(ASCIIToUTF16(kValidPacScript2),
2183            resolver->pending_set_pac_script_request()->script_data()->utf16());
2184  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2185
2186  ASSERT_EQ(1u, resolver->pending_requests().size());
2187  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
2188
2189  // Complete the pending second request.
2190  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
2191  resolver->pending_requests()[0]->CompleteNow(OK);
2192
2193  // Wait for completion callback, and verify that the request ran as expected.
2194  EXPECT_EQ(OK, callback2.WaitForResult());
2195  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
2196
2197  // Check that the expected events were output to the log stream. In particular
2198  // PROXY_CONFIG_CHANGED should have only been emitted once (for the initial
2199  // setup), and NOT a second time when the IP address changed.
2200  CapturingNetLog::CapturedEntryList entries;
2201  log.GetEntries(&entries);
2202
2203  EXPECT_TRUE(LogContainsEntryWithType(entries, 0,
2204                                       NetLog::TYPE_PROXY_CONFIG_CHANGED));
2205  ASSERT_EQ(9u, entries.size());
2206  for (size_t i = 1; i < entries.size(); ++i)
2207    EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, entries[i].type);
2208}
2209
2210// This test verifies that the PAC script specified by the settings is
2211// periodically polled for changes. Specifically, if the initial fetch fails due
2212// to a network error, we will eventually re-configure the service to use the
2213// script once it becomes available.
2214TEST_F(ProxyServiceTest, PACScriptRefetchAfterFailure) {
2215  // Change the retry policy to wait a mere 1 ms before retrying, so the test
2216  // runs quickly.
2217  ImmediatePollPolicy poll_policy;
2218  ProxyService::set_pac_script_poll_policy(&poll_policy);
2219
2220  MockProxyConfigService* config_service =
2221      new MockProxyConfigService("http://foopy/proxy.pac");
2222
2223  MockAsyncProxyResolverExpectsBytes* resolver =
2224      new MockAsyncProxyResolverExpectsBytes;
2225
2226  ProxyService service(config_service, resolver, NULL);
2227
2228  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
2229  service.SetProxyScriptFetchers(fetcher,
2230                                 new DoNothingDhcpProxyScriptFetcher());
2231
2232  // Start 1 request.
2233
2234  ProxyInfo info1;
2235  TestCompletionCallback callback1;
2236  int rv = service.ResolveProxy(
2237      GURL("http://request1"), &info1, callback1.callback(),
2238      NULL, BoundNetLog());
2239  EXPECT_EQ(ERR_IO_PENDING, rv);
2240
2241  // The first request should have triggered initial download of PAC script.
2242  EXPECT_TRUE(fetcher->has_pending_request());
2243  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2244
2245  // Nothing has been sent to the resolver yet.
2246  EXPECT_TRUE(resolver->pending_requests().empty());
2247
2248  // At this point the ProxyService should be waiting for the
2249  // ProxyScriptFetcher to invoke its completion callback, notifying it of
2250  // PAC script download completion.
2251  //
2252  // We simulate a failed download attempt, the proxy service should now
2253  // fall-back to DIRECT connections.
2254  fetcher->NotifyFetchCompletion(ERR_FAILED, std::string());
2255
2256  ASSERT_TRUE(resolver->pending_requests().empty());
2257
2258  // Wait for completion callback, and verify it used DIRECT.
2259  EXPECT_EQ(OK, callback1.WaitForResult());
2260  EXPECT_TRUE(info1.is_direct());
2261
2262  // At this point we have initialized the proxy service using a PAC script,
2263  // however it failed and fell-back to DIRECT.
2264  //
2265  // A background task to periodically re-check the PAC script for validity will
2266  // have been started. We will now wait for the next download attempt to start.
2267  //
2268  // Note that we shouldn't have to wait long here, since our test enables a
2269  // special unit-test mode.
2270  fetcher->WaitUntilFetch();
2271
2272  ASSERT_TRUE(resolver->pending_requests().empty());
2273
2274  // Make sure that our background checker is trying to download the expected
2275  // PAC script (same one as before). This time we will simulate a successful
2276  // download of the script.
2277  EXPECT_TRUE(fetcher->has_pending_request());
2278  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2279  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2280
2281  base::MessageLoop::current()->RunUntilIdle();
2282
2283  // Now that the PAC script is downloaded, it should be used to initialize the
2284  // ProxyResolver. Simulate a successful parse.
2285  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
2286            resolver->pending_set_pac_script_request()->script_data()->utf16());
2287  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2288
2289  // At this point the ProxyService should have re-configured itself to use the
2290  // PAC script (thereby recovering from the initial fetch failure). We will
2291  // verify that the next Resolve request uses the resolver rather than
2292  // DIRECT.
2293
2294  // Start a second request.
2295  ProxyInfo info2;
2296  TestCompletionCallback callback2;
2297  rv = service.ResolveProxy(
2298      GURL("http://request2"), &info2, callback2.callback(), NULL,
2299      BoundNetLog());
2300  EXPECT_EQ(ERR_IO_PENDING, rv);
2301
2302  // Check that it was sent to the resolver.
2303  ASSERT_EQ(1u, resolver->pending_requests().size());
2304  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
2305
2306  // Complete the pending second request.
2307  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
2308  resolver->pending_requests()[0]->CompleteNow(OK);
2309
2310  // Wait for completion callback, and verify that the request ran as expected.
2311  EXPECT_EQ(OK, callback2.WaitForResult());
2312  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
2313}
2314
2315// This test verifies that the PAC script specified by the settings is
2316// periodically polled for changes. Specifically, if the initial fetch succeeds,
2317// however at a later time its *contents* change, we will eventually
2318// re-configure the service to use the new script.
2319TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentChange) {
2320  // Change the retry policy to wait a mere 1 ms before retrying, so the test
2321  // runs quickly.
2322  ImmediatePollPolicy poll_policy;
2323  ProxyService::set_pac_script_poll_policy(&poll_policy);
2324
2325  MockProxyConfigService* config_service =
2326      new MockProxyConfigService("http://foopy/proxy.pac");
2327
2328  MockAsyncProxyResolverExpectsBytes* resolver =
2329      new MockAsyncProxyResolverExpectsBytes;
2330
2331  ProxyService service(config_service, resolver, NULL);
2332
2333  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
2334  service.SetProxyScriptFetchers(fetcher,
2335                                 new DoNothingDhcpProxyScriptFetcher());
2336
2337  // Start 1 request.
2338
2339  ProxyInfo info1;
2340  TestCompletionCallback callback1;
2341  int rv = service.ResolveProxy(
2342      GURL("http://request1"), &info1, callback1.callback(), NULL,
2343      BoundNetLog());
2344  EXPECT_EQ(ERR_IO_PENDING, rv);
2345
2346  // The first request should have triggered initial download of PAC script.
2347  EXPECT_TRUE(fetcher->has_pending_request());
2348  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2349
2350  // Nothing has been sent to the resolver yet.
2351  EXPECT_TRUE(resolver->pending_requests().empty());
2352
2353  // At this point the ProxyService should be waiting for the
2354  // ProxyScriptFetcher to invoke its completion callback, notifying it of
2355  // PAC script download completion.
2356  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2357
2358  // Now that the PAC script is downloaded, the request will have been sent to
2359  // the proxy resolver.
2360  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
2361            resolver->pending_set_pac_script_request()->script_data()->utf16());
2362  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2363
2364  ASSERT_EQ(1u, resolver->pending_requests().size());
2365  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
2366
2367  // Complete the pending request.
2368  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
2369  resolver->pending_requests()[0]->CompleteNow(OK);
2370
2371  // Wait for completion callback, and verify that the request ran as expected.
2372  EXPECT_EQ(OK, callback1.WaitForResult());
2373  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
2374
2375  // At this point we have initialized the proxy service using a PAC script.
2376  //
2377  // A background task to periodically re-check the PAC script for validity will
2378  // have been started. We will now wait for the next download attempt to start.
2379  //
2380  // Note that we shouldn't have to wait long here, since our test enables a
2381  // special unit-test mode.
2382  fetcher->WaitUntilFetch();
2383
2384  ASSERT_TRUE(resolver->pending_requests().empty());
2385
2386  // Make sure that our background checker is trying to download the expected
2387  // PAC script (same one as before). This time we will simulate a successful
2388  // download of a DIFFERENT script.
2389  EXPECT_TRUE(fetcher->has_pending_request());
2390  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2391  fetcher->NotifyFetchCompletion(OK, kValidPacScript2);
2392
2393  base::MessageLoop::current()->RunUntilIdle();
2394
2395  // Now that the PAC script is downloaded, it should be used to initialize the
2396  // ProxyResolver. Simulate a successful parse.
2397  EXPECT_EQ(ASCIIToUTF16(kValidPacScript2),
2398            resolver->pending_set_pac_script_request()->script_data()->utf16());
2399  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2400
2401  // At this point the ProxyService should have re-configured itself to use the
2402  // new PAC script.
2403
2404  // Start a second request.
2405  ProxyInfo info2;
2406  TestCompletionCallback callback2;
2407  rv = service.ResolveProxy(
2408      GURL("http://request2"), &info2, callback2.callback(), NULL,
2409      BoundNetLog());
2410  EXPECT_EQ(ERR_IO_PENDING, rv);
2411
2412  // Check that it was sent to the resolver.
2413  ASSERT_EQ(1u, resolver->pending_requests().size());
2414  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
2415
2416  // Complete the pending second request.
2417  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
2418  resolver->pending_requests()[0]->CompleteNow(OK);
2419
2420  // Wait for completion callback, and verify that the request ran as expected.
2421  EXPECT_EQ(OK, callback2.WaitForResult());
2422  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
2423}
2424
2425// This test verifies that the PAC script specified by the settings is
2426// periodically polled for changes. Specifically, if the initial fetch succeeds
2427// and so does the next poll, however the contents of the downloaded script
2428// have NOT changed, then we do not bother to re-initialize the proxy resolver.
2429TEST_F(ProxyServiceTest, PACScriptRefetchAfterContentUnchanged) {
2430  // Change the retry policy to wait a mere 1 ms before retrying, so the test
2431  // runs quickly.
2432  ImmediatePollPolicy poll_policy;
2433  ProxyService::set_pac_script_poll_policy(&poll_policy);
2434
2435  MockProxyConfigService* config_service =
2436      new MockProxyConfigService("http://foopy/proxy.pac");
2437
2438  MockAsyncProxyResolverExpectsBytes* resolver =
2439      new MockAsyncProxyResolverExpectsBytes;
2440
2441  ProxyService service(config_service, resolver, NULL);
2442
2443  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
2444  service.SetProxyScriptFetchers(fetcher,
2445                                 new DoNothingDhcpProxyScriptFetcher());
2446
2447  // Start 1 request.
2448
2449  ProxyInfo info1;
2450  TestCompletionCallback callback1;
2451  int rv = service.ResolveProxy(
2452      GURL("http://request1"), &info1, callback1.callback(), NULL,
2453      BoundNetLog());
2454  EXPECT_EQ(ERR_IO_PENDING, rv);
2455
2456  // The first request should have triggered initial download of PAC script.
2457  EXPECT_TRUE(fetcher->has_pending_request());
2458  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2459
2460  // Nothing has been sent to the resolver yet.
2461  EXPECT_TRUE(resolver->pending_requests().empty());
2462
2463  // At this point the ProxyService should be waiting for the
2464  // ProxyScriptFetcher to invoke its completion callback, notifying it of
2465  // PAC script download completion.
2466  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2467
2468  // Now that the PAC script is downloaded, the request will have been sent to
2469  // the proxy resolver.
2470  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
2471            resolver->pending_set_pac_script_request()->script_data()->utf16());
2472  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2473
2474  ASSERT_EQ(1u, resolver->pending_requests().size());
2475  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
2476
2477  // Complete the pending request.
2478  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
2479  resolver->pending_requests()[0]->CompleteNow(OK);
2480
2481  // Wait for completion callback, and verify that the request ran as expected.
2482  EXPECT_EQ(OK, callback1.WaitForResult());
2483  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
2484
2485  // At this point we have initialized the proxy service using a PAC script.
2486  //
2487  // A background task to periodically re-check the PAC script for validity will
2488  // have been started. We will now wait for the next download attempt to start.
2489  //
2490  // Note that we shouldn't have to wait long here, since our test enables a
2491  // special unit-test mode.
2492  fetcher->WaitUntilFetch();
2493
2494  ASSERT_TRUE(resolver->pending_requests().empty());
2495
2496  // Make sure that our background checker is trying to download the expected
2497  // PAC script (same one as before). We will simulate the same response as
2498  // last time (i.e. the script is unchanged).
2499  EXPECT_TRUE(fetcher->has_pending_request());
2500  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2501  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2502
2503  base::MessageLoop::current()->RunUntilIdle();
2504
2505  ASSERT_FALSE(resolver->has_pending_set_pac_script_request());
2506
2507  // At this point the ProxyService is still running the same PAC script as
2508  // before.
2509
2510  // Start a second request.
2511  ProxyInfo info2;
2512  TestCompletionCallback callback2;
2513  rv = service.ResolveProxy(
2514      GURL("http://request2"), &info2, callback2.callback(), NULL,
2515      BoundNetLog());
2516  EXPECT_EQ(ERR_IO_PENDING, rv);
2517
2518  // Check that it was sent to the resolver.
2519  ASSERT_EQ(1u, resolver->pending_requests().size());
2520  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
2521
2522  // Complete the pending second request.
2523  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
2524  resolver->pending_requests()[0]->CompleteNow(OK);
2525
2526  // Wait for completion callback, and verify that the request ran as expected.
2527  EXPECT_EQ(OK, callback2.WaitForResult());
2528  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
2529}
2530
2531// This test verifies that the PAC script specified by the settings is
2532// periodically polled for changes. Specifically, if the initial fetch succeeds,
2533// however at a later time it starts to fail, we should re-configure the
2534// ProxyService to stop using that PAC script.
2535TEST_F(ProxyServiceTest, PACScriptRefetchAfterSuccess) {
2536  // Change the retry policy to wait a mere 1 ms before retrying, so the test
2537  // runs quickly.
2538  ImmediatePollPolicy poll_policy;
2539  ProxyService::set_pac_script_poll_policy(&poll_policy);
2540
2541  MockProxyConfigService* config_service =
2542      new MockProxyConfigService("http://foopy/proxy.pac");
2543
2544  MockAsyncProxyResolverExpectsBytes* resolver =
2545      new MockAsyncProxyResolverExpectsBytes;
2546
2547  ProxyService service(config_service, resolver, NULL);
2548
2549  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
2550  service.SetProxyScriptFetchers(fetcher,
2551                                 new DoNothingDhcpProxyScriptFetcher());
2552
2553  // Start 1 request.
2554
2555  ProxyInfo info1;
2556  TestCompletionCallback callback1;
2557  int rv = service.ResolveProxy(
2558      GURL("http://request1"), &info1, callback1.callback(), NULL,
2559      BoundNetLog());
2560  EXPECT_EQ(ERR_IO_PENDING, rv);
2561
2562  // The first request should have triggered initial download of PAC script.
2563  EXPECT_TRUE(fetcher->has_pending_request());
2564  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2565
2566  // Nothing has been sent to the resolver yet.
2567  EXPECT_TRUE(resolver->pending_requests().empty());
2568
2569  // At this point the ProxyService should be waiting for the
2570  // ProxyScriptFetcher to invoke its completion callback, notifying it of
2571  // PAC script download completion.
2572  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2573
2574  // Now that the PAC script is downloaded, the request will have been sent to
2575  // the proxy resolver.
2576  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
2577            resolver->pending_set_pac_script_request()->script_data()->utf16());
2578  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2579
2580  ASSERT_EQ(1u, resolver->pending_requests().size());
2581  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
2582
2583  // Complete the pending request.
2584  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
2585  resolver->pending_requests()[0]->CompleteNow(OK);
2586
2587  // Wait for completion callback, and verify that the request ran as expected.
2588  EXPECT_EQ(OK, callback1.WaitForResult());
2589  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
2590
2591  // At this point we have initialized the proxy service using a PAC script.
2592  //
2593  // A background task to periodically re-check the PAC script for validity will
2594  // have been started. We will now wait for the next download attempt to start.
2595  //
2596  // Note that we shouldn't have to wait long here, since our test enables a
2597  // special unit-test mode.
2598  fetcher->WaitUntilFetch();
2599
2600  ASSERT_TRUE(resolver->pending_requests().empty());
2601
2602  // Make sure that our background checker is trying to download the expected
2603  // PAC script (same one as before). This time we will simulate a failure
2604  // to download the script.
2605  EXPECT_TRUE(fetcher->has_pending_request());
2606  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2607  fetcher->NotifyFetchCompletion(ERR_FAILED, std::string());
2608
2609  base::MessageLoop::current()->RunUntilIdle();
2610
2611  // At this point the ProxyService should have re-configured itself to use
2612  // DIRECT connections rather than the given proxy resolver.
2613
2614  // Start a second request.
2615  ProxyInfo info2;
2616  TestCompletionCallback callback2;
2617  rv = service.ResolveProxy(
2618      GURL("http://request2"), &info2, callback2.callback(), NULL,
2619      BoundNetLog());
2620  EXPECT_EQ(OK, rv);
2621  EXPECT_TRUE(info2.is_direct());
2622}
2623
2624// Tests that the code which decides at what times to poll the PAC
2625// script follows the expected policy.
2626TEST_F(ProxyServiceTest, PACScriptPollingPolicy) {
2627  // Retrieve the internal polling policy implementation used by ProxyService.
2628  scoped_ptr<ProxyService::PacPollPolicy> policy =
2629      ProxyService::CreateDefaultPacPollPolicy();
2630
2631  int error;
2632  ProxyService::PacPollPolicy::Mode mode;
2633  const base::TimeDelta initial_delay = base::TimeDelta::FromMilliseconds(-1);
2634  base::TimeDelta delay = initial_delay;
2635
2636  // --------------------------------------------------
2637  // Test the poll sequence in response to a failure.
2638  // --------------------------------------------------
2639  error = ERR_NAME_NOT_RESOLVED;
2640
2641  // Poll #0
2642  mode = policy->GetNextDelay(error, initial_delay, &delay);
2643  EXPECT_EQ(8, delay.InSeconds());
2644  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_USE_TIMER, mode);
2645
2646  // Poll #1
2647  mode = policy->GetNextDelay(error, delay, &delay);
2648  EXPECT_EQ(32, delay.InSeconds());
2649  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2650
2651  // Poll #2
2652  mode = policy->GetNextDelay(error, delay, &delay);
2653  EXPECT_EQ(120, delay.InSeconds());
2654  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2655
2656  // Poll #3
2657  mode = policy->GetNextDelay(error, delay, &delay);
2658  EXPECT_EQ(14400, delay.InSeconds());
2659  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2660
2661  // Poll #4
2662  mode = policy->GetNextDelay(error, delay, &delay);
2663  EXPECT_EQ(14400, delay.InSeconds());
2664  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2665
2666  // --------------------------------------------------
2667  // Test the poll sequence in response to a success.
2668  // --------------------------------------------------
2669  error = OK;
2670
2671  // Poll #0
2672  mode = policy->GetNextDelay(error, initial_delay, &delay);
2673  EXPECT_EQ(43200, delay.InSeconds());
2674  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2675
2676  // Poll #1
2677  mode = policy->GetNextDelay(error, delay, &delay);
2678  EXPECT_EQ(43200, delay.InSeconds());
2679  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2680
2681  // Poll #2
2682  mode = policy->GetNextDelay(error, delay, &delay);
2683  EXPECT_EQ(43200, delay.InSeconds());
2684  EXPECT_EQ(ProxyService::PacPollPolicy::MODE_START_AFTER_ACTIVITY, mode);
2685}
2686
2687// This tests the polling of the PAC script. Specifically, it tests that
2688// polling occurs in response to user activity.
2689TEST_F(ProxyServiceTest, PACScriptRefetchAfterActivity) {
2690  ImmediateAfterActivityPollPolicy poll_policy;
2691  ProxyService::set_pac_script_poll_policy(&poll_policy);
2692
2693  MockProxyConfigService* config_service =
2694      new MockProxyConfigService("http://foopy/proxy.pac");
2695
2696  MockAsyncProxyResolverExpectsBytes* resolver =
2697      new MockAsyncProxyResolverExpectsBytes;
2698
2699  ProxyService service(config_service, resolver, NULL);
2700
2701  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
2702  service.SetProxyScriptFetchers(fetcher,
2703                                 new DoNothingDhcpProxyScriptFetcher());
2704
2705  // Start 1 request.
2706
2707  ProxyInfo info1;
2708  TestCompletionCallback callback1;
2709  int rv = service.ResolveProxy(
2710      GURL("http://request1"), &info1, callback1.callback(), NULL,
2711      BoundNetLog());
2712  EXPECT_EQ(ERR_IO_PENDING, rv);
2713
2714  // The first request should have triggered initial download of PAC script.
2715  EXPECT_TRUE(fetcher->has_pending_request());
2716  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2717
2718  // Nothing has been sent to the resolver yet.
2719  EXPECT_TRUE(resolver->pending_requests().empty());
2720
2721  // At this point the ProxyService should be waiting for the
2722  // ProxyScriptFetcher to invoke its completion callback, notifying it of
2723  // PAC script download completion.
2724  fetcher->NotifyFetchCompletion(OK, kValidPacScript1);
2725
2726  // Now that the PAC script is downloaded, the request will have been sent to
2727  // the proxy resolver.
2728  EXPECT_EQ(ASCIIToUTF16(kValidPacScript1),
2729            resolver->pending_set_pac_script_request()->script_data()->utf16());
2730  resolver->pending_set_pac_script_request()->CompleteNow(OK);
2731
2732  ASSERT_EQ(1u, resolver->pending_requests().size());
2733  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
2734
2735  // Complete the pending request.
2736  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
2737  resolver->pending_requests()[0]->CompleteNow(OK);
2738
2739  // Wait for completion callback, and verify that the request ran as expected.
2740  EXPECT_EQ(OK, callback1.WaitForResult());
2741  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
2742
2743  // At this point we have initialized the proxy service using a PAC script.
2744  // Our PAC poller is set to update ONLY in response to network activity,
2745  // (i.e. another call to ResolveProxy()).
2746
2747  ASSERT_FALSE(fetcher->has_pending_request());
2748  ASSERT_TRUE(resolver->pending_requests().empty());
2749
2750  // Start a second request.
2751  ProxyInfo info2;
2752  TestCompletionCallback callback2;
2753  rv = service.ResolveProxy(
2754      GURL("http://request2"), &info2, callback2.callback(), NULL,
2755      BoundNetLog());
2756  EXPECT_EQ(ERR_IO_PENDING, rv);
2757
2758  // This request should have sent work to the resolver; complete it.
2759  ASSERT_EQ(1u, resolver->pending_requests().size());
2760  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
2761  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
2762  resolver->pending_requests()[0]->CompleteNow(OK);
2763
2764  EXPECT_EQ(OK, callback2.WaitForResult());
2765  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
2766
2767  // In response to getting that resolve request, the poller should have
2768  // started the next poll, and made it as far as to request the download.
2769
2770  EXPECT_TRUE(fetcher->has_pending_request());
2771  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
2772
2773  // This time we will fail the download, to simulate a PAC script change.
2774  fetcher->NotifyFetchCompletion(ERR_FAILED, std::string());
2775
2776  // Drain the message loop, so ProxyService is notified of the change
2777  // and has a chance to re-configure itself.
2778  base::MessageLoop::current()->RunUntilIdle();
2779
2780  // Start a third request -- this time we expect to get a direct connection
2781  // since the PAC script poller experienced a failure.
2782  ProxyInfo info3;
2783  TestCompletionCallback callback3;
2784  rv = service.ResolveProxy(
2785      GURL("http://request3"), &info3, callback3.callback(), NULL,
2786      BoundNetLog());
2787  EXPECT_EQ(OK, rv);
2788  EXPECT_TRUE(info3.is_direct());
2789}
2790
2791}  // namespace net
2792