1// Copyright (c) 2011 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/string_util.h"
12#include "base/utf_string_conversions.h"
13#include "googleurl/src/gurl.h"
14#include "net/base/net_errors.h"
15#include "net/base/net_log.h"
16#include "net/base/net_log_unittest.h"
17#include "net/base/test_completion_callback.h"
18#include "net/proxy/mock_proxy_resolver.h"
19#include "net/proxy/proxy_config_service.h"
20#include "net/proxy/proxy_resolver.h"
21#include "net/proxy/proxy_script_fetcher.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24// TODO(eroman): Write a test which exercises
25//              ProxyService::SuspendAllPendingRequests().
26namespace net {
27namespace {
28
29class MockProxyConfigService: public ProxyConfigService {
30 public:
31  explicit MockProxyConfigService(const ProxyConfig& config)
32      : availability_(CONFIG_VALID),
33        config_(config) {
34  }
35
36  explicit MockProxyConfigService(const std::string& pac_url)
37      : availability_(CONFIG_VALID),
38        config_(ProxyConfig::CreateFromCustomPacURL(GURL(pac_url))) {
39  }
40
41  virtual void AddObserver(Observer* observer) {
42    observers_.AddObserver(observer);
43  }
44
45  virtual void RemoveObserver(Observer* observer) {
46    observers_.RemoveObserver(observer);
47  }
48
49  virtual ConfigAvailability GetLatestProxyConfig(ProxyConfig* results) {
50    if (availability_ == CONFIG_VALID)
51      *results = config_;
52    return availability_;
53  }
54
55  void SetConfig(const ProxyConfig& config) {
56    availability_ = CONFIG_VALID;
57    config_ = config;
58    FOR_EACH_OBSERVER(Observer, observers_,
59                      OnProxyConfigChanged(config_, availability_));
60  }
61
62 private:
63  ConfigAvailability availability_;
64  ProxyConfig config_;
65  ObserverList<Observer, true> observers_;
66};
67
68}  // namespace
69
70// A mock ProxyScriptFetcher. No result will be returned to the fetch client
71// until we call NotifyFetchCompletion() to set the results.
72class MockProxyScriptFetcher : public ProxyScriptFetcher {
73 public:
74  MockProxyScriptFetcher()
75      : pending_request_callback_(NULL), pending_request_text_(NULL) {
76  }
77
78  // ProxyScriptFetcher implementation.
79  virtual int Fetch(const GURL& url,
80                    string16* text,
81                    CompletionCallback* callback) {
82    DCHECK(!has_pending_request());
83
84    // Save the caller's information, and have them wait.
85    pending_request_url_ = url;
86    pending_request_callback_ = callback;
87    pending_request_text_ = text;
88    return ERR_IO_PENDING;
89  }
90
91  void NotifyFetchCompletion(int result, const std::string& ascii_text) {
92    DCHECK(has_pending_request());
93    *pending_request_text_ = ASCIIToUTF16(ascii_text);
94    CompletionCallback* callback = pending_request_callback_;
95    pending_request_callback_ = NULL;
96    callback->Run(result);
97  }
98
99  virtual void Cancel() {}
100
101  virtual URLRequestContext* GetRequestContext() { return NULL; }
102
103  const GURL& pending_request_url() const {
104    return pending_request_url_;
105  }
106
107  bool has_pending_request() const {
108    return pending_request_callback_ != NULL;
109  }
110
111 private:
112  GURL pending_request_url_;
113  CompletionCallback* pending_request_callback_;
114  string16* pending_request_text_;
115};
116
117TEST(ProxyServiceTest, Direct) {
118  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
119  scoped_refptr<ProxyService> service(
120      new ProxyService(new MockProxyConfigService(
121          ProxyConfig::CreateDirect()), resolver, NULL));
122
123  GURL url("http://www.google.com/");
124
125  ProxyInfo info;
126  TestCompletionCallback callback;
127  CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
128  int rv = service->ResolveProxy(url, &info, &callback, NULL, log.bound());
129  EXPECT_EQ(OK, rv);
130  EXPECT_TRUE(resolver->pending_requests().empty());
131
132  EXPECT_TRUE(info.is_direct());
133
134  // Check the NetLog was filled correctly.
135  CapturingNetLog::EntryList entries;
136  log.GetEntries(&entries);
137
138  EXPECT_EQ(3u, entries.size());
139  EXPECT_TRUE(LogContainsBeginEvent(
140      entries, 0, NetLog::TYPE_PROXY_SERVICE));
141  EXPECT_TRUE(LogContainsEvent(
142      entries, 1, NetLog::TYPE_PROXY_SERVICE_RESOLVED_PROXY_LIST,
143      NetLog::PHASE_NONE));
144  EXPECT_TRUE(LogContainsEndEvent(
145      entries, 2, NetLog::TYPE_PROXY_SERVICE));
146}
147
148TEST(ProxyServiceTest, PAC) {
149  MockProxyConfigService* config_service =
150      new MockProxyConfigService("http://foopy/proxy.pac");
151
152  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
153
154  scoped_refptr<ProxyService> service(
155      new ProxyService(config_service, resolver, NULL));
156
157  GURL url("http://www.google.com/");
158
159  ProxyInfo info;
160  TestCompletionCallback callback;
161  CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
162
163  int rv = service->ResolveProxy(url, &info, &callback, NULL, log.bound());
164  EXPECT_EQ(ERR_IO_PENDING, rv);
165
166  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
167            resolver->pending_set_pac_script_request()->script_data()->url());
168  resolver->pending_set_pac_script_request()->CompleteNow(OK);
169
170  ASSERT_EQ(1u, resolver->pending_requests().size());
171  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
172
173  // Set the result in proxy resolver.
174  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy");
175  resolver->pending_requests()[0]->CompleteNow(OK);
176
177  EXPECT_EQ(OK, callback.WaitForResult());
178  EXPECT_FALSE(info.is_direct());
179  EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
180
181  // Check the NetLog was filled correctly.
182  CapturingNetLog::EntryList entries;
183  log.GetEntries(&entries);
184
185  EXPECT_EQ(5u, entries.size());
186  EXPECT_TRUE(LogContainsBeginEvent(
187      entries, 0, NetLog::TYPE_PROXY_SERVICE));
188  EXPECT_TRUE(LogContainsBeginEvent(
189      entries, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
190  EXPECT_TRUE(LogContainsEndEvent(
191      entries, 2, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
192  EXPECT_TRUE(LogContainsEndEvent(
193      entries, 4, NetLog::TYPE_PROXY_SERVICE));
194}
195
196// Test that the proxy resolver does not see the URL's username/password
197// or its reference section.
198TEST(ProxyServiceTest, PAC_NoIdentityOrHash) {
199  MockProxyConfigService* config_service =
200      new MockProxyConfigService("http://foopy/proxy.pac");
201
202  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
203
204  scoped_refptr<ProxyService> service(
205      new ProxyService(config_service, resolver, NULL));
206
207  GURL url("http://username:password@www.google.com/?ref#hash#hash");
208
209  ProxyInfo info;
210  TestCompletionCallback callback;
211  int rv = service->ResolveProxy(url, &info, &callback, NULL, BoundNetLog());
212  EXPECT_EQ(ERR_IO_PENDING, rv);
213
214  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
215            resolver->pending_set_pac_script_request()->script_data()->url());
216  resolver->pending_set_pac_script_request()->CompleteNow(OK);
217
218  ASSERT_EQ(1u, resolver->pending_requests().size());
219  // The URL should have been simplified, stripping the username/password/hash.
220  EXPECT_EQ(GURL("http://www.google.com/?ref"),
221                 resolver->pending_requests()[0]->url());
222
223  // We end here without ever completing the request -- destruction of
224  // ProxyService will cancel the outstanding request.
225}
226
227TEST(ProxyServiceTest, PAC_FailoverWithoutDirect) {
228  MockProxyConfigService* config_service =
229      new MockProxyConfigService("http://foopy/proxy.pac");
230  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
231
232  scoped_refptr<ProxyService> service(
233      new ProxyService(config_service, resolver, NULL));
234
235  GURL url("http://www.google.com/");
236
237  ProxyInfo info;
238  TestCompletionCallback callback1;
239  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
240  EXPECT_EQ(ERR_IO_PENDING, rv);
241
242  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
243            resolver->pending_set_pac_script_request()->script_data()->url());
244  resolver->pending_set_pac_script_request()->CompleteNow(OK);
245
246  ASSERT_EQ(1u, resolver->pending_requests().size());
247  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
248
249  // Set the result in proxy resolver.
250  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy:8080");
251  resolver->pending_requests()[0]->CompleteNow(OK);
252
253  EXPECT_EQ(OK, callback1.WaitForResult());
254  EXPECT_FALSE(info.is_direct());
255  EXPECT_EQ("foopy:8080", info.proxy_server().ToURI());
256
257  // Now, imagine that connecting to foopy:8080 fails: there is nothing
258  // left to fallback to, since our proxy list was NOT terminated by
259  // DIRECT.
260  TestCompletionCallback callback2;
261  rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
262                                          BoundNetLog());
263  // ReconsiderProxyAfterError returns error indicating nothing left.
264  EXPECT_EQ(ERR_FAILED, rv);
265  EXPECT_TRUE(info.is_empty());
266}
267
268// The proxy list could potentially contain the DIRECT fallback choice
269// in a location other than the very end of the list, and could even
270// specify it multiple times.
271//
272// This is not a typical usage, but we will obey it.
273// (If we wanted to disallow this type of input, the right place to
274// enforce it would be in parsing the PAC result string).
275//
276// This test will use the PAC result string:
277//
278//   "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20"
279//
280// For which we expect it to try DIRECT, then foobar:10, then DIRECT again,
281// then foobar:20, and then give up and error.
282//
283// The important check of this test is to make sure that DIRECT is not somehow
284// cached as being a bad proxy.
285TEST(ProxyServiceTest, PAC_FailoverAfterDirect) {
286  MockProxyConfigService* config_service =
287      new MockProxyConfigService("http://foopy/proxy.pac");
288  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
289
290  scoped_refptr<ProxyService> service(
291      new ProxyService(config_service, resolver, NULL));
292
293  GURL url("http://www.google.com/");
294
295  ProxyInfo info;
296  TestCompletionCallback callback1;
297  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
298  EXPECT_EQ(ERR_IO_PENDING, rv);
299
300  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
301            resolver->pending_set_pac_script_request()->script_data()->url());
302  resolver->pending_set_pac_script_request()->CompleteNow(OK);
303
304  ASSERT_EQ(1u, resolver->pending_requests().size());
305  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
306
307  // Set the result in proxy resolver.
308  resolver->pending_requests()[0]->results()->UsePacString(
309      "DIRECT ; PROXY foobar:10 ; DIRECT ; PROXY foobar:20");
310  resolver->pending_requests()[0]->CompleteNow(OK);
311
312  EXPECT_EQ(OK, callback1.WaitForResult());
313  EXPECT_TRUE(info.is_direct());
314
315  // Fallback 1.
316  TestCompletionCallback callback2;
317  rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
318                                          BoundNetLog());
319  EXPECT_EQ(OK, rv);
320  EXPECT_FALSE(info.is_direct());
321  EXPECT_EQ("foobar:10", info.proxy_server().ToURI());
322
323  // Fallback 2.
324  TestCompletionCallback callback3;
325  rv = service->ReconsiderProxyAfterError(url, &info, &callback3, NULL,
326                                          BoundNetLog());
327  EXPECT_EQ(OK, rv);
328  EXPECT_TRUE(info.is_direct());
329
330  // Fallback 3.
331  TestCompletionCallback callback4;
332  rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL,
333                                          BoundNetLog());
334  EXPECT_EQ(OK, rv);
335  EXPECT_FALSE(info.is_direct());
336  EXPECT_EQ("foobar:20", info.proxy_server().ToURI());
337
338  // Fallback 4 -- Nothing to fall back to!
339  TestCompletionCallback callback5;
340  rv = service->ReconsiderProxyAfterError(url, &info, &callback5, NULL,
341                                          BoundNetLog());
342  EXPECT_EQ(ERR_FAILED, rv);
343  EXPECT_TRUE(info.is_empty());
344}
345
346TEST(ProxyServiceTest, ProxyResolverFails) {
347  // Test what happens when the ProxyResolver fails. The download and setting
348  // of the PAC script have already succeeded, so this corresponds with a
349  // javascript runtime error while calling FindProxyForURL().
350
351  MockProxyConfigService* config_service =
352      new MockProxyConfigService("http://foopy/proxy.pac");
353
354  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
355
356  scoped_refptr<ProxyService> service(
357      new ProxyService(config_service, resolver, NULL));
358
359  // Start first resolve request.
360  GURL url("http://www.google.com/");
361  ProxyInfo info;
362  TestCompletionCallback callback1;
363  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
364  EXPECT_EQ(ERR_IO_PENDING, rv);
365
366  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
367            resolver->pending_set_pac_script_request()->script_data()->url());
368  resolver->pending_set_pac_script_request()->CompleteNow(OK);
369
370  ASSERT_EQ(1u, resolver->pending_requests().size());
371  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
372
373  // Fail the first resolve request in MockAsyncProxyResolver.
374  resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
375
376  // Although the proxy resolver failed the request, ProxyService implicitly
377  // falls-back to DIRECT.
378  EXPECT_EQ(OK, callback1.WaitForResult());
379  EXPECT_TRUE(info.is_direct());
380
381  // The second resolve request will try to run through the proxy resolver,
382  // regardless of whether the first request failed in it.
383  TestCompletionCallback callback2;
384  rv = service->ResolveProxy(url, &info, &callback2, NULL, BoundNetLog());
385  EXPECT_EQ(ERR_IO_PENDING, rv);
386
387  ASSERT_EQ(1u, resolver->pending_requests().size());
388  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
389
390  // This time we will have the resolver succeed (perhaps the PAC script has
391  // a dependency on the current time).
392  resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
393  resolver->pending_requests()[0]->CompleteNow(OK);
394
395  EXPECT_EQ(OK, callback2.WaitForResult());
396  EXPECT_FALSE(info.is_direct());
397  EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
398}
399
400TEST(ProxyServiceTest, ProxyFallback) {
401  // Test what happens when we specify multiple proxy servers and some of them
402  // are bad.
403
404  MockProxyConfigService* config_service =
405      new MockProxyConfigService("http://foopy/proxy.pac");
406
407  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
408
409  scoped_refptr<ProxyService> service(
410      new ProxyService(config_service, resolver, NULL));
411
412  GURL url("http://www.google.com/");
413
414  // Get the proxy information.
415  ProxyInfo info;
416  TestCompletionCallback callback1;
417  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
418  EXPECT_EQ(ERR_IO_PENDING, rv);
419
420  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
421            resolver->pending_set_pac_script_request()->script_data()->url());
422  resolver->pending_set_pac_script_request()->CompleteNow(OK);
423
424  ASSERT_EQ(1u, resolver->pending_requests().size());
425  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
426
427  // Set the result in proxy resolver.
428  resolver->pending_requests()[0]->results()->UseNamedProxy(
429      "foopy1:8080;foopy2:9090");
430  resolver->pending_requests()[0]->CompleteNow(OK);
431
432  // The first item is valid.
433  EXPECT_EQ(OK, callback1.WaitForResult());
434  EXPECT_FALSE(info.is_direct());
435  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
436
437  // Fake an error on the proxy.
438  TestCompletionCallback callback2;
439  rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
440                                          BoundNetLog());
441  EXPECT_EQ(OK, rv);
442
443  // The second proxy should be specified.
444  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
445
446  TestCompletionCallback callback3;
447  rv = service->ResolveProxy(url, &info, &callback3, NULL, BoundNetLog());
448  EXPECT_EQ(ERR_IO_PENDING, rv);
449
450  ASSERT_EQ(1u, resolver->pending_requests().size());
451  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
452
453  // Set the result in proxy resolver -- the second result is already known
454  // to be bad, so we will not try to use it initially.
455  resolver->pending_requests()[0]->results()->UseNamedProxy(
456      "foopy3:7070;foopy1:8080;foopy2:9090");
457  resolver->pending_requests()[0]->CompleteNow(OK);
458
459  EXPECT_EQ(OK, callback3.WaitForResult());
460  EXPECT_FALSE(info.is_direct());
461  EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI());
462
463  // We fake another error. It should now try the third one.
464  TestCompletionCallback callback4;
465  rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL,
466                                          BoundNetLog());
467  EXPECT_EQ(OK, rv);
468  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
469
470  // We fake another error. At this point we have tried all of the
471  // proxy servers we thought were valid; next we try the proxy server
472  // that was in our bad proxies map (foopy1:8080).
473  TestCompletionCallback callback5;
474  rv = service->ReconsiderProxyAfterError(url, &info, &callback5, NULL,
475                                          BoundNetLog());
476  EXPECT_EQ(OK, rv);
477  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
478
479  // Fake another error, the last proxy is gone, the list should now be empty,
480  // so there is nothing left to try.
481  TestCompletionCallback callback6;
482  rv = service->ReconsiderProxyAfterError(url, &info, &callback6, NULL,
483                                          BoundNetLog());
484  EXPECT_EQ(ERR_FAILED, rv);
485  EXPECT_FALSE(info.is_direct());
486  EXPECT_TRUE(info.is_empty());
487
488  // TODO(nsylvain): Test that the proxy can be retried after the delay.
489}
490
491// This test is similar to ProxyFallback, but this time we have an explicit
492// fallback choice to DIRECT.
493TEST(ProxyServiceTest, ProxyFallbackToDirect) {
494  MockProxyConfigService* config_service =
495      new MockProxyConfigService("http://foopy/proxy.pac");
496
497  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
498
499  scoped_refptr<ProxyService> service(
500      new ProxyService(config_service, resolver, NULL));
501
502  GURL url("http://www.google.com/");
503
504  // Get the proxy information.
505  ProxyInfo info;
506  TestCompletionCallback callback1;
507  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
508  EXPECT_EQ(ERR_IO_PENDING, rv);
509
510  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
511            resolver->pending_set_pac_script_request()->script_data()->url());
512  resolver->pending_set_pac_script_request()->CompleteNow(OK);
513
514  ASSERT_EQ(1u, resolver->pending_requests().size());
515  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
516
517  // Set the result in proxy resolver.
518  resolver->pending_requests()[0]->results()->UsePacString(
519      "PROXY foopy1:8080; PROXY foopy2:9090; DIRECT");
520  resolver->pending_requests()[0]->CompleteNow(OK);
521
522  // Get the first result.
523  EXPECT_EQ(OK, callback1.WaitForResult());
524  EXPECT_FALSE(info.is_direct());
525  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
526
527  // Fake an error on the proxy.
528  TestCompletionCallback callback2;
529  rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
530                                          BoundNetLog());
531  EXPECT_EQ(OK, rv);
532
533  // Now we get back the second proxy.
534  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
535
536  // Fake an error on this proxy as well.
537  TestCompletionCallback callback3;
538  rv = service->ReconsiderProxyAfterError(url, &info, &callback3, NULL,
539                                          BoundNetLog());
540  EXPECT_EQ(OK, rv);
541
542  // Finally, we get back DIRECT.
543  EXPECT_TRUE(info.is_direct());
544
545  // Now we tell the proxy service that even DIRECT failed.
546  TestCompletionCallback callback4;
547  rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL,
548                                          BoundNetLog());
549  // There was nothing left to try after DIRECT, so we are out of
550  // choices.
551  EXPECT_EQ(ERR_FAILED, rv);
552}
553
554TEST(ProxyServiceTest, ProxyFallback_NewSettings) {
555  // Test proxy failover when new settings are available.
556
557  MockProxyConfigService* config_service =
558      new MockProxyConfigService("http://foopy/proxy.pac");
559
560  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
561
562  scoped_refptr<ProxyService> service(
563      new ProxyService(config_service, resolver, NULL));
564
565  GURL url("http://www.google.com/");
566
567  // Get the proxy information.
568  ProxyInfo info;
569  TestCompletionCallback callback1;
570  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
571  EXPECT_EQ(ERR_IO_PENDING, rv);
572
573  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
574            resolver->pending_set_pac_script_request()->script_data()->url());
575  resolver->pending_set_pac_script_request()->CompleteNow(OK);
576
577  ASSERT_EQ(1u, resolver->pending_requests().size());
578  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
579
580  // Set the result in proxy resolver.
581  resolver->pending_requests()[0]->results()->UseNamedProxy(
582      "foopy1:8080;foopy2:9090");
583  resolver->pending_requests()[0]->CompleteNow(OK);
584
585  // The first item is valid.
586  EXPECT_EQ(OK, callback1.WaitForResult());
587  EXPECT_FALSE(info.is_direct());
588  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
589
590  // Fake an error on the proxy, and also a new configuration on the proxy.
591  config_service->SetConfig(
592      ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy-new/proxy.pac")));
593
594  TestCompletionCallback callback2;
595  rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
596                                          BoundNetLog());
597  EXPECT_EQ(ERR_IO_PENDING, rv);
598
599  EXPECT_EQ(GURL("http://foopy-new/proxy.pac"),
600            resolver->pending_set_pac_script_request()->script_data()->url());
601  resolver->pending_set_pac_script_request()->CompleteNow(OK);
602
603  ASSERT_EQ(1u, resolver->pending_requests().size());
604  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
605
606  resolver->pending_requests()[0]->results()->UseNamedProxy(
607      "foopy1:8080;foopy2:9090");
608  resolver->pending_requests()[0]->CompleteNow(OK);
609
610  // The first proxy is still there since the configuration changed.
611  EXPECT_EQ(OK, callback2.WaitForResult());
612  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
613
614  // We fake another error. It should now ignore the first one.
615  TestCompletionCallback callback3;
616  rv = service->ReconsiderProxyAfterError(url, &info, &callback3, NULL,
617                                          BoundNetLog());
618  EXPECT_EQ(OK, rv);
619  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
620
621  // We simulate a new configuration.
622  config_service->SetConfig(
623      ProxyConfig::CreateFromCustomPacURL(
624          GURL("http://foopy-new2/proxy.pac")));
625
626  // We fake another error. It should go back to the first proxy.
627  TestCompletionCallback callback4;
628  rv = service->ReconsiderProxyAfterError(url, &info, &callback4, NULL,
629                                          BoundNetLog());
630  EXPECT_EQ(ERR_IO_PENDING, rv);
631
632  EXPECT_EQ(GURL("http://foopy-new2/proxy.pac"),
633            resolver->pending_set_pac_script_request()->script_data()->url());
634  resolver->pending_set_pac_script_request()->CompleteNow(OK);
635
636  ASSERT_EQ(1u, resolver->pending_requests().size());
637  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
638
639  resolver->pending_requests()[0]->results()->UseNamedProxy(
640      "foopy1:8080;foopy2:9090");
641  resolver->pending_requests()[0]->CompleteNow(OK);
642
643  EXPECT_EQ(OK, callback4.WaitForResult());
644  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
645}
646
647TEST(ProxyServiceTest, ProxyFallback_BadConfig) {
648  // Test proxy failover when the configuration is bad.
649
650  MockProxyConfigService* config_service =
651      new MockProxyConfigService("http://foopy/proxy.pac");
652
653  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
654
655  scoped_refptr<ProxyService> service(
656      new ProxyService(config_service, resolver, NULL));
657
658  GURL url("http://www.google.com/");
659
660  // Get the proxy information.
661  ProxyInfo info;
662  TestCompletionCallback callback1;
663  int rv = service->ResolveProxy(url, &info, &callback1, NULL, BoundNetLog());
664  EXPECT_EQ(ERR_IO_PENDING, rv);
665
666  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
667            resolver->pending_set_pac_script_request()->script_data()->url());
668  resolver->pending_set_pac_script_request()->CompleteNow(OK);
669  ASSERT_EQ(1u, resolver->pending_requests().size());
670  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
671
672  resolver->pending_requests()[0]->results()->UseNamedProxy(
673      "foopy1:8080;foopy2:9090");
674  resolver->pending_requests()[0]->CompleteNow(OK);
675
676  // The first item is valid.
677  EXPECT_EQ(OK, callback1.WaitForResult());
678  EXPECT_FALSE(info.is_direct());
679  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
680
681  // Fake a proxy error.
682  TestCompletionCallback callback2;
683  rv = service->ReconsiderProxyAfterError(url, &info, &callback2, NULL,
684                                          BoundNetLog());
685  EXPECT_EQ(OK, rv);
686
687  // The first proxy is ignored, and the second one is selected.
688  EXPECT_FALSE(info.is_direct());
689  EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
690
691  // Fake a PAC failure.
692  ProxyInfo info2;
693  TestCompletionCallback callback3;
694  rv = service->ResolveProxy(url, &info2, &callback3, NULL, BoundNetLog());
695  EXPECT_EQ(ERR_IO_PENDING, rv);
696
697  ASSERT_EQ(1u, resolver->pending_requests().size());
698  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
699
700  // This simulates a javascript runtime error in the PAC script.
701  resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
702
703  // Although the resolver failed, the ProxyService will implicitly fall-back
704  // to a DIRECT connection.
705  EXPECT_EQ(OK, callback3.WaitForResult());
706  EXPECT_TRUE(info2.is_direct());
707  EXPECT_FALSE(info2.is_empty());
708
709  // The PAC script will work properly next time and successfully return a
710  // proxy list. Since we have not marked the configuration as bad, it should
711  // "just work" the next time we call it.
712  ProxyInfo info3;
713  TestCompletionCallback callback4;
714  rv = service->ReconsiderProxyAfterError(url, &info3, &callback4, NULL,
715                                          BoundNetLog());
716  EXPECT_EQ(ERR_IO_PENDING, rv);
717
718  ASSERT_EQ(1u, resolver->pending_requests().size());
719  EXPECT_EQ(url, resolver->pending_requests()[0]->url());
720
721  resolver->pending_requests()[0]->results()->UseNamedProxy(
722      "foopy1:8080;foopy2:9090");
723  resolver->pending_requests()[0]->CompleteNow(OK);
724
725  // The first proxy is not there since the it was added to the bad proxies
726  // list by the earlier ReconsiderProxyAfterError().
727  EXPECT_EQ(OK, callback4.WaitForResult());
728  EXPECT_FALSE(info3.is_direct());
729  EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
730}
731
732TEST(ProxyServiceTest, ProxyBypassList) {
733  // Test that the proxy bypass rules are consulted.
734
735  TestCompletionCallback callback[2];
736  ProxyInfo info[2];
737  ProxyConfig config;
738  config.proxy_rules().ParseFromString("foopy1:8080;foopy2:9090");
739  config.set_auto_detect(false);
740  config.proxy_rules().bypass_rules.ParseFromString("*.org");
741
742  scoped_refptr<ProxyService> service(new ProxyService(
743      new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
744
745  int rv;
746  GURL url1("http://www.webkit.org");
747  GURL url2("http://www.webkit.com");
748
749  // Request for a .org domain should bypass proxy.
750  rv = service->ResolveProxy(url1, &info[0], &callback[0], NULL, BoundNetLog());
751  EXPECT_EQ(OK, rv);
752  EXPECT_TRUE(info[0].is_direct());
753
754  // Request for a .com domain hits the proxy.
755  rv = service->ResolveProxy(url2, &info[1], &callback[1], NULL, BoundNetLog());
756  EXPECT_EQ(OK, rv);
757  EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI());
758}
759
760
761TEST(ProxyServiceTest, PerProtocolProxyTests) {
762  ProxyConfig config;
763  config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080");
764  config.set_auto_detect(false);
765  {
766    scoped_refptr<ProxyService> service(new ProxyService(
767        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
768    GURL test_url("http://www.msn.com");
769    ProxyInfo info;
770    TestCompletionCallback callback;
771    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
772                                   BoundNetLog());
773    EXPECT_EQ(OK, rv);
774    EXPECT_FALSE(info.is_direct());
775    EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
776  }
777  {
778    scoped_refptr<ProxyService> service(new ProxyService(
779        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
780    GURL test_url("ftp://ftp.google.com");
781    ProxyInfo info;
782    TestCompletionCallback callback;
783    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
784                                   BoundNetLog());
785    EXPECT_EQ(OK, rv);
786    EXPECT_TRUE(info.is_direct());
787    EXPECT_EQ("direct://", info.proxy_server().ToURI());
788  }
789  {
790    scoped_refptr<ProxyService> service(new ProxyService(
791        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
792    GURL test_url("https://webbranch.techcu.com");
793    ProxyInfo info;
794    TestCompletionCallback callback;
795    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
796                                   BoundNetLog());
797    EXPECT_EQ(OK, rv);
798    EXPECT_FALSE(info.is_direct());
799    EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
800  }
801  {
802    config.proxy_rules().ParseFromString("foopy1:8080");
803    scoped_refptr<ProxyService> service(new ProxyService(
804        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
805    GURL test_url("http://www.microsoft.com");
806    ProxyInfo info;
807    TestCompletionCallback callback;
808    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
809                                   BoundNetLog());
810    EXPECT_EQ(OK, rv);
811    EXPECT_FALSE(info.is_direct());
812    EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
813  }
814}
815
816// If only HTTP and a SOCKS proxy are specified, check if ftp/https queries
817// fall back to the SOCKS proxy.
818TEST(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
819  ProxyConfig config;
820  config.proxy_rules().ParseFromString("http=foopy1:8080;socks=foopy2:1080");
821  config.set_auto_detect(false);
822  EXPECT_EQ(ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME,
823            config.proxy_rules().type);
824
825  {
826    scoped_refptr<ProxyService> service(new ProxyService(
827        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
828    GURL test_url("http://www.msn.com");
829    ProxyInfo info;
830    TestCompletionCallback callback;
831    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
832                                   BoundNetLog());
833    EXPECT_EQ(OK, rv);
834    EXPECT_FALSE(info.is_direct());
835    EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
836  }
837  {
838    scoped_refptr<ProxyService> service(new ProxyService(
839        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
840    GURL test_url("ftp://ftp.google.com");
841    ProxyInfo info;
842    TestCompletionCallback callback;
843    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
844                                   BoundNetLog());
845    EXPECT_EQ(OK, rv);
846    EXPECT_FALSE(info.is_direct());
847    EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
848  }
849  {
850    scoped_refptr<ProxyService> service(new ProxyService(
851        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
852    GURL test_url("https://webbranch.techcu.com");
853    ProxyInfo info;
854    TestCompletionCallback callback;
855    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
856                                   BoundNetLog());
857    EXPECT_EQ(OK, rv);
858    EXPECT_FALSE(info.is_direct());
859    EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
860  }
861  {
862    scoped_refptr<ProxyService> service(new ProxyService(
863        new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL));
864    GURL test_url("unknown://www.microsoft.com");
865    ProxyInfo info;
866    TestCompletionCallback callback;
867    int rv = service->ResolveProxy(test_url, &info, &callback, NULL,
868                                   BoundNetLog());
869    EXPECT_EQ(OK, rv);
870    EXPECT_FALSE(info.is_direct());
871    EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
872  }
873}
874
875// Test cancellation of an in-progress request.
876TEST(ProxyServiceTest, CancelInProgressRequest) {
877  MockProxyConfigService* config_service =
878      new MockProxyConfigService("http://foopy/proxy.pac");
879
880  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
881
882  scoped_refptr<ProxyService> service(
883      new ProxyService(config_service, resolver, NULL));
884
885  // Start 3 requests.
886
887  ProxyInfo info1;
888  TestCompletionCallback callback1;
889  int rv = service->ResolveProxy(
890      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
891  EXPECT_EQ(ERR_IO_PENDING, rv);
892
893  // Nothing has been sent to the proxy resolver yet, since the proxy
894  // resolver has not been configured yet.
895  ASSERT_EQ(0u, resolver->pending_requests().size());
896
897  // Successfully initialize the PAC script.
898  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
899            resolver->pending_set_pac_script_request()->script_data()->url());
900  resolver->pending_set_pac_script_request()->CompleteNow(OK);
901
902  ASSERT_EQ(1u, resolver->pending_requests().size());
903  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
904
905  ProxyInfo info2;
906  TestCompletionCallback callback2;
907  ProxyService::PacRequest* request2;
908  rv = service->ResolveProxy(
909      GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog());
910  EXPECT_EQ(ERR_IO_PENDING, rv);
911  ASSERT_EQ(2u, resolver->pending_requests().size());
912  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
913
914  ProxyInfo info3;
915  TestCompletionCallback callback3;
916  rv = service->ResolveProxy(
917      GURL("http://request3"), &info3, &callback3, NULL, BoundNetLog());
918  EXPECT_EQ(ERR_IO_PENDING, rv);
919  ASSERT_EQ(3u, resolver->pending_requests().size());
920  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url());
921
922  // Cancel the second request
923  service->CancelPacRequest(request2);
924
925  ASSERT_EQ(2u, resolver->pending_requests().size());
926  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
927  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[1]->url());
928
929  // Complete the two un-cancelled requests.
930  // We complete the last one first, just to mix it up a bit.
931  resolver->pending_requests()[1]->results()->UseNamedProxy("request3:80");
932  resolver->pending_requests()[1]->CompleteNow(OK);
933
934  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
935  resolver->pending_requests()[0]->CompleteNow(OK);
936
937  // Complete and verify that requests ran as expected.
938  EXPECT_EQ(OK, callback1.WaitForResult());
939  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
940
941  EXPECT_FALSE(callback2.have_result());  // Cancelled.
942  ASSERT_EQ(1u, resolver->cancelled_requests().size());
943  EXPECT_EQ(GURL("http://request2"), resolver->cancelled_requests()[0]->url());
944
945  EXPECT_EQ(OK, callback3.WaitForResult());
946  EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
947}
948
949// Test the initial PAC download for resolver that expects bytes.
950TEST(ProxyServiceTest, InitialPACScriptDownload) {
951  MockProxyConfigService* config_service =
952      new MockProxyConfigService("http://foopy/proxy.pac");
953
954  MockAsyncProxyResolverExpectsBytes* resolver =
955      new MockAsyncProxyResolverExpectsBytes;
956
957  scoped_refptr<ProxyService> service(
958      new ProxyService(config_service, resolver, NULL));
959
960  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
961  service->SetProxyScriptFetcher(fetcher);
962
963  // Start 3 requests.
964
965  ProxyInfo info1;
966  TestCompletionCallback callback1;
967  int rv = service->ResolveProxy(
968      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
969  EXPECT_EQ(ERR_IO_PENDING, rv);
970
971  // The first request should have triggered download of PAC script.
972  EXPECT_TRUE(fetcher->has_pending_request());
973  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
974
975  ProxyInfo info2;
976  TestCompletionCallback callback2;
977  rv = service->ResolveProxy(
978      GURL("http://request2"), &info2, &callback2, NULL, BoundNetLog());
979  EXPECT_EQ(ERR_IO_PENDING, rv);
980
981  ProxyInfo info3;
982  TestCompletionCallback callback3;
983  rv = service->ResolveProxy(
984      GURL("http://request3"), &info3, &callback3, NULL, BoundNetLog());
985  EXPECT_EQ(ERR_IO_PENDING, rv);
986
987  // Nothing has been sent to the resolver yet.
988  EXPECT_TRUE(resolver->pending_requests().empty());
989
990  // At this point the ProxyService should be waiting for the
991  // ProxyScriptFetcher to invoke its completion callback, notifying it of
992  // PAC script download completion.
993  fetcher->NotifyFetchCompletion(OK, "pac-v1");
994
995  // Now that the PAC script is downloaded, it will have been sent to the proxy
996  // resolver.
997  EXPECT_EQ(ASCIIToUTF16("pac-v1"),
998            resolver->pending_set_pac_script_request()->script_data()->utf16());
999  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1000
1001  ASSERT_EQ(3u, resolver->pending_requests().size());
1002  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1003  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1004  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url());
1005
1006  // Complete all the requests (in some order).
1007  // Note that as we complete requests, they shift up in |pending_requests()|.
1008
1009  resolver->pending_requests()[2]->results()->UseNamedProxy("request3:80");
1010  resolver->pending_requests()[2]->CompleteNow(OK);
1011
1012  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1013  resolver->pending_requests()[0]->CompleteNow(OK);
1014
1015  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
1016  resolver->pending_requests()[0]->CompleteNow(OK);
1017
1018  // Complete and verify that requests ran as expected.
1019  EXPECT_EQ(OK, callback1.WaitForResult());
1020  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1021
1022  EXPECT_EQ(OK, callback2.WaitForResult());
1023  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1024
1025  EXPECT_EQ(OK, callback3.WaitForResult());
1026  EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
1027}
1028
1029// Test changing the ProxyScriptFetcher while PAC download is in progress.
1030TEST(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) {
1031  MockProxyConfigService* config_service =
1032      new MockProxyConfigService("http://foopy/proxy.pac");
1033
1034  MockAsyncProxyResolverExpectsBytes* resolver =
1035      new MockAsyncProxyResolverExpectsBytes;
1036
1037  scoped_refptr<ProxyService> service(
1038      new ProxyService(config_service, resolver, NULL));
1039
1040  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1041  service->SetProxyScriptFetcher(fetcher);
1042
1043  // Start 2 requests.
1044
1045  ProxyInfo info1;
1046  TestCompletionCallback callback1;
1047  int rv = service->ResolveProxy(
1048      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
1049  EXPECT_EQ(ERR_IO_PENDING, rv);
1050
1051  // The first request should have triggered download of PAC script.
1052  EXPECT_TRUE(fetcher->has_pending_request());
1053  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1054
1055  ProxyInfo info2;
1056  TestCompletionCallback callback2;
1057  rv = service->ResolveProxy(
1058      GURL("http://request2"), &info2, &callback2, NULL, BoundNetLog());
1059  EXPECT_EQ(ERR_IO_PENDING, rv);
1060
1061  // At this point the ProxyService should be waiting for the
1062  // ProxyScriptFetcher to invoke its completion callback, notifying it of
1063  // PAC script download completion.
1064
1065  // We now change out the ProxyService's script fetcher. We should restart
1066  // the initialization with the new fetcher.
1067
1068  fetcher = new MockProxyScriptFetcher;
1069  service->SetProxyScriptFetcher(fetcher);
1070
1071  // Nothing has been sent to the resolver yet.
1072  EXPECT_TRUE(resolver->pending_requests().empty());
1073
1074  fetcher->NotifyFetchCompletion(OK, "pac-v1");
1075
1076  // Now that the PAC script is downloaded, it will have been sent to the proxy
1077  // resolver.
1078  EXPECT_EQ(ASCIIToUTF16("pac-v1"),
1079            resolver->pending_set_pac_script_request()->script_data()->utf16());
1080  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1081
1082  ASSERT_EQ(2u, resolver->pending_requests().size());
1083  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1084  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1085}
1086
1087// Test cancellation of a request, while the PAC script is being fetched.
1088TEST(ProxyServiceTest, CancelWhilePACFetching) {
1089  MockProxyConfigService* config_service =
1090      new MockProxyConfigService("http://foopy/proxy.pac");
1091
1092  MockAsyncProxyResolverExpectsBytes* resolver =
1093      new MockAsyncProxyResolverExpectsBytes;
1094
1095  scoped_refptr<ProxyService> service(
1096      new ProxyService(config_service, resolver, NULL));
1097
1098  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1099  service->SetProxyScriptFetcher(fetcher);
1100
1101  // Start 3 requests.
1102  ProxyInfo info1;
1103  TestCompletionCallback callback1;
1104  ProxyService::PacRequest* request1;
1105  CapturingBoundNetLog log1(CapturingNetLog::kUnbounded);
1106  int rv = service->ResolveProxy(
1107      GURL("http://request1"), &info1, &callback1, &request1, log1.bound());
1108  EXPECT_EQ(ERR_IO_PENDING, rv);
1109
1110  // The first request should have triggered download of PAC script.
1111  EXPECT_TRUE(fetcher->has_pending_request());
1112  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1113
1114  ProxyInfo info2;
1115  TestCompletionCallback callback2;
1116  ProxyService::PacRequest* request2;
1117  rv = service->ResolveProxy(
1118      GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog());
1119  EXPECT_EQ(ERR_IO_PENDING, rv);
1120
1121  ProxyInfo info3;
1122  TestCompletionCallback callback3;
1123  rv = service->ResolveProxy(
1124      GURL("http://request3"), &info3, &callback3, NULL, BoundNetLog());
1125  EXPECT_EQ(ERR_IO_PENDING, rv);
1126
1127  // Nothing has been sent to the resolver yet.
1128  EXPECT_TRUE(resolver->pending_requests().empty());
1129
1130  // Cancel the first 2 requests.
1131  service->CancelPacRequest(request1);
1132  service->CancelPacRequest(request2);
1133
1134  // At this point the ProxyService should be waiting for the
1135  // ProxyScriptFetcher to invoke its completion callback, notifying it of
1136  // PAC script download completion.
1137  fetcher->NotifyFetchCompletion(OK, "pac-v1");
1138
1139  // Now that the PAC script is downloaded, it will have been sent to the
1140  // proxy resolver.
1141  EXPECT_EQ(ASCIIToUTF16("pac-v1"),
1142            resolver->pending_set_pac_script_request()->script_data()->utf16());
1143  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1144
1145  ASSERT_EQ(1u, resolver->pending_requests().size());
1146  EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[0]->url());
1147
1148  // Complete all the requests.
1149  resolver->pending_requests()[0]->results()->UseNamedProxy("request3:80");
1150  resolver->pending_requests()[0]->CompleteNow(OK);
1151
1152  EXPECT_EQ(OK, callback3.WaitForResult());
1153  EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
1154
1155  EXPECT_TRUE(resolver->cancelled_requests().empty());
1156
1157  EXPECT_FALSE(callback1.have_result());  // Cancelled.
1158  EXPECT_FALSE(callback2.have_result());  // Cancelled.
1159
1160  CapturingNetLog::EntryList entries1;
1161  log1.GetEntries(&entries1);
1162
1163  // Check the NetLog for request 1 (which was cancelled) got filled properly.
1164  EXPECT_EQ(4u, entries1.size());
1165  EXPECT_TRUE(LogContainsBeginEvent(
1166      entries1, 0, NetLog::TYPE_PROXY_SERVICE));
1167  EXPECT_TRUE(LogContainsBeginEvent(
1168      entries1, 1, NetLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC));
1169  // Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
1170  // the cancellation occured.
1171  EXPECT_TRUE(LogContainsEvent(
1172      entries1, 2, NetLog::TYPE_CANCELLED, NetLog::PHASE_NONE));
1173  EXPECT_TRUE(LogContainsEndEvent(
1174      entries1, 3, NetLog::TYPE_PROXY_SERVICE));
1175}
1176
1177// Test that if auto-detect fails, we fall-back to the custom pac.
1178TEST(ProxyServiceTest, FallbackFromAutodetectToCustomPac) {
1179  ProxyConfig config;
1180  config.set_auto_detect(true);
1181  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1182  config.proxy_rules().ParseFromString("http=foopy:80");  // Won't be used.
1183
1184  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1185  MockAsyncProxyResolverExpectsBytes* resolver =
1186      new MockAsyncProxyResolverExpectsBytes;
1187  scoped_refptr<ProxyService> service(
1188      new ProxyService(config_service, resolver, NULL));
1189
1190  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1191  service->SetProxyScriptFetcher(fetcher);
1192
1193  // Start 2 requests.
1194
1195  ProxyInfo info1;
1196  TestCompletionCallback callback1;
1197  int rv = service->ResolveProxy(
1198      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
1199  EXPECT_EQ(ERR_IO_PENDING, rv);
1200
1201  ProxyInfo info2;
1202  TestCompletionCallback callback2;
1203  ProxyService::PacRequest* request2;
1204  rv = service->ResolveProxy(
1205      GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog());
1206  EXPECT_EQ(ERR_IO_PENDING, rv);
1207
1208  // Check that nothing has been sent to the proxy resolver yet.
1209  ASSERT_EQ(0u, resolver->pending_requests().size());
1210
1211  // It should be trying to auto-detect first -- FAIL the autodetect during
1212  // the script download.
1213  EXPECT_TRUE(fetcher->has_pending_request());
1214  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1215  fetcher->NotifyFetchCompletion(ERR_FAILED, "");
1216
1217  // Next it should be trying the custom PAC url.
1218  EXPECT_TRUE(fetcher->has_pending_request());
1219  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1220  fetcher->NotifyFetchCompletion(OK, "custom-pac-script");
1221
1222  EXPECT_EQ(ASCIIToUTF16("custom-pac-script"),
1223            resolver->pending_set_pac_script_request()->script_data()->utf16());
1224  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1225
1226  // Now finally, the pending requests should have been sent to the resolver
1227  // (which was initialized with custom PAC script).
1228
1229  ASSERT_EQ(2u, resolver->pending_requests().size());
1230  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1231  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1232
1233  // Complete the pending requests.
1234  resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80");
1235  resolver->pending_requests()[1]->CompleteNow(OK);
1236  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1237  resolver->pending_requests()[0]->CompleteNow(OK);
1238
1239  // Verify that requests ran as expected.
1240  EXPECT_EQ(OK, callback1.WaitForResult());
1241  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1242
1243  EXPECT_EQ(OK, callback2.WaitForResult());
1244  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1245}
1246
1247// This is the same test as FallbackFromAutodetectToCustomPac, except
1248// the auto-detect script fails parsing rather than downloading.
1249TEST(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) {
1250  ProxyConfig config;
1251  config.set_auto_detect(true);
1252  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1253  config.proxy_rules().ParseFromString("http=foopy:80");  // Won't be used.
1254
1255  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1256  MockAsyncProxyResolverExpectsBytes* resolver =
1257      new MockAsyncProxyResolverExpectsBytes;
1258  scoped_refptr<ProxyService> service(
1259      new ProxyService(config_service, resolver, NULL));
1260
1261  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1262  service->SetProxyScriptFetcher(fetcher);
1263
1264  // Start 2 requests.
1265
1266  ProxyInfo info1;
1267  TestCompletionCallback callback1;
1268  int rv = service->ResolveProxy(
1269      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
1270  EXPECT_EQ(ERR_IO_PENDING, rv);
1271
1272  ProxyInfo info2;
1273  TestCompletionCallback callback2;
1274  ProxyService::PacRequest* request2;
1275  rv = service->ResolveProxy(
1276      GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog());
1277  EXPECT_EQ(ERR_IO_PENDING, rv);
1278
1279  // Check that nothing has been sent to the proxy resolver yet.
1280  ASSERT_EQ(0u, resolver->pending_requests().size());
1281
1282  // It should be trying to auto-detect first -- succeed the download.
1283  EXPECT_TRUE(fetcher->has_pending_request());
1284  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1285  fetcher->NotifyFetchCompletion(OK, "invalid-script-contents");
1286
1287  // Simulate a parse error.
1288  EXPECT_EQ(ASCIIToUTF16("invalid-script-contents"),
1289            resolver->pending_set_pac_script_request()->script_data()->utf16());
1290  resolver->pending_set_pac_script_request()->CompleteNow(
1291      ERR_PAC_SCRIPT_FAILED);
1292
1293  // Next it should be trying the custom PAC url.
1294  EXPECT_TRUE(fetcher->has_pending_request());
1295  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1296  fetcher->NotifyFetchCompletion(OK, "custom-pac-script");
1297
1298  EXPECT_EQ(ASCIIToUTF16("custom-pac-script"),
1299            resolver->pending_set_pac_script_request()->script_data()->utf16());
1300  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1301
1302  // Now finally, the pending requests should have been sent to the resolver
1303  // (which was initialized with custom PAC script).
1304
1305  ASSERT_EQ(2u, resolver->pending_requests().size());
1306  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1307  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
1308
1309  // Complete the pending requests.
1310  resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80");
1311  resolver->pending_requests()[1]->CompleteNow(OK);
1312  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1313  resolver->pending_requests()[0]->CompleteNow(OK);
1314
1315  // Verify that requests ran as expected.
1316  EXPECT_EQ(OK, callback1.WaitForResult());
1317  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1318
1319  EXPECT_EQ(OK, callback2.WaitForResult());
1320  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1321}
1322
1323// Test that if all of auto-detect, a custom PAC script, and manual settings
1324// are given, then we will try them in that order.
1325TEST(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) {
1326  ProxyConfig config;
1327  config.set_auto_detect(true);
1328  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1329  config.proxy_rules().ParseFromString("http=foopy:80");
1330
1331  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1332  MockAsyncProxyResolverExpectsBytes* resolver =
1333      new MockAsyncProxyResolverExpectsBytes;
1334  scoped_refptr<ProxyService> service(
1335      new ProxyService(config_service, resolver, NULL));
1336
1337  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1338  service->SetProxyScriptFetcher(fetcher);
1339
1340  // Start 2 requests.
1341
1342  ProxyInfo info1;
1343  TestCompletionCallback callback1;
1344  int rv = service->ResolveProxy(
1345      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
1346  EXPECT_EQ(ERR_IO_PENDING, rv);
1347
1348  ProxyInfo info2;
1349  TestCompletionCallback callback2;
1350  ProxyService::PacRequest* request2;
1351  rv = service->ResolveProxy(
1352      GURL("http://request2"), &info2, &callback2, &request2, BoundNetLog());
1353  EXPECT_EQ(ERR_IO_PENDING, rv);
1354
1355  // Check that nothing has been sent to the proxy resolver yet.
1356  ASSERT_EQ(0u, resolver->pending_requests().size());
1357
1358  // It should be trying to auto-detect first -- fail the download.
1359  EXPECT_TRUE(fetcher->has_pending_request());
1360  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1361  fetcher->NotifyFetchCompletion(ERR_FAILED, "");
1362
1363  // Next it should be trying the custom PAC url -- fail the download.
1364  EXPECT_TRUE(fetcher->has_pending_request());
1365  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1366  fetcher->NotifyFetchCompletion(ERR_FAILED, "");
1367
1368  // Since we never managed to initialize a ProxyResolver, nothing should have
1369  // been sent to it.
1370  ASSERT_EQ(0u, resolver->pending_requests().size());
1371
1372  // Verify that requests ran as expected -- they should have fallen back to
1373  // the manual proxy configuration for HTTP urls.
1374  EXPECT_EQ(OK, callback1.WaitForResult());
1375  EXPECT_EQ("foopy:80", info1.proxy_server().ToURI());
1376
1377  EXPECT_EQ(OK, callback2.WaitForResult());
1378  EXPECT_EQ("foopy:80", info2.proxy_server().ToURI());
1379}
1380
1381// Test that the bypass rules are NOT applied when using autodetect.
1382TEST(ProxyServiceTest, BypassDoesntApplyToPac) {
1383  ProxyConfig config;
1384  config.set_auto_detect(true);
1385  config.set_pac_url(GURL("http://foopy/proxy.pac"));
1386  config.proxy_rules().ParseFromString("http=foopy:80");  // Not used.
1387  config.proxy_rules().bypass_rules.ParseFromString("www.google.com");
1388
1389  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1390  MockAsyncProxyResolverExpectsBytes* resolver =
1391      new MockAsyncProxyResolverExpectsBytes;
1392  scoped_refptr<ProxyService> service(
1393      new ProxyService(config_service, resolver, NULL));
1394
1395  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1396  service->SetProxyScriptFetcher(fetcher);
1397
1398  // Start 1 requests.
1399
1400  ProxyInfo info1;
1401  TestCompletionCallback callback1;
1402  int rv = service->ResolveProxy(
1403      GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog());
1404  EXPECT_EQ(ERR_IO_PENDING, rv);
1405
1406  // Check that nothing has been sent to the proxy resolver yet.
1407  ASSERT_EQ(0u, resolver->pending_requests().size());
1408
1409  // It should be trying to auto-detect first -- succeed the download.
1410  EXPECT_TRUE(fetcher->has_pending_request());
1411  EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
1412  fetcher->NotifyFetchCompletion(OK, "auto-detect");
1413
1414  EXPECT_EQ(ASCIIToUTF16("auto-detect"),
1415            resolver->pending_set_pac_script_request()->script_data()->utf16());
1416  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1417
1418  ASSERT_EQ(1u, resolver->pending_requests().size());
1419  EXPECT_EQ(GURL("http://www.google.com"),
1420            resolver->pending_requests()[0]->url());
1421
1422  // Complete the pending request.
1423  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1424  resolver->pending_requests()[0]->CompleteNow(OK);
1425
1426  // Verify that request ran as expected.
1427  EXPECT_EQ(OK, callback1.WaitForResult());
1428  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1429
1430  // Start another request, it should pickup the bypass item.
1431  ProxyInfo info2;
1432  TestCompletionCallback callback2;
1433  rv = service->ResolveProxy(
1434      GURL("http://www.google.com"), &info2, &callback2, NULL, BoundNetLog());
1435  EXPECT_EQ(ERR_IO_PENDING, rv);
1436
1437  ASSERT_EQ(1u, resolver->pending_requests().size());
1438  EXPECT_EQ(GURL("http://www.google.com"),
1439            resolver->pending_requests()[0]->url());
1440
1441  // Complete the pending request.
1442  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
1443  resolver->pending_requests()[0]->CompleteNow(OK);
1444
1445  EXPECT_EQ(OK, callback2.WaitForResult());
1446  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1447}
1448
1449// Delete the ProxyService while InitProxyResolver has an outstanding
1450// request to the script fetcher. When run under valgrind, should not
1451// have any memory errors (used to be that the ProxyScriptFetcher was
1452// being deleted prior to the InitProxyResolver).
1453TEST(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingFetch) {
1454  ProxyConfig config =
1455    ProxyConfig::CreateFromCustomPacURL(GURL("http://foopy/proxy.pac"));
1456
1457  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1458  MockAsyncProxyResolverExpectsBytes* resolver =
1459      new MockAsyncProxyResolverExpectsBytes;
1460  scoped_refptr<ProxyService> service(
1461      new ProxyService(config_service, resolver, NULL));
1462
1463  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1464  service->SetProxyScriptFetcher(fetcher);
1465
1466  // Start 1 request.
1467
1468  ProxyInfo info1;
1469  TestCompletionCallback callback1;
1470  int rv = service->ResolveProxy(
1471      GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog());
1472  EXPECT_EQ(ERR_IO_PENDING, rv);
1473
1474  // Check that nothing has been sent to the proxy resolver yet.
1475  ASSERT_EQ(0u, resolver->pending_requests().size());
1476
1477  // InitProxyResolver should have issued a request to the ProxyScriptFetcher
1478  // and be waiting on that to complete.
1479  EXPECT_TRUE(fetcher->has_pending_request());
1480  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1481
1482  // Delete the ProxyService
1483  service = NULL;
1484}
1485
1486// Delete the ProxyService while InitProxyResolver has an outstanding
1487// request to the proxy resolver. When run under valgrind, should not
1488// have any memory errors (used to be that the ProxyResolver was
1489// being deleted prior to the InitProxyResolver).
1490TEST(ProxyServiceTest, DeleteWhileInitProxyResolverHasOutstandingSet) {
1491  MockProxyConfigService* config_service =
1492      new MockProxyConfigService("http://foopy/proxy.pac");
1493
1494  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
1495
1496  scoped_refptr<ProxyService> service(
1497      new ProxyService(config_service, resolver, NULL));
1498
1499  GURL url("http://www.google.com/");
1500
1501  ProxyInfo info;
1502  TestCompletionCallback callback;
1503  int rv = service->ResolveProxy(url, &info, &callback, NULL, BoundNetLog());
1504  EXPECT_EQ(ERR_IO_PENDING, rv);
1505
1506  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
1507            resolver->pending_set_pac_script_request()->script_data()->url());
1508
1509  // Delete the ProxyService.
1510  service = NULL;
1511}
1512
1513TEST(ProxyServiceTest, ResetProxyConfigService) {
1514  ProxyConfig config1;
1515  config1.proxy_rules().ParseFromString("foopy1:8080");
1516  config1.set_auto_detect(false);
1517  scoped_refptr<ProxyService> service(new ProxyService(
1518      new MockProxyConfigService(config1),
1519      new MockAsyncProxyResolverExpectsBytes, NULL));
1520
1521  ProxyInfo info;
1522  TestCompletionCallback callback1;
1523  int rv = service->ResolveProxy(
1524      GURL("http://request1"), &info, &callback1, NULL, BoundNetLog());
1525  EXPECT_EQ(OK, rv);
1526  EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
1527
1528  ProxyConfig config2;
1529  config2.proxy_rules().ParseFromString("foopy2:8080");
1530  config2.set_auto_detect(false);
1531  service->ResetConfigService(new MockProxyConfigService(config2));
1532  TestCompletionCallback callback2;
1533  rv = service->ResolveProxy(
1534      GURL("http://request2"), &info, &callback2, NULL, BoundNetLog());
1535  EXPECT_EQ(OK, rv);
1536  EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
1537}
1538
1539// Test that when going from a configuration that required PAC to one
1540// that does NOT, we unset the variable |should_use_proxy_resolver_|.
1541TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) {
1542  ProxyConfig config = ProxyConfig::CreateAutoDetect();
1543
1544  MockProxyConfigService* config_service = new MockProxyConfigService(config);
1545  MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
1546  scoped_refptr<ProxyService> service(
1547      new ProxyService(config_service, resolver, NULL));
1548
1549  // Start 1 request.
1550
1551  ProxyInfo info1;
1552  TestCompletionCallback callback1;
1553  int rv = service->ResolveProxy(
1554      GURL("http://www.google.com"), &info1, &callback1, NULL, BoundNetLog());
1555  EXPECT_EQ(ERR_IO_PENDING, rv);
1556
1557  // Check that nothing has been sent to the proxy resolver yet.
1558  ASSERT_EQ(0u, resolver->pending_requests().size());
1559
1560  // Successfully set the autodetect script.
1561  EXPECT_EQ(ProxyResolverScriptData::TYPE_AUTO_DETECT,
1562            resolver->pending_set_pac_script_request()->script_data()->type());
1563  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1564
1565  // Complete the pending request.
1566  ASSERT_EQ(1u, resolver->pending_requests().size());
1567  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1568  resolver->pending_requests()[0]->CompleteNow(OK);
1569
1570  // Verify that request ran as expected.
1571  EXPECT_EQ(OK, callback1.WaitForResult());
1572  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1573
1574  // Force the ProxyService to pull down a new proxy configuration.
1575  // (Even though the configuration isn't old/bad).
1576  //
1577  // This new configuration no longer has auto_detect set, so
1578  // requests should complete synchronously now as direct-connect.
1579  config_service->SetConfig(ProxyConfig::CreateDirect());
1580
1581  // Start another request -- the effective configuration has changed.
1582  ProxyInfo info2;
1583  TestCompletionCallback callback2;
1584  rv = service->ResolveProxy(
1585      GURL("http://www.google.com"), &info2, &callback2, NULL, BoundNetLog());
1586  EXPECT_EQ(OK, rv);
1587
1588  EXPECT_TRUE(info2.is_direct());
1589}
1590
1591TEST(ProxyServiceTest, NetworkChangeTriggersPacRefetch) {
1592  MockProxyConfigService* config_service =
1593      new MockProxyConfigService("http://foopy/proxy.pac");
1594
1595  MockAsyncProxyResolverExpectsBytes* resolver =
1596      new MockAsyncProxyResolverExpectsBytes;
1597
1598  CapturingNetLog log(CapturingNetLog::kUnbounded);
1599
1600  scoped_refptr<ProxyService> service(
1601      new ProxyService(config_service, resolver, &log));
1602
1603  MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
1604  service->SetProxyScriptFetcher(fetcher);
1605
1606  // Disable the "wait after IP address changes" hack, so this unit-test can
1607  // complete quickly.
1608  service->set_stall_proxy_auto_config_delay(base::TimeDelta());
1609
1610  // Start 1 request.
1611
1612  ProxyInfo info1;
1613  TestCompletionCallback callback1;
1614  int rv = service->ResolveProxy(
1615      GURL("http://request1"), &info1, &callback1, NULL, BoundNetLog());
1616  EXPECT_EQ(ERR_IO_PENDING, rv);
1617
1618  // The first request should have triggered initial download of PAC script.
1619  EXPECT_TRUE(fetcher->has_pending_request());
1620  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1621
1622  // Nothing has been sent to the resolver yet.
1623  EXPECT_TRUE(resolver->pending_requests().empty());
1624
1625  // At this point the ProxyService should be waiting for the
1626  // ProxyScriptFetcher to invoke its completion callback, notifying it of
1627  // PAC script download completion.
1628  fetcher->NotifyFetchCompletion(OK, "pac-v1");
1629
1630  // Now that the PAC script is downloaded, the request will have been sent to
1631  // the proxy resolver.
1632  EXPECT_EQ(ASCIIToUTF16("pac-v1"),
1633            resolver->pending_set_pac_script_request()->script_data()->utf16());
1634  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1635
1636  ASSERT_EQ(1u, resolver->pending_requests().size());
1637  EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
1638
1639  // Complete the pending request.
1640  resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
1641  resolver->pending_requests()[0]->CompleteNow(OK);
1642
1643  // Wait for completion callback, and verify that the request ran as expected.
1644  EXPECT_EQ(OK, callback1.WaitForResult());
1645  EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
1646
1647  // Now simluate a change in the network. The ProxyConfigService is still
1648  // going to return the same PAC URL as before, but this URL needs to be
1649  // refetched on the new network.
1650  NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
1651  MessageLoop::current()->RunAllPending();  // Notification happens async.
1652
1653  // Start a second request.
1654  ProxyInfo info2;
1655  TestCompletionCallback callback2;
1656  rv = service->ResolveProxy(
1657      GURL("http://request2"), &info2, &callback2, NULL, BoundNetLog());
1658  EXPECT_EQ(ERR_IO_PENDING, rv);
1659
1660  // This second request should have triggered the re-download of the PAC
1661  // script (since we marked the network as having changed).
1662  EXPECT_TRUE(fetcher->has_pending_request());
1663  EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
1664
1665  // Nothing has been sent to the resolver yet.
1666  EXPECT_TRUE(resolver->pending_requests().empty());
1667
1668  // Simulate the PAC script fetch as having completed (this time with
1669  // different data).
1670  fetcher->NotifyFetchCompletion(OK, "pac-v2");
1671
1672  // Now that the PAC script is downloaded, the second request will have been
1673  // sent to the proxy resolver.
1674  EXPECT_EQ(ASCIIToUTF16("pac-v2"),
1675            resolver->pending_set_pac_script_request()->script_data()->utf16());
1676  resolver->pending_set_pac_script_request()->CompleteNow(OK);
1677
1678  ASSERT_EQ(1u, resolver->pending_requests().size());
1679  EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[0]->url());
1680
1681  // Complete the pending second request.
1682  resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
1683  resolver->pending_requests()[0]->CompleteNow(OK);
1684
1685  // Wait for completion callback, and verify that the request ran as expected.
1686  EXPECT_EQ(OK, callback2.WaitForResult());
1687  EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
1688
1689  // Check that the expected events were outputted to the log stream.
1690  // In particular, PROXY_CONFIG_CHANGED should have only been emitted once
1691  // (for the initial setup), and NOT a second time when the IP address
1692  // changed.
1693  CapturingNetLog::EntryList entries;
1694  log.GetEntries(&entries);
1695
1696  EXPECT_TRUE(LogContainsEntryWithType(entries, 0,
1697                                       NetLog::TYPE_PROXY_CONFIG_CHANGED));
1698  ASSERT_EQ(13u, entries.size());
1699  for (size_t i = 1; i < entries.size(); ++i)
1700    EXPECT_NE(NetLog::TYPE_PROXY_CONFIG_CHANGED, entries[i].type);
1701}
1702
1703}  // namespace net
1704