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