Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / proxy / proxy_resolver_v8_tracing_unittest.cc
1 // Copyright (c) 2013 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_resolver_v8_tracing.h"
6
7 #include "base/files/file_util.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/values.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/net_log.h"
19 #include "net/base/net_log_unittest.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/dns/host_cache.h"
22 #include "net/dns/mock_host_resolver.h"
23 #include "net/proxy/proxy_info.h"
24 #include "net/proxy/proxy_resolver_error_observer.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "url/gurl.h"
27
28 namespace net {
29
30 namespace {
31
32 class ProxyResolverV8TracingTest : public testing::Test {
33  public:
34   void TearDown() override {
35     // Drain any pending messages, which may be left over from cancellation.
36     // This way they get reliably run as part of the current test, rather than
37     // spilling into the next test's execution.
38     base::MessageLoop::current()->RunUntilIdle();
39   }
40 };
41
42 scoped_refptr<ProxyResolverScriptData> LoadScriptData(const char* filename) {
43   base::FilePath path;
44   PathService::Get(base::DIR_SOURCE_ROOT, &path);
45   path = path.AppendASCII("net");
46   path = path.AppendASCII("data");
47   path = path.AppendASCII("proxy_resolver_v8_tracing_unittest");
48   path = path.AppendASCII(filename);
49
50   // Try to read the file from disk.
51   std::string file_contents;
52   bool ok = base::ReadFileToString(path, &file_contents);
53
54   // If we can't load the file from disk, something is misconfigured.
55   EXPECT_TRUE(ok) << "Failed to read file: " << path.value();
56
57   // Load the PAC script into the ProxyResolver.
58   return ProxyResolverScriptData::FromUTF8(file_contents);
59 }
60
61 void InitResolver(ProxyResolverV8Tracing* resolver, const char* filename) {
62   TestCompletionCallback callback;
63   int rv =
64       resolver->SetPacScript(LoadScriptData(filename), callback.callback());
65   EXPECT_EQ(ERR_IO_PENDING, rv);
66   EXPECT_EQ(OK, callback.WaitForResult());
67 }
68
69 class MockErrorObserver : public ProxyResolverErrorObserver {
70  public:
71   MockErrorObserver() : event_(true, false) {}
72
73   void OnPACScriptError(int line_number, const base::string16& error) override {
74     {
75       base::AutoLock l(lock_);
76       output += base::StringPrintf("Error: line %d: %s\n", line_number,
77                                    base::UTF16ToASCII(error).c_str());
78     }
79     event_.Signal();
80   }
81
82   std::string GetOutput() {
83     base::AutoLock l(lock_);
84     return output;
85   }
86
87   void WaitForOutput() {
88     event_.Wait();
89   }
90
91  private:
92   base::Lock lock_;
93   std::string output;
94
95   base::WaitableEvent event_;
96 };
97
98 TEST_F(ProxyResolverV8TracingTest, Simple) {
99   CapturingNetLog log;
100   CapturingBoundNetLog request_log;
101   MockCachingHostResolver host_resolver;
102   MockErrorObserver* error_observer = new MockErrorObserver;
103   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
104
105   InitResolver(&resolver, "simple.js");
106
107   TestCompletionCallback callback;
108   ProxyInfo proxy_info;
109
110   int rv = resolver.GetProxyForURL(
111       GURL("http://foo/"), &proxy_info, callback.callback(),
112       NULL, request_log.bound());
113
114   EXPECT_EQ(ERR_IO_PENDING, rv);
115   EXPECT_EQ(OK, callback.WaitForResult());
116
117   EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI());
118
119   EXPECT_EQ(0u, host_resolver.num_resolve());
120
121   // There were no errors.
122   EXPECT_EQ("", error_observer->GetOutput());
123
124   // Check the NetLogs -- nothing was logged.
125   EXPECT_EQ(0u, log.GetSize());
126   EXPECT_EQ(0u, request_log.GetSize());
127 }
128
129 TEST_F(ProxyResolverV8TracingTest, JavascriptError) {
130   CapturingNetLog log;
131   CapturingBoundNetLog request_log;
132   MockCachingHostResolver host_resolver;
133   MockErrorObserver* error_observer = new MockErrorObserver;
134   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
135
136   InitResolver(&resolver, "error.js");
137
138   TestCompletionCallback callback;
139   ProxyInfo proxy_info;
140
141   int rv = resolver.GetProxyForURL(
142       GURL("http://throw-an-error/"), &proxy_info, callback.callback(), NULL,
143       request_log.bound());
144
145   EXPECT_EQ(ERR_IO_PENDING, rv);
146   EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
147
148   EXPECT_EQ(0u, host_resolver.num_resolve());
149
150   EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
151             "of null\n", error_observer->GetOutput());
152
153   // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
154   // were output to both the global log, and per-request log.
155   CapturingNetLog::CapturedEntryList entries_list[2];
156   log.GetEntries(&entries_list[0]);
157   request_log.GetEntries(&entries_list[1]);
158
159   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
160     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
161     EXPECT_EQ(2u, entries.size());
162     EXPECT_TRUE(
163         LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
164                          NetLog::PHASE_NONE));
165     EXPECT_TRUE(
166         LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
167                          NetLog::PHASE_NONE));
168
169     EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries[0].GetParamsJson());
170     EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
171               "read property 'split' of null\"}", entries[1].GetParamsJson());
172   }
173 }
174
175 TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) {
176   CapturingNetLog log;
177   CapturingBoundNetLog request_log;
178   MockCachingHostResolver host_resolver;
179   MockErrorObserver* error_observer = new MockErrorObserver;
180   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
181
182   InitResolver(&resolver, "too_many_alerts.js");
183
184   TestCompletionCallback callback;
185   ProxyInfo proxy_info;
186
187   int rv = resolver.GetProxyForURL(
188       GURL("http://foo/"),
189       &proxy_info,
190       callback.callback(),
191       NULL,
192       request_log.bound());
193
194   EXPECT_EQ(ERR_IO_PENDING, rv);
195   EXPECT_EQ(OK, callback.WaitForResult());
196
197   // Iteration1 does a DNS resolve
198   // Iteration2 exceeds the alert buffer
199   // Iteration3 runs in blocking mode and completes
200   EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
201
202   EXPECT_EQ(1u, host_resolver.num_resolve());
203
204   // No errors.
205   EXPECT_EQ("", error_observer->GetOutput());
206
207   // Check the NetLogs -- the script generated 50 alerts, which were mirrored
208   // to both the global and per-request logs.
209   CapturingNetLog::CapturedEntryList entries_list[2];
210   log.GetEntries(&entries_list[0]);
211   request_log.GetEntries(&entries_list[1]);
212
213   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
214     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
215     EXPECT_EQ(50u, entries.size());
216     for (size_t i = 0; i < entries.size(); ++i) {
217       ASSERT_TRUE(
218           LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
219                            NetLog::PHASE_NONE));
220     }
221   }
222 }
223
224 // Verify that buffered alerts cannot grow unboundedly, even when the message is
225 // empty string.
226 TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) {
227   CapturingNetLog log;
228   CapturingBoundNetLog request_log;
229   MockCachingHostResolver host_resolver;
230   MockErrorObserver* error_observer = new MockErrorObserver;
231   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
232
233   InitResolver(&resolver, "too_many_empty_alerts.js");
234
235   TestCompletionCallback callback;
236   ProxyInfo proxy_info;
237
238   int rv = resolver.GetProxyForURL(
239       GURL("http://foo/"),
240       &proxy_info,
241       callback.callback(),
242       NULL,
243       request_log.bound());
244
245   EXPECT_EQ(ERR_IO_PENDING, rv);
246   EXPECT_EQ(OK, callback.WaitForResult());
247
248   EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
249
250   EXPECT_EQ(1u, host_resolver.num_resolve());
251
252   // No errors.
253   EXPECT_EQ("", error_observer->GetOutput());
254
255   // Check the NetLogs -- the script generated 50 alerts, which were mirrored
256   // to both the global and per-request logs.
257   CapturingNetLog::CapturedEntryList entries_list[2];
258   log.GetEntries(&entries_list[0]);
259   request_log.GetEntries(&entries_list[1]);
260
261   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
262     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
263     EXPECT_EQ(1000u, entries.size());
264     for (size_t i = 0; i < entries.size(); ++i) {
265       ASSERT_TRUE(
266           LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
267                            NetLog::PHASE_NONE));
268     }
269   }
270 }
271
272 // This test runs a PAC script that issues a sequence of DNS resolves. The test
273 // verifies the final result, and that the underlying DNS resolver received
274 // the correct set of queries.
275 TEST_F(ProxyResolverV8TracingTest, Dns) {
276   CapturingNetLog log;
277   CapturingBoundNetLog request_log;
278   MockCachingHostResolver host_resolver;
279   MockErrorObserver* error_observer = new MockErrorObserver;
280   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
281
282   host_resolver.rules()->AddRuleForAddressFamily(
283       "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
284   host_resolver.rules()
285       ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
286   host_resolver.rules()->AddSimulatedFailure("host2");
287   host_resolver.rules()->AddRule("host3", "166.155.144.33");
288   host_resolver.rules()->AddRule("host5", "166.155.144.55");
289   host_resolver.rules()->AddSimulatedFailure("host6");
290   host_resolver.rules()->AddRuleForAddressFamily(
291       "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
292   host_resolver.rules()->AddRule("*", "133.122.100.200");
293
294   InitResolver(&resolver, "dns.js");
295
296   TestCompletionCallback callback;
297   ProxyInfo proxy_info;
298
299   int rv = resolver.GetProxyForURL(
300       GURL("http://foo/"),
301       &proxy_info,
302       callback.callback(),
303       NULL,
304       request_log.bound());
305
306   EXPECT_EQ(ERR_IO_PENDING, rv);
307   EXPECT_EQ(OK, callback.WaitForResult());
308
309   // The test does 13 DNS resolution, however only 7 of them are unique.
310   EXPECT_EQ(7u, host_resolver.num_resolve());
311
312   const char* kExpectedResult =
313     "122.133.144.155-"  // myIpAddress()
314     "null-"  // dnsResolve('')
315     "__1_192.168.1.1-"  // dnsResolveEx('host1')
316     "null-"  // dnsResolve('host2')
317     "166.155.144.33-"  // dnsResolve('host3')
318     "122.133.144.155-"  // myIpAddress()
319     "166.155.144.33-"  // dnsResolve('host3')
320     "__1_192.168.1.1-"  // dnsResolveEx('host1')
321     "122.133.144.155-"  // myIpAddress()
322     "null-"  // dnsResolve('host2')
323     "-"  // dnsResolveEx('host6')
324     "133.122.100.200-"  // myIpAddressEx()
325     "166.155.144.44"  // dnsResolve('host1')
326     ":99";
327
328   EXPECT_EQ(kExpectedResult, proxy_info.proxy_server().ToURI());
329
330   // No errors.
331   EXPECT_EQ("", error_observer->GetOutput());
332
333   // Check the NetLogs -- the script generated 1 alert, mirrored to both
334   // the per-request and global logs.
335   CapturingNetLog::CapturedEntryList entries_list[2];
336   log.GetEntries(&entries_list[0]);
337   request_log.GetEntries(&entries_list[1]);
338
339   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
340     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
341     EXPECT_EQ(1u, entries.size());
342     EXPECT_TRUE(
343         LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
344                          NetLog::PHASE_NONE));
345     EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson());
346   }
347 }
348
349 // This test runs a PAC script that does "myIpAddress()" followed by
350 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
351 // cache is warmed, subsequent calls should take 0 restarts.
352 TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) {
353   CapturingNetLog log;
354   CapturingBoundNetLog request_log;
355   MockCachingHostResolver host_resolver;
356   MockErrorObserver* error_observer = new MockErrorObserver;
357   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
358
359   host_resolver.rules()->AddRule("foopy", "166.155.144.11");
360   host_resolver.rules()->AddRule("*", "122.133.144.155");
361
362   InitResolver(&resolver, "simple_dns.js");
363
364   TestCompletionCallback callback1;
365   TestCompletionCallback callback2;
366   ProxyInfo proxy_info;
367
368   int rv = resolver.GetProxyForURL(
369       GURL("http://foopy/req1"),
370       &proxy_info,
371       callback1.callback(),
372       NULL,
373       request_log.bound());
374
375   EXPECT_EQ(ERR_IO_PENDING, rv);
376   EXPECT_EQ(OK, callback1.WaitForResult());
377
378   // The test does 2 DNS resolutions.
379   EXPECT_EQ(2u, host_resolver.num_resolve());
380
381   // The first request took 2 restarts, hence on g_iteration=3.
382   EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI());
383
384   rv = resolver.GetProxyForURL(
385       GURL("http://foopy/req2"),
386       &proxy_info,
387       callback2.callback(),
388       NULL,
389       request_log.bound());
390
391   EXPECT_EQ(ERR_IO_PENDING, rv);
392   EXPECT_EQ(OK, callback2.WaitForResult());
393
394   EXPECT_EQ(4u, host_resolver.num_resolve());
395
396   // This time no restarts were required, so g_iteration incremented by 1.
397   EXPECT_EQ("166.155.144.11:4", proxy_info.proxy_server().ToURI());
398
399   // No errors.
400   EXPECT_EQ("", error_observer->GetOutput());
401
402   EXPECT_EQ(0u, log.GetSize());
403   EXPECT_EQ(0u, request_log.GetSize());
404 }
405
406 // This test runs a weird PAC script that was designed to defeat the DNS tracing
407 // optimization. The proxy resolver should detect the inconsistency and
408 // fall-back to synchronous mode execution.
409 TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous1) {
410   CapturingNetLog log;
411   CapturingBoundNetLog request_log;
412   MockCachingHostResolver host_resolver;
413   MockErrorObserver* error_observer = new MockErrorObserver;
414   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
415
416   host_resolver.rules()->AddRule("host1", "166.155.144.11");
417   host_resolver.rules()->AddRule("crazy4", "133.199.111.4");
418   host_resolver.rules()->AddRule("*", "122.133.144.155");
419
420   InitResolver(&resolver, "global_sideffects1.js");
421
422   TestCompletionCallback callback;
423   ProxyInfo proxy_info;
424
425   int rv = resolver.GetProxyForURL(
426       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
427       request_log.bound());
428   EXPECT_EQ(ERR_IO_PENDING, rv);
429   EXPECT_EQ(OK, callback.WaitForResult());
430
431   // The script itself only does 2 DNS resolves per execution, however it
432   // constructs the hostname using a global counter which changes on each
433   // invocation.
434   EXPECT_EQ(3u, host_resolver.num_resolve());
435
436   EXPECT_EQ("166.155.144.11-133.199.111.4:100",
437             proxy_info.proxy_server().ToURI());
438
439   // No errors.
440   EXPECT_EQ("", error_observer->GetOutput());
441
442   // Check the NetLogs -- the script generated 1 alert, mirrored to both
443   // the per-request and global logs.
444   CapturingNetLog::CapturedEntryList entries_list[2];
445   log.GetEntries(&entries_list[0]);
446   request_log.GetEntries(&entries_list[1]);
447
448   for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
449     const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
450     EXPECT_EQ(1u, entries.size());
451     EXPECT_TRUE(
452         LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
453                          NetLog::PHASE_NONE));
454     EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson());
455   }
456 }
457
458 // This test runs a weird PAC script that was designed to defeat the DNS tracing
459 // optimization. The proxy resolver should detect the inconsistency and
460 // fall-back to synchronous mode execution.
461 TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) {
462   CapturingNetLog log;
463   CapturingBoundNetLog request_log;
464   MockCachingHostResolver host_resolver;
465   MockErrorObserver* error_observer = new MockErrorObserver;
466   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
467
468   host_resolver.rules()->AddRule("host1", "166.155.144.11");
469   host_resolver.rules()->AddRule("host2", "166.155.144.22");
470   host_resolver.rules()->AddRule("host3", "166.155.144.33");
471   host_resolver.rules()->AddRule("host4", "166.155.144.44");
472   host_resolver.rules()->AddRule("*", "122.133.144.155");
473
474   InitResolver(&resolver, "global_sideffects2.js");
475
476   TestCompletionCallback callback;
477   ProxyInfo proxy_info;
478
479   int rv = resolver.GetProxyForURL(
480       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
481       request_log.bound());
482   EXPECT_EQ(ERR_IO_PENDING, rv);
483   EXPECT_EQ(OK, callback.WaitForResult());
484
485   EXPECT_EQ(3u, host_resolver.num_resolve());
486
487   EXPECT_EQ("166.155.144.44:100", proxy_info.proxy_server().ToURI());
488
489   // No errors.
490   EXPECT_EQ("", error_observer->GetOutput());
491
492   // Check the NetLogs -- nothing was logged.
493   EXPECT_EQ(0u, log.GetSize());
494   EXPECT_EQ(0u, request_log.GetSize());
495 }
496
497 // This test runs a weird PAC script that yields a never ending sequence
498 // of DNS resolves when restarting. Running it will hit the maximum
499 // DNS resolves per request limit (20) after which every DNS resolve will
500 // fail.
501 TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) {
502   CapturingNetLog log;
503   CapturingBoundNetLog request_log;
504   MockCachingHostResolver host_resolver;
505   MockErrorObserver* error_observer = new MockErrorObserver;
506   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
507
508   host_resolver.rules()->AddRule("host*", "166.155.144.11");
509   host_resolver.rules()->AddRule("*", "122.133.144.155");
510
511   InitResolver(&resolver, "global_sideffects3.js");
512
513   TestCompletionCallback callback;
514   ProxyInfo proxy_info;
515
516   int rv = resolver.GetProxyForURL(
517       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
518       request_log.bound());
519   EXPECT_EQ(ERR_IO_PENDING, rv);
520   EXPECT_EQ(OK, callback.WaitForResult());
521
522   EXPECT_EQ(20u, host_resolver.num_resolve());
523
524   EXPECT_EQ(
525       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
526       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
527       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
528       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
529       "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
530       "null:21", proxy_info.proxy_server().ToURI());
531
532   // No errors.
533   EXPECT_EQ("", error_observer->GetOutput());
534
535   // Check the NetLogs -- 1 alert was logged.
536   EXPECT_EQ(1u, log.GetSize());
537   EXPECT_EQ(1u, request_log.GetSize());
538 }
539
540 // This test runs a weird PAC script that yields a never ending sequence
541 // of DNS resolves when restarting. Running it will hit the maximum
542 // DNS resolves per request limit (20) after which every DNS resolve will
543 // fail.
544 TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) {
545   CapturingNetLog log;
546   CapturingBoundNetLog request_log;
547   MockCachingHostResolver host_resolver;
548   MockErrorObserver* error_observer = new MockErrorObserver;
549   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
550
551   host_resolver.rules()->AddRule("host*", "166.155.144.11");
552   host_resolver.rules()->AddRule("*", "122.133.144.155");
553
554   InitResolver(&resolver, "global_sideffects4.js");
555
556   TestCompletionCallback callback;
557   ProxyInfo proxy_info;
558
559   int rv = resolver.GetProxyForURL(
560       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
561       request_log.bound());
562   EXPECT_EQ(ERR_IO_PENDING, rv);
563   EXPECT_EQ(OK, callback.WaitForResult());
564
565   EXPECT_EQ(20u, host_resolver.num_resolve());
566
567   EXPECT_EQ("null21:34", proxy_info.proxy_server().ToURI());
568
569   // No errors.
570   EXPECT_EQ("", error_observer->GetOutput());
571
572   // Check the NetLogs -- 1 alert was logged.
573   EXPECT_EQ(1u, log.GetSize());
574   EXPECT_EQ(1u, request_log.GetSize());
575 }
576
577 void DnsDuringInitHelper(bool synchronous_host_resolver) {
578   CapturingNetLog log;
579   CapturingBoundNetLog request_log;
580   MockCachingHostResolver host_resolver;
581   host_resolver.set_synchronous_mode(synchronous_host_resolver);
582   MockErrorObserver* error_observer = new MockErrorObserver;
583   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
584
585   host_resolver.rules()->AddRule("host1", "91.13.12.1");
586   host_resolver.rules()->AddRule("host2", "91.13.12.2");
587
588   InitResolver(&resolver, "dns_during_init.js");
589
590   // Initialization did 2 dnsResolves.
591   EXPECT_EQ(2u, host_resolver.num_resolve());
592
593   host_resolver.rules()->ClearRules();
594   host_resolver.GetHostCache()->clear();
595
596   host_resolver.rules()->AddRule("host1", "145.88.13.3");
597   host_resolver.rules()->AddRule("host2", "137.89.8.45");
598
599   TestCompletionCallback callback;
600   ProxyInfo proxy_info;
601
602   int rv = resolver.GetProxyForURL(
603       GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
604       request_log.bound());
605   EXPECT_EQ(ERR_IO_PENDING, rv);
606   EXPECT_EQ(OK, callback.WaitForResult());
607
608   // Fetched host1 and host2 again, since the ones done during initialization
609   // should not have been cached.
610   EXPECT_EQ(4u, host_resolver.num_resolve());
611
612   EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
613             proxy_info.proxy_server().ToURI());
614
615   // Check the NetLogs -- the script generated 2 alerts during initialization.
616   EXPECT_EQ(0u, request_log.GetSize());
617   CapturingNetLog::CapturedEntryList entries;
618   log.GetEntries(&entries);
619
620   ASSERT_EQ(2u, entries.size());
621   EXPECT_TRUE(
622       LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
623                        NetLog::PHASE_NONE));
624   EXPECT_TRUE(
625       LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
626                        NetLog::PHASE_NONE));
627
628   EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson());
629   EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson());
630 }
631
632 // Tests a PAC script which does DNS resolves during initialization.
633 TEST_F(ProxyResolverV8TracingTest, DnsDuringInit) {
634   // Test with both both a host resolver that always completes asynchronously,
635   // and then again with one that completes synchronously.
636   DnsDuringInitHelper(false);
637   DnsDuringInitHelper(true);
638 }
639
640 void CrashCallback(int) {
641   // Be extra sure that if the callback ever gets invoked, the test will fail.
642   CHECK(false);
643 }
644
645 // Start some requests, cancel them all, and then destroy the resolver.
646 // Note the execution order for this test can vary. Since multiple
647 // threads are involved, the cancellation may be received a different
648 // times.
649 TEST_F(ProxyResolverV8TracingTest, CancelAll) {
650   MockCachingHostResolver host_resolver;
651   MockErrorObserver* error_observer = new MockErrorObserver;
652   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
653
654   host_resolver.rules()->AddSimulatedFailure("*");
655
656   InitResolver(&resolver, "dns.js");
657
658   const size_t kNumRequests = 5;
659   ProxyInfo proxy_info[kNumRequests];
660   ProxyResolver::RequestHandle request[kNumRequests];
661
662   for (size_t i = 0; i < kNumRequests; ++i) {
663     int rv = resolver.GetProxyForURL(
664         GURL("http://foo/"), &proxy_info[i],
665         base::Bind(&CrashCallback), &request[i], BoundNetLog());
666     EXPECT_EQ(ERR_IO_PENDING, rv);
667   }
668
669   for (size_t i = 0; i < kNumRequests; ++i) {
670     resolver.CancelRequest(request[i]);
671   }
672 }
673
674 // Note the execution order for this test can vary. Since multiple
675 // threads are involved, the cancellation may be received a different
676 // times.
677 TEST_F(ProxyResolverV8TracingTest, CancelSome) {
678   MockCachingHostResolver host_resolver;
679   MockErrorObserver* error_observer = new MockErrorObserver;
680   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
681
682   host_resolver.rules()->AddSimulatedFailure("*");
683
684   InitResolver(&resolver, "dns.js");
685
686   ProxyInfo proxy_info1;
687   ProxyInfo proxy_info2;
688   ProxyResolver::RequestHandle request1;
689   ProxyResolver::RequestHandle request2;
690   TestCompletionCallback callback;
691
692   int rv = resolver.GetProxyForURL(
693       GURL("http://foo/"), &proxy_info1,
694       base::Bind(&CrashCallback), &request1, BoundNetLog());
695   EXPECT_EQ(ERR_IO_PENDING, rv);
696
697   rv = resolver.GetProxyForURL(
698       GURL("http://foo/"), &proxy_info2,
699       callback.callback(), &request2, BoundNetLog());
700   EXPECT_EQ(ERR_IO_PENDING, rv);
701
702   resolver.CancelRequest(request1);
703
704   EXPECT_EQ(OK, callback.WaitForResult());
705 }
706
707 // Cancel a request after it has finished running on the worker thread, and has
708 // posted a task the completion task back to origin thread.
709 TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) {
710   MockCachingHostResolver host_resolver;
711   MockErrorObserver* error_observer = new MockErrorObserver;
712   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
713
714   host_resolver.rules()->AddSimulatedFailure("*");
715
716   InitResolver(&resolver, "error.js");
717
718   ProxyInfo proxy_info1;
719   ProxyInfo proxy_info2;
720   ProxyInfo proxy_info3;
721   ProxyResolver::RequestHandle request1;
722   ProxyResolver::RequestHandle request2;
723   ProxyResolver::RequestHandle request3;
724   TestCompletionCallback callback;
725
726   int rv = resolver.GetProxyForURL(
727       GURL("http://foo/"), &proxy_info1,
728       base::Bind(&CrashCallback), &request1, BoundNetLog());
729   EXPECT_EQ(ERR_IO_PENDING, rv);
730
731   rv = resolver.GetProxyForURL(
732       GURL("http://throw-an-error/"), &proxy_info2,
733       callback.callback(), &request2, BoundNetLog());
734   EXPECT_EQ(ERR_IO_PENDING, rv);
735
736   // Wait until the first request has finished running on the worker thread.
737   // (The second request will output an error).
738   error_observer->WaitForOutput();
739
740   // Cancel the first request, while it has a pending completion task on
741   // the origin thread.
742   resolver.CancelRequest(request1);
743
744   EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
745
746   // Start another request, to make sure it is able to complete.
747   rv = resolver.GetProxyForURL(
748       GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3,
749       callback.callback(), &request3, BoundNetLog());
750   EXPECT_EQ(ERR_IO_PENDING, rv);
751
752   EXPECT_EQ(OK, callback.WaitForResult());
753
754   EXPECT_EQ("i-approve-this-message:42",
755             proxy_info3.proxy_server().ToURI());
756 }
757
758 // This implementation of HostResolver allows blocking until a resolve request
759 // has been received. The resolve requests it receives will never be completed.
760 class BlockableHostResolver : public HostResolver {
761  public:
762   BlockableHostResolver()
763       : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
764
765   int Resolve(const RequestInfo& info,
766               RequestPriority priority,
767               AddressList* addresses,
768               const CompletionCallback& callback,
769               RequestHandle* out_req,
770               const BoundNetLog& net_log) override {
771     EXPECT_FALSE(callback.is_null());
772     EXPECT_TRUE(out_req);
773
774     if (!action_.is_null())
775       action_.Run();
776
777     // Indicate to the caller that a request was received.
778     EXPECT_TRUE(waiting_for_resolve_);
779     base::MessageLoop::current()->Quit();
780
781     // This line is intentionally after action_.Run(), since one of the
782     // tests does a cancellation inside of Resolve(), and it is more
783     // interesting if *out_req hasn't been written yet at that point.
784     *out_req = reinterpret_cast<RequestHandle*>(1);  // Magic value.
785
786     // Return ERR_IO_PENDING as this request will NEVER be completed.
787     // Expectation is for the caller to later cancel the request.
788     return ERR_IO_PENDING;
789   }
790
791   int ResolveFromCache(const RequestInfo& info,
792                        AddressList* addresses,
793                        const BoundNetLog& net_log) override {
794     NOTREACHED();
795     return ERR_DNS_CACHE_MISS;
796   }
797
798   void CancelRequest(RequestHandle req) override {
799     EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
800     num_cancelled_requests_++;
801   }
802
803   void SetAction(const base::Callback<void(void)>& action) {
804     action_ = action;
805   }
806
807   // Waits until Resolve() has been called.
808   void WaitUntilRequestIsReceived() {
809     waiting_for_resolve_ = true;
810     base::MessageLoop::current()->Run();
811     DCHECK(waiting_for_resolve_);
812     waiting_for_resolve_ = false;
813   }
814
815   int num_cancelled_requests() const {
816     return num_cancelled_requests_;
817   }
818
819  private:
820   int num_cancelled_requests_;
821   bool waiting_for_resolve_;
822   base::Callback<void(void)> action_;
823 };
824
825 // This cancellation test exercises a more predictable cancellation codepath --
826 // when the request has an outstanding DNS request in flight.
827 TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) {
828   BlockableHostResolver host_resolver;
829   MockErrorObserver* error_observer = new MockErrorObserver;
830   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
831
832   InitResolver(&resolver, "dns.js");
833
834   ProxyInfo proxy_info1;
835   ProxyInfo proxy_info2;
836   ProxyResolver::RequestHandle request1;
837   ProxyResolver::RequestHandle request2;
838
839   int rv = resolver.GetProxyForURL(
840       GURL("http://foo/req1"), &proxy_info1,
841       base::Bind(&CrashCallback), &request1, BoundNetLog());
842
843   EXPECT_EQ(ERR_IO_PENDING, rv);
844
845   host_resolver.WaitUntilRequestIsReceived();
846
847   rv = resolver.GetProxyForURL(
848       GURL("http://foo/req2"), &proxy_info2,
849       base::Bind(&CrashCallback), &request2, BoundNetLog());
850
851   EXPECT_EQ(ERR_IO_PENDING, rv);
852
853   host_resolver.WaitUntilRequestIsReceived();
854
855   resolver.CancelRequest(request1);
856   resolver.CancelRequest(request2);
857
858   EXPECT_EQ(2, host_resolver.num_cancelled_requests());
859
860   // After leaving this scope, the ProxyResolver is destroyed.
861   // This should not cause any problems, as the outstanding work
862   // should have been cancelled.
863 }
864
865 void CancelRequestAndPause(ProxyResolverV8Tracing* resolver,
866                            ProxyResolver::RequestHandle request) {
867   resolver->CancelRequest(request);
868
869   // Sleep for a little bit. This makes it more likely for the worker
870   // thread to have returned from its call, and serves as a regression
871   // test for http://crbug.com/173373.
872   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
873 }
874
875 // In non-blocking mode, the worker thread actually does block for
876 // a short time to see if the result is in the DNS cache. Test
877 // cancellation while the worker thread is waiting on this event.
878 TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) {
879   BlockableHostResolver host_resolver;
880   MockErrorObserver* error_observer = new MockErrorObserver;
881   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
882
883   InitResolver(&resolver, "dns.js");
884
885   ProxyInfo proxy_info;
886   ProxyResolver::RequestHandle request;
887
888   int rv = resolver.GetProxyForURL(
889       GURL("http://foo/"), &proxy_info,
890       base::Bind(&CrashCallback), &request, BoundNetLog());
891
892   EXPECT_EQ(ERR_IO_PENDING, rv);
893
894   host_resolver.SetAction(
895       base::Bind(CancelRequestAndPause, &resolver, request));
896
897   host_resolver.WaitUntilRequestIsReceived();
898
899   // At this point the host resolver ran Resolve(), and should have cancelled
900   // the request.
901
902   EXPECT_EQ(1, host_resolver.num_cancelled_requests());
903 }
904
905 // Cancel the request while there is a pending DNS request, however before
906 // the request is sent to the host resolver.
907 TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) {
908   MockCachingHostResolver host_resolver;
909   MockErrorObserver* error_observer = new MockErrorObserver;
910   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
911
912   InitResolver(&resolver, "dns.js");
913
914   ProxyInfo proxy_info;
915   ProxyResolver::RequestHandle request;
916
917   int rv = resolver.GetProxyForURL(
918       GURL("http://foo/"), &proxy_info,
919       base::Bind(&CrashCallback), &request, BoundNetLog());
920
921   EXPECT_EQ(ERR_IO_PENDING, rv);
922
923   // Wait a bit, so the DNS task has hopefully been posted. The test will
924   // work whatever the delay is here, but it is most useful if the delay
925   // is large enough to allow a task to be posted back.
926   base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
927   resolver.CancelRequest(request);
928
929   EXPECT_EQ(0u, host_resolver.num_resolve());
930 }
931
932 TEST_F(ProxyResolverV8TracingTest, CancelSetPacWhileOutstandingBlockingDns) {
933   BlockableHostResolver host_resolver;
934   MockErrorObserver* error_observer = new MockErrorObserver;
935
936   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
937
938   int rv =
939       resolver.SetPacScript(LoadScriptData("dns_during_init.js"),
940       base::Bind(&CrashCallback));
941   EXPECT_EQ(ERR_IO_PENDING, rv);
942
943   host_resolver.WaitUntilRequestIsReceived();
944
945   resolver.CancelSetPacScript();
946   EXPECT_EQ(1, host_resolver.num_cancelled_requests());
947 }
948
949 // This tests that the execution of a PAC script is terminated when the DNS
950 // dependencies are missing. If the test fails, then it will hang.
951 TEST_F(ProxyResolverV8TracingTest, Terminate) {
952   CapturingNetLog log;
953   CapturingBoundNetLog request_log;
954   MockCachingHostResolver host_resolver;
955   MockErrorObserver* error_observer = new MockErrorObserver;
956   ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
957
958   host_resolver.rules()->AddRule("host1", "182.111.0.222");
959   host_resolver.rules()->AddRule("host2", "111.33.44.55");
960
961   InitResolver(&resolver, "terminate.js");
962
963   TestCompletionCallback callback;
964   ProxyInfo proxy_info;
965
966   int rv = resolver.GetProxyForURL(
967       GURL("http://foopy/req1"),
968       &proxy_info,
969       callback.callback(),
970       NULL,
971       request_log.bound());
972
973   EXPECT_EQ(ERR_IO_PENDING, rv);
974   EXPECT_EQ(OK, callback.WaitForResult());
975
976   // The test does 2 DNS resolutions.
977   EXPECT_EQ(2u, host_resolver.num_resolve());
978
979   EXPECT_EQ("foopy:3", proxy_info.proxy_server().ToURI());
980
981   // No errors.
982   EXPECT_EQ("", error_observer->GetOutput());
983
984   EXPECT_EQ(0u, log.GetSize());
985   EXPECT_EQ(0u, request_log.GetSize());
986 }
987
988 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
989 // correctly at the same time. This is relevant because at the moment (time
990 // this test was written) each ProxyResolverV8Tracing creates its own thread to
991 // run V8 on, however each thread is operating on the same v8::Isolate.
992 TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) {
993   // ------------------------
994   // Setup resolver0
995   // ------------------------
996   MockHostResolver host_resolver0;
997   host_resolver0.rules()->AddRuleForAddressFamily(
998       "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
999   host_resolver0.rules()
1000       ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
1001   host_resolver0.rules()->AddSimulatedFailure("host2");
1002   host_resolver0.rules()->AddRule("host3", "166.155.144.33");
1003   host_resolver0.rules()->AddRule("host5", "166.155.144.55");
1004   host_resolver0.rules()->AddSimulatedFailure("host6");
1005   host_resolver0.rules()->AddRuleForAddressFamily(
1006       "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
1007   host_resolver0.rules()->AddRule("*", "133.122.100.200");
1008   ProxyResolverV8Tracing resolver0(
1009       &host_resolver0, new MockErrorObserver, NULL);
1010   InitResolver(&resolver0, "dns.js");
1011
1012   // ------------------------
1013   // Setup resolver1
1014   // ------------------------
1015   ProxyResolverV8Tracing resolver1(
1016       &host_resolver0, new MockErrorObserver, NULL);
1017   InitResolver(&resolver1, "dns.js");
1018
1019   // ------------------------
1020   // Setup resolver2
1021   // ------------------------
1022   ProxyResolverV8Tracing resolver2(
1023       &host_resolver0, new MockErrorObserver, NULL);
1024   InitResolver(&resolver2, "simple.js");
1025
1026   // ------------------------
1027   // Setup resolver3
1028   // ------------------------
1029   MockHostResolver host_resolver3;
1030   host_resolver3.rules()->AddRule("foo", "166.155.144.33");
1031   ProxyResolverV8Tracing resolver3(
1032       &host_resolver3, new MockErrorObserver, NULL);
1033   InitResolver(&resolver3, "simple_dns.js");
1034
1035   // ------------------------
1036   // Queue up work for each resolver (which will be running in parallel).
1037   // ------------------------
1038
1039   ProxyResolverV8Tracing* resolver[] = {
1040     &resolver0, &resolver1, &resolver2, &resolver3,
1041   };
1042
1043   const size_t kNumResolvers = arraysize(resolver);
1044   const size_t kNumIterations = 20;
1045   const size_t kNumResults = kNumResolvers * kNumIterations;
1046   TestCompletionCallback callback[kNumResults];
1047   ProxyInfo proxy_info[kNumResults];
1048
1049   for (size_t i = 0; i < kNumResults; ++i) {
1050     size_t resolver_i = i % kNumResolvers;
1051     int rv = resolver[resolver_i]->GetProxyForURL(
1052         GURL("http://foo/"), &proxy_info[i], callback[i].callback(), NULL,
1053         BoundNetLog());
1054     EXPECT_EQ(ERR_IO_PENDING, rv);
1055   }
1056
1057   // ------------------------
1058   // Verify all of the results.
1059   // ------------------------
1060
1061   const char* kExpectedForDnsJs =
1062     "122.133.144.155-"  // myIpAddress()
1063     "null-"  // dnsResolve('')
1064     "__1_192.168.1.1-"  // dnsResolveEx('host1')
1065     "null-"  // dnsResolve('host2')
1066     "166.155.144.33-"  // dnsResolve('host3')
1067     "122.133.144.155-"  // myIpAddress()
1068     "166.155.144.33-"  // dnsResolve('host3')
1069     "__1_192.168.1.1-"  // dnsResolveEx('host1')
1070     "122.133.144.155-"  // myIpAddress()
1071     "null-"  // dnsResolve('host2')
1072     "-"  // dnsResolveEx('host6')
1073     "133.122.100.200-"  // myIpAddressEx()
1074     "166.155.144.44"  // dnsResolve('host1')
1075     ":99";
1076
1077   for (size_t i = 0; i < kNumResults; ++i) {
1078     size_t resolver_i = i % kNumResolvers;
1079     EXPECT_EQ(OK, callback[i].WaitForResult());
1080
1081     std::string proxy_uri = proxy_info[i].proxy_server().ToURI();
1082
1083     if (resolver_i == 0 || resolver_i == 1) {
1084       EXPECT_EQ(kExpectedForDnsJs, proxy_uri);
1085     } else if (resolver_i == 2) {
1086       EXPECT_EQ("foo:99", proxy_uri);
1087     } else if (resolver_i == 3) {
1088       EXPECT_EQ("166.155.144.33:",
1089                 proxy_uri.substr(0, proxy_uri.find(':') + 1));
1090     } else {
1091       NOTREACHED();
1092     }
1093   }
1094 }
1095
1096 }  // namespace
1097
1098 }  // namespace net