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