| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/proxy_resolution/proxy_resolver_v8_tracing_wrapper.h" |
| |
| #include <string> |
| |
| #include "base/files/file_util.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/path_service.h" |
| #include "base/run_loop.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/values.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/test_completion_callback.h" |
| #include "net/dns/host_cache.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/log/net_log_event_type.h" |
| #include "net/log/net_log_with_source.h" |
| #include "net/log/test_net_log.h" |
| #include "net/log/test_net_log_entry.h" |
| #include "net/log/test_net_log_util.h" |
| #include "net/proxy_resolution/proxy_info.h" |
| #include "net/proxy_resolution/proxy_resolver_error_observer.h" |
| #include "net/test/event_waiter.h" |
| #include "net/test/gtest_util.h" |
| #include "net/test/test_with_scoped_task_environment.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| using net::test::IsError; |
| using net::test::IsOk; |
| |
| namespace net { |
| |
| namespace { |
| |
| class ProxyResolverV8TracingWrapperTest : public TestWithScopedTaskEnvironment { |
| public: |
| void TearDown() override { |
| // Drain any pending messages, which may be left over from cancellation. |
| // This way they get reliably run as part of the current test, rather than |
| // spilling into the next test's execution. |
| base::RunLoop().RunUntilIdle(); |
| } |
| }; |
| |
| scoped_refptr<PacFileData> LoadScriptData(const char* filename) { |
| base::FilePath path; |
| base::PathService::Get(base::DIR_TEST_DATA, &path); |
| path = path.AppendASCII("net"); |
| path = path.AppendASCII("data"); |
| path = path.AppendASCII("proxy_resolver_v8_tracing_unittest"); |
| path = path.AppendASCII(filename); |
| |
| // Try to read the file from disk. |
| std::string file_contents; |
| bool ok = base::ReadFileToString(path, &file_contents); |
| |
| // If we can't load the file from disk, something is misconfigured. |
| EXPECT_TRUE(ok) << "Failed to read file: " << path.value(); |
| |
| // Load the PAC script into the ProxyResolver. |
| return PacFileData::FromUTF8(file_contents); |
| } |
| |
| std::unique_ptr<ProxyResolverErrorObserver> ReturnErrorObserver( |
| std::unique_ptr<ProxyResolverErrorObserver> error_observer) { |
| return error_observer; |
| } |
| |
| std::unique_ptr<ProxyResolver> CreateResolver( |
| NetLog* net_log, |
| HostResolver* host_resolver, |
| std::unique_ptr<ProxyResolverErrorObserver> error_observer, |
| const char* filename) { |
| std::unique_ptr<ProxyResolver> resolver; |
| ProxyResolverFactoryV8TracingWrapper factory( |
| host_resolver, net_log, |
| base::Bind(&ReturnErrorObserver, base::Passed(&error_observer))); |
| TestCompletionCallback callback; |
| std::unique_ptr<ProxyResolverFactory::Request> request; |
| int rv = factory.CreateProxyResolver(LoadScriptData(filename), &resolver, |
| callback.callback(), &request); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| EXPECT_TRUE(resolver); |
| return resolver; |
| } |
| |
| class MockErrorObserver : public ProxyResolverErrorObserver { |
| public: |
| void OnPACScriptError(int line_number, const base::string16& error) override { |
| output += base::StringPrintf("Error: line %d: %s\n", line_number, |
| base::UTF16ToASCII(error).c_str()); |
| waiter_.NotifyEvent(EVENT_ERROR); |
| if (!error_callback_.is_null()) |
| error_callback_.Run(); |
| } |
| |
| std::string GetOutput() { |
| return output; |
| } |
| |
| void RunOnError(const base::Closure& callback) { |
| error_callback_ = callback; |
| waiter_.WaitForEvent(EVENT_ERROR); |
| } |
| |
| private: |
| enum Event { |
| EVENT_ERROR, |
| }; |
| std::string output; |
| |
| base::Closure error_callback_; |
| EventWaiter<Event> waiter_; |
| }; |
| |
| TEST_F(ProxyResolverV8TracingWrapperTest, Simple) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| &log, &host_resolver, base::WrapUnique(error_observer), "simple.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI()); |
| |
| EXPECT_EQ(0u, host_resolver.num_resolve()); |
| |
| // There were no errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- nothing was logged. |
| EXPECT_EQ(0u, log.GetSize()); |
| EXPECT_EQ(0u, request_log.GetSize()); |
| } |
| |
| TEST_F(ProxyResolverV8TracingWrapperTest, JavascriptError) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| &log, &host_resolver, base::WrapUnique(error_observer), "error.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED)); |
| |
| EXPECT_EQ(0u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ( |
| "Error: line 5: Uncaught TypeError: Cannot read property 'split' " |
| "of null\n", |
| error_observer->GetOutput()); |
| |
| // Check the NetLogs -- there was 1 alert and 1 javascript error, and they |
| // were output to both the global log, and per-request log. |
| TestNetLogEntry::List entries_list[2]; |
| log.GetEntries(&entries_list[0]); |
| request_log.GetEntries(&entries_list[1]); |
| |
| for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) { |
| const TestNetLogEntry::List& entries = entries_list[list_i]; |
| EXPECT_EQ(2u, entries.size()); |
| EXPECT_TRUE(LogContainsEvent(entries, 0, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| EXPECT_TRUE(LogContainsEvent(entries, 1, |
| NetLogEventType::PAC_JAVASCRIPT_ERROR, |
| NetLogEventPhase::NONE)); |
| |
| EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries[0].GetParamsJson()); |
| EXPECT_EQ( |
| "{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot " |
| "read property 'split' of null\"}", |
| entries[1].GetParamsJson()); |
| } |
| } |
| |
| TEST_F(ProxyResolverV8TracingWrapperTest, TooManyAlerts) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "too_many_alerts.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| // Iteration1 does a DNS resolve |
| // Iteration2 exceeds the alert buffer |
| // Iteration3 runs in blocking mode and completes |
| EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI()); |
| |
| EXPECT_EQ(1u, host_resolver.num_resolve()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- the script generated 50 alerts, which were mirrored |
| // to both the global and per-request logs. |
| TestNetLogEntry::List entries_list[2]; |
| log.GetEntries(&entries_list[0]); |
| request_log.GetEntries(&entries_list[1]); |
| |
| for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) { |
| const TestNetLogEntry::List& entries = entries_list[list_i]; |
| EXPECT_EQ(50u, entries.size()); |
| for (size_t i = 0; i < entries.size(); ++i) { |
| ASSERT_TRUE(LogContainsEvent(entries, i, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| } |
| } |
| } |
| |
| // Verify that buffered alerts cannot grow unboundedly, even when the message is |
| // empty string. |
| TEST_F(ProxyResolverV8TracingWrapperTest, TooManyEmptyAlerts) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "too_many_empty_alerts.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI()); |
| |
| EXPECT_EQ(1u, host_resolver.num_resolve()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- the script generated 50 alerts, which were mirrored |
| // to both the global and per-request logs. |
| TestNetLogEntry::List entries_list[2]; |
| log.GetEntries(&entries_list[0]); |
| request_log.GetEntries(&entries_list[1]); |
| |
| for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) { |
| const TestNetLogEntry::List& entries = entries_list[list_i]; |
| EXPECT_EQ(1000u, entries.size()); |
| for (size_t i = 0; i < entries.size(); ++i) { |
| ASSERT_TRUE(LogContainsEvent(entries, i, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| } |
| } |
| } |
| |
| // This test runs a PAC script that issues a sequence of DNS resolves. The test |
| // verifies the final result, and that the underlying DNS resolver received |
| // the correct set of queries. |
| TEST_F(ProxyResolverV8TracingWrapperTest, Dns) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRuleForAddressFamily("host1", ADDRESS_FAMILY_IPV4, |
| "166.155.144.44"); |
| host_resolver.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1", |
| std::string()); |
| host_resolver.rules()->AddSimulatedFailure("host2"); |
| host_resolver.rules()->AddRule("host3", "166.155.144.33"); |
| host_resolver.rules()->AddRule("host5", "166.155.144.55"); |
| host_resolver.rules()->AddSimulatedFailure("host6"); |
| host_resolver.rules()->AddRuleForAddressFamily("*", ADDRESS_FAMILY_IPV4, |
| "122.133.144.155"); |
| host_resolver.rules()->AddRule("*", "133.122.100.200"); |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| &log, &host_resolver, base::WrapUnique(error_observer), "dns.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| // The test does 13 DNS resolution, however only 7 of them are unique. |
| EXPECT_EQ(7u, host_resolver.num_resolve()); |
| |
| const char* kExpectedResult = |
| "122.133.144.155-" // myIpAddress() |
| "null-" // dnsResolve('') |
| "__1_192.168.1.1-" // dnsResolveEx('host1') |
| "null-" // dnsResolve('host2') |
| "166.155.144.33-" // dnsResolve('host3') |
| "122.133.144.155-" // myIpAddress() |
| "166.155.144.33-" // dnsResolve('host3') |
| "__1_192.168.1.1-" // dnsResolveEx('host1') |
| "122.133.144.155-" // myIpAddress() |
| "null-" // dnsResolve('host2') |
| "-" // dnsResolveEx('host6') |
| "133.122.100.200-" // myIpAddressEx() |
| "166.155.144.44" // dnsResolve('host1') |
| ":99"; |
| |
| EXPECT_EQ(kExpectedResult, proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- the script generated 1 alert, mirrored to both |
| // the per-request and global logs. |
| TestNetLogEntry::List entries_list[2]; |
| log.GetEntries(&entries_list[0]); |
| request_log.GetEntries(&entries_list[1]); |
| |
| for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) { |
| const TestNetLogEntry::List& entries = entries_list[list_i]; |
| EXPECT_EQ(1u, entries.size()); |
| EXPECT_TRUE(LogContainsEvent(entries, 0, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson()); |
| } |
| } |
| |
| // This test runs a PAC script that does "myIpAddress()" followed by |
| // "dnsResolve()". This requires 2 restarts. However once the HostResolver's |
| // cache is warmed, subsequent calls should take 0 restarts. |
| TEST_F(ProxyResolverV8TracingWrapperTest, DnsChecksCache) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("foopy", "166.155.144.11"); |
| host_resolver.rules()->AddRule("*", "122.133.144.155"); |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| &log, &host_resolver, base::WrapUnique(error_observer), "simple_dns.js"); |
| |
| TestCompletionCallback callback1; |
| TestCompletionCallback callback2; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, |
| callback1.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback1.WaitForResult(), IsOk()); |
| |
| // The test does 2 DNS resolutions. |
| EXPECT_EQ(2u, host_resolver.num_resolve()); |
| |
| // The first request took 2 restarts, hence on g_iteration=3. |
| EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI()); |
| |
| std::unique_ptr<ProxyResolver::Request> req2; |
| rv = resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info, |
| callback2.callback(), &req2, |
| request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback2.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ(4u, host_resolver.num_resolve()); |
| |
| // This time no restarts were required, so g_iteration incremented by 1. |
| EXPECT_EQ("166.155.144.11:4", proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| EXPECT_EQ(0u, log.GetSize()); |
| EXPECT_EQ(0u, request_log.GetSize()); |
| } |
| |
| // This test runs a weird PAC script that was designed to defeat the DNS tracing |
| // optimization. The proxy resolver should detect the inconsistency and |
| // fall-back to synchronous mode execution. |
| TEST_F(ProxyResolverV8TracingWrapperTest, FallBackToSynchronous1) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("host1", "166.155.144.11"); |
| host_resolver.rules()->AddRule("crazy4", "133.199.111.4"); |
| host_resolver.rules()->AddRule("*", "122.133.144.155"); |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "global_sideffects1.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| // The script itself only does 2 DNS resolves per execution, however it |
| // constructs the hostname using a global counter which changes on each |
| // invocation. |
| EXPECT_EQ(3u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ("166.155.144.11-133.199.111.4:100", |
| proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- the script generated 1 alert, mirrored to both |
| // the per-request and global logs. |
| TestNetLogEntry::List entries_list[2]; |
| log.GetEntries(&entries_list[0]); |
| request_log.GetEntries(&entries_list[1]); |
| |
| for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) { |
| const TestNetLogEntry::List& entries = entries_list[list_i]; |
| EXPECT_EQ(1u, entries.size()); |
| EXPECT_TRUE(LogContainsEvent(entries, 0, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson()); |
| } |
| } |
| |
| // This test runs a weird PAC script that was designed to defeat the DNS tracing |
| // optimization. The proxy resolver should detect the inconsistency and |
| // fall-back to synchronous mode execution. |
| TEST_F(ProxyResolverV8TracingWrapperTest, FallBackToSynchronous2) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("host1", "166.155.144.11"); |
| host_resolver.rules()->AddRule("host2", "166.155.144.22"); |
| host_resolver.rules()->AddRule("host3", "166.155.144.33"); |
| host_resolver.rules()->AddRule("host4", "166.155.144.44"); |
| host_resolver.rules()->AddRule("*", "122.133.144.155"); |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "global_sideffects2.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ(3u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ("166.155.144.44:100", proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- nothing was logged. |
| EXPECT_EQ(0u, log.GetSize()); |
| EXPECT_EQ(0u, request_log.GetSize()); |
| } |
| |
| // This test runs a weird PAC script that yields a never ending sequence |
| // of DNS resolves when restarting. Running it will hit the maximum |
| // DNS resolves per request limit (20) after which every DNS resolve will |
| // fail. |
| TEST_F(ProxyResolverV8TracingWrapperTest, InfiniteDNSSequence) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("host*", "166.155.144.11"); |
| host_resolver.rules()->AddRule("*", "122.133.144.155"); |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "global_sideffects3.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| |
| callback.callback(), &req, request_log.bound()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ(20u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ( |
| "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-" |
| "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-" |
| "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-" |
| "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-" |
| "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-" |
| "null:21", |
| proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- 1 alert was logged. |
| EXPECT_EQ(1u, log.GetSize()); |
| EXPECT_EQ(1u, request_log.GetSize()); |
| } |
| |
| // This test runs a weird PAC script that yields a never ending sequence |
| // of DNS resolves when restarting. Running it will hit the maximum |
| // DNS resolves per request limit (20) after which every DNS resolve will |
| // fail. |
| TEST_F(ProxyResolverV8TracingWrapperTest, InfiniteDNSSequence2) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("host*", "166.155.144.11"); |
| host_resolver.rules()->AddRule("*", "122.133.144.155"); |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "global_sideffects4.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ(20u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ("null21:34", proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| // Check the NetLogs -- 1 alert was logged. |
| EXPECT_EQ(1u, log.GetSize()); |
| EXPECT_EQ(1u, request_log.GetSize()); |
| } |
| |
| void DnsDuringInitHelper(bool synchronous_host_resolver) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| host_resolver.set_synchronous_mode(synchronous_host_resolver); |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("host1", "91.13.12.1"); |
| host_resolver.rules()->AddRule("host2", "91.13.12.2"); |
| |
| std::unique_ptr<ProxyResolver> resolver = |
| CreateResolver(&log, &host_resolver, base::WrapUnique(error_observer), |
| "dns_during_init.js"); |
| |
| // Initialization did 2 dnsResolves. |
| EXPECT_EQ(2u, host_resolver.num_resolve()); |
| |
| host_resolver.rules()->ClearRules(); |
| host_resolver.GetHostCache()->clear(); |
| |
| host_resolver.rules()->AddRule("host1", "145.88.13.3"); |
| host_resolver.rules()->AddRule("host2", "137.89.8.45"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| // Fetched host1 and host2 again, since the ones done during initialization |
| // should not have been cached. |
| EXPECT_EQ(4u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99", |
| proxy_info.proxy_server().ToURI()); |
| |
| // Check the NetLogs -- the script generated 2 alerts during initialization. |
| EXPECT_EQ(0u, request_log.GetSize()); |
| TestNetLogEntry::List entries; |
| log.GetEntries(&entries); |
| |
| ASSERT_EQ(2u, entries.size()); |
| EXPECT_TRUE(LogContainsEvent(entries, 0, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| EXPECT_TRUE(LogContainsEvent(entries, 1, |
| NetLogEventType::PAC_JAVASCRIPT_ALERT, |
| NetLogEventPhase::NONE)); |
| |
| EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson()); |
| EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson()); |
| } |
| |
| // Tests a PAC script which does DNS resolves during initialization. |
| TEST_F(ProxyResolverV8TracingWrapperTest, DnsDuringInit) { |
| // Test with both both a host resolver that always completes asynchronously, |
| // and then again with one that completes synchronously. |
| DnsDuringInitHelper(false); |
| DnsDuringInitHelper(true); |
| } |
| |
| void CrashCallback(int) { |
| // Be extra sure that if the callback ever gets invoked, the test will fail. |
| CHECK(false); |
| } |
| |
| // Start some requests, cancel them all, and then destroy the resolver. |
| // Note the execution order for this test can vary. Since multiple |
| // threads are involved, the cancellation may be received a different |
| // times. |
| TEST_F(ProxyResolverV8TracingWrapperTest, CancelAll) { |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddSimulatedFailure("*"); |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| nullptr, &host_resolver, base::WrapUnique(error_observer), "dns.js"); |
| |
| const size_t kNumRequests = 5; |
| ProxyInfo proxy_info[kNumRequests]; |
| std::unique_ptr<ProxyResolver::Request> request[kNumRequests]; |
| |
| for (size_t i = 0; i < kNumRequests; ++i) { |
| int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info[i], |
| base::Bind(&CrashCallback), &request[i], |
| NetLogWithSource()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| } |
| |
| for (size_t i = 0; i < kNumRequests; ++i) { |
| request[i].reset(); |
| } |
| } |
| |
| // Note the execution order for this test can vary. Since multiple |
| // threads are involved, the cancellation may be received a different |
| // times. |
| TEST_F(ProxyResolverV8TracingWrapperTest, CancelSome) { |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddSimulatedFailure("*"); |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| nullptr, &host_resolver, base::WrapUnique(error_observer), "dns.js"); |
| |
| ProxyInfo proxy_info1; |
| ProxyInfo proxy_info2; |
| std::unique_ptr<ProxyResolver::Request> request1; |
| std::unique_ptr<ProxyResolver::Request> request2; |
| TestCompletionCallback callback; |
| |
| int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, |
| base::Bind(&CrashCallback), &request1, |
| NetLogWithSource()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2, |
| callback.callback(), &request2, |
| NetLogWithSource()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| request1.reset(); |
| |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| } |
| |
| // Cancel a request after it has finished running on the worker thread, and has |
| // posted a task the completion task back to origin thread. |
| TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhilePendingCompletionTask) { |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddSimulatedFailure("*"); |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| nullptr, &host_resolver, base::WrapUnique(error_observer), "error.js"); |
| |
| ProxyInfo proxy_info1; |
| ProxyInfo proxy_info2; |
| std::unique_ptr<ProxyResolver::Request> request1; |
| std::unique_ptr<ProxyResolver::Request> request2; |
| TestCompletionCallback callback; |
| |
| int rv = resolver->GetProxyForURL(GURL("http://throw-an-error/"), |
| &proxy_info1, base::Bind(&CrashCallback), |
| &request1, NetLogWithSource()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| // Wait until the first request has finished running on the worker thread. |
| // Cancel the first request, while it has a pending completion task on |
| // the origin thread. Reset deletes Request object which cancels the request. |
| error_observer->RunOnError( |
| base::Bind(&std::unique_ptr<ProxyResolver::Request>::reset, |
| base::Unretained(&request1), nullptr)); |
| |
| // Start another request, to make sure it is able to complete. |
| rv = resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"), |
| &proxy_info2, callback.callback(), &request2, |
| NetLogWithSource()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| EXPECT_EQ("i-approve-this-message:42", proxy_info2.proxy_server().ToURI()); |
| } |
| |
| // This implementation of HostResolver allows blocking until a resolve request |
| // has been received. The resolve requests it receives will never be completed. |
| class BlockableHostResolver : public HostResolver { |
| public: |
| BlockableHostResolver() |
| : num_cancelled_requests_(0), waiting_for_resolve_(false) {} |
| |
| std::unique_ptr<ResolveHostRequest> CreateRequest( |
| const HostPortPair& host, |
| const NetLogWithSource& net_log, |
| const base::Optional<ResolveHostParameters>& optional_parameters) |
| override { |
| NOTIMPLEMENTED(); |
| return nullptr; |
| } |
| |
| int Resolve(const RequestInfo& info, |
| RequestPriority priority, |
| AddressList* addresses, |
| CompletionOnceCallback callback, |
| std::unique_ptr<Request>* out_req, |
| const NetLogWithSource& net_log) override { |
| EXPECT_FALSE(callback.is_null()); |
| EXPECT_TRUE(out_req); |
| |
| if (!action_.is_null()) |
| action_.Run(); |
| |
| // Indicate to the caller that a request was received. |
| EXPECT_TRUE(waiting_for_resolve_); |
| base::RunLoop::QuitCurrentWhenIdleDeprecated(); |
| |
| // This line is intentionally after action_.Run(), since one of the |
| // tests does a cancellation inside of Resolve(), and it is more |
| // interesting if *out_req hasn't been written yet at that point. |
| out_req->reset(new RequestImpl(this)); |
| |
| // Return ERR_IO_PENDING as this request will NEVER be completed. |
| // Expectation is for the caller to later cancel the request. |
| return ERR_IO_PENDING; |
| } |
| |
| int ResolveFromCache(const RequestInfo& info, |
| AddressList* addresses, |
| const NetLogWithSource& net_log) override { |
| NOTREACHED(); |
| return ERR_DNS_CACHE_MISS; |
| } |
| |
| int ResolveStaleFromCache(const RequestInfo& info, |
| AddressList* addresses, |
| HostCache::EntryStaleness* stale_info, |
| const NetLogWithSource& net_log) override { |
| NOTREACHED(); |
| return ERR_DNS_CACHE_MISS; |
| } |
| |
| bool HasCached(base::StringPiece hostname, |
| HostCache::Entry::Source* source_out, |
| HostCache::EntryStaleness* stale_out) const override { |
| NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void IncreaseNumOfCancelledRequests() { num_cancelled_requests_++; } |
| |
| void SetAction(const base::Callback<void(void)>& action) { action_ = action; } |
| |
| // Waits until Resolve() has been called. |
| void WaitUntilRequestIsReceived() { |
| waiting_for_resolve_ = true; |
| base::RunLoop().Run(); |
| DCHECK(waiting_for_resolve_); |
| waiting_for_resolve_ = false; |
| } |
| |
| int num_cancelled_requests() const { return num_cancelled_requests_; } |
| |
| private: |
| class RequestImpl : public HostResolver::Request { |
| public: |
| RequestImpl(BlockableHostResolver* resolver) : resolver_(resolver) {} |
| |
| ~RequestImpl() override { |
| if (resolver_) |
| resolver_->IncreaseNumOfCancelledRequests(); |
| } |
| |
| void ChangeRequestPriority(RequestPriority priority) override {} |
| |
| private: |
| BlockableHostResolver* resolver_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RequestImpl); |
| }; |
| |
| int num_cancelled_requests_; |
| bool waiting_for_resolve_; |
| base::Callback<void(void)> action_; |
| }; |
| |
| // This cancellation test exercises a more predictable cancellation codepath -- |
| // when the request has an outstanding DNS request in flight. |
| TEST_F(ProxyResolverV8TracingWrapperTest, |
| CancelWhileOutstandingNonBlockingDns) { |
| BlockableHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| nullptr, &host_resolver, base::WrapUnique(error_observer), "dns.js"); |
| |
| ProxyInfo proxy_info1; |
| ProxyInfo proxy_info2; |
| std::unique_ptr<ProxyResolver::Request> request1; |
| std::unique_ptr<ProxyResolver::Request> request2; |
| |
| int rv = resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1, |
| base::Bind(&CrashCallback), &request1, |
| NetLogWithSource()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| host_resolver.WaitUntilRequestIsReceived(); |
| |
| rv = resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2, |
| base::Bind(&CrashCallback), &request2, |
| NetLogWithSource()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| host_resolver.WaitUntilRequestIsReceived(); |
| |
| request1.reset(); |
| request2.reset(); |
| |
| EXPECT_EQ(2, host_resolver.num_cancelled_requests()); |
| |
| // After leaving this scope, the ProxyResolver is destroyed. |
| // This should not cause any problems, as the outstanding work |
| // should have been cancelled. |
| } |
| |
| void CancelRequestAndPause(std::unique_ptr<ProxyResolver::Request>* request) { |
| request->reset(); |
| |
| // Sleep for a little bit. This makes it more likely for the worker |
| // thread to have returned from its call, and serves as a regression |
| // test for http://crbug.com/173373. |
| base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30)); |
| } |
| |
| // In non-blocking mode, the worker thread actually does block for |
| // a short time to see if the result is in the DNS cache. Test |
| // cancellation while the worker thread is waiting on this event. |
| TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhileBlockedInNonBlockingDns) { |
| BlockableHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| nullptr, &host_resolver, base::WrapUnique(error_observer), "dns.js"); |
| |
| ProxyInfo proxy_info; |
| std::unique_ptr<ProxyResolver::Request> request; |
| |
| int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| base::Bind(&CrashCallback), &request, |
| NetLogWithSource()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| host_resolver.SetAction(base::Bind(CancelRequestAndPause, &request)); |
| |
| host_resolver.WaitUntilRequestIsReceived(); |
| } |
| |
| // Cancel the request while there is a pending DNS request, however before |
| // the request is sent to the host resolver. |
| TEST_F(ProxyResolverV8TracingWrapperTest, CancelWhileBlockedInNonBlockingDns2) { |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| nullptr, &host_resolver, base::WrapUnique(error_observer), "dns.js"); |
| |
| ProxyInfo proxy_info; |
| std::unique_ptr<ProxyResolver::Request> request; |
| |
| int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, |
| base::Bind(&CrashCallback), &request, |
| NetLogWithSource()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| // Wait a bit, so the DNS task has hopefully been posted. The test will |
| // work whatever the delay is here, but it is most useful if the delay |
| // is large enough to allow a task to be posted back. |
| base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); |
| request.reset(); |
| |
| EXPECT_EQ(0u, host_resolver.num_resolve()); |
| } |
| |
| TEST_F(ProxyResolverV8TracingWrapperTest, |
| CancelCreateResolverWhileOutstandingBlockingDns) { |
| BlockableHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| ProxyResolverFactoryV8TracingWrapper factory( |
| &host_resolver, nullptr, |
| base::Bind(&ReturnErrorObserver, |
| base::Passed(base::WrapUnique(error_observer)))); |
| |
| std::unique_ptr<ProxyResolver> resolver; |
| std::unique_ptr<ProxyResolverFactory::Request> request; |
| int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), |
| &resolver, base::Bind(&CrashCallback), |
| &request); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| |
| host_resolver.WaitUntilRequestIsReceived(); |
| |
| request.reset(); |
| EXPECT_EQ(1, host_resolver.num_cancelled_requests()); |
| } |
| |
| TEST_F(ProxyResolverV8TracingWrapperTest, |
| DeleteFactoryWhileOutstandingBlockingDns) { |
| BlockableHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| std::unique_ptr<ProxyResolver> resolver; |
| std::unique_ptr<ProxyResolverFactory::Request> request; |
| { |
| ProxyResolverFactoryV8TracingWrapper factory( |
| &host_resolver, nullptr, |
| base::Bind(&ReturnErrorObserver, |
| base::Passed(base::WrapUnique(error_observer)))); |
| |
| int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), |
| &resolver, base::Bind(&CrashCallback), |
| &request); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| host_resolver.WaitUntilRequestIsReceived(); |
| } |
| EXPECT_EQ(1, host_resolver.num_cancelled_requests()); |
| } |
| |
| TEST_F(ProxyResolverV8TracingWrapperTest, ErrorLoadingScript) { |
| BlockableHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| ProxyResolverFactoryV8TracingWrapper factory( |
| &host_resolver, nullptr, |
| base::Bind(&ReturnErrorObserver, |
| base::Passed(base::WrapUnique(error_observer)))); |
| |
| std::unique_ptr<ProxyResolver> resolver; |
| std::unique_ptr<ProxyResolverFactory::Request> request; |
| TestCompletionCallback callback; |
| int rv = |
| factory.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver, |
| callback.callback(), &request); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PAC_SCRIPT_FAILED)); |
| EXPECT_FALSE(resolver); |
| } |
| |
| // This tests that the execution of a PAC script is terminated when the DNS |
| // dependencies are missing. If the test fails, then it will hang. |
| TEST_F(ProxyResolverV8TracingWrapperTest, Terminate) { |
| TestNetLog log; |
| BoundTestNetLog request_log; |
| MockCachingHostResolver host_resolver; |
| MockErrorObserver* error_observer = new MockErrorObserver; |
| |
| host_resolver.rules()->AddRule("host1", "182.111.0.222"); |
| host_resolver.rules()->AddRule("host2", "111.33.44.55"); |
| |
| std::unique_ptr<ProxyResolver> resolver = CreateResolver( |
| &log, &host_resolver, base::WrapUnique(error_observer), "terminate.js"); |
| |
| TestCompletionCallback callback; |
| ProxyInfo proxy_info; |
| |
| std::unique_ptr<ProxyResolver::Request> req; |
| int rv = |
| resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, |
| callback.callback(), &req, request_log.bound()); |
| |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| EXPECT_THAT(callback.WaitForResult(), IsOk()); |
| |
| // The test does 2 DNS resolutions. |
| EXPECT_EQ(2u, host_resolver.num_resolve()); |
| |
| EXPECT_EQ("foopy:3", proxy_info.proxy_server().ToURI()); |
| |
| // No errors. |
| EXPECT_EQ("", error_observer->GetOutput()); |
| |
| EXPECT_EQ(0u, log.GetSize()); |
| EXPECT_EQ(0u, request_log.GetSize()); |
| } |
| |
| // Tests that multiple instances of ProxyResolverV8TracingWrapper can coexist |
| // and run correctly at the same time. This is relevant because at the moment |
| // (time this test was written) each ProxyResolverV8TracingWrapper creates its |
| // own thread to run V8 on, however each thread is operating on the same |
| // v8::Isolate. |
| TEST_F(ProxyResolverV8TracingWrapperTest, MultipleResolvers) { |
| // ------------------------ |
| // Setup resolver0 |
| // ------------------------ |
| MockHostResolver host_resolver0; |
| host_resolver0.rules()->AddRuleForAddressFamily("host1", ADDRESS_FAMILY_IPV4, |
| "166.155.144.44"); |
| host_resolver0.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1", |
| std::string()); |
| host_resolver0.rules()->AddSimulatedFailure("host2"); |
| host_resolver0.rules()->AddRule("host3", "166.155.144.33"); |
| host_resolver0.rules()->AddRule("host5", "166.155.144.55"); |
| host_resolver0.rules()->AddSimulatedFailure("host6"); |
| host_resolver0.rules()->AddRuleForAddressFamily("*", ADDRESS_FAMILY_IPV4, |
| "122.133.144.155"); |
| host_resolver0.rules()->AddRule("*", "133.122.100.200"); |
| std::unique_ptr<ProxyResolver> resolver0 = |
| CreateResolver(nullptr, &host_resolver0, |
| std::make_unique<MockErrorObserver>(), "dns.js"); |
| |
| // ------------------------ |
| // Setup resolver1 |
| // ------------------------ |
| std::unique_ptr<ProxyResolver> resolver1 = |
| CreateResolver(nullptr, &host_resolver0, |
| std::make_unique<MockErrorObserver>(), "dns.js"); |
| |
| // ------------------------ |
| // Setup resolver2 |
| // ------------------------ |
| std::unique_ptr<ProxyResolver> resolver2 = |
| CreateResolver(nullptr, &host_resolver0, |
| std::make_unique<MockErrorObserver>(), "simple.js"); |
| |
| // ------------------------ |
| // Setup resolver3 |
| // ------------------------ |
| MockHostResolver host_resolver3; |
| host_resolver3.rules()->AddRule("foo", "166.155.144.33"); |
| std::unique_ptr<ProxyResolver> resolver3 = |
| CreateResolver(nullptr, &host_resolver3, |
| std::make_unique<MockErrorObserver>(), "simple_dns.js"); |
| |
| // ------------------------ |
| // Queue up work for each resolver (which will be running in parallel). |
| // ------------------------ |
| |
| ProxyResolver* resolver[] = { |
| resolver0.get(), resolver1.get(), resolver2.get(), resolver3.get(), |
| }; |
| |
| const size_t kNumResolvers = arraysize(resolver); |
| const size_t kNumIterations = 20; |
| const size_t kNumResults = kNumResolvers * kNumIterations; |
| TestCompletionCallback callback[kNumResults]; |
| ProxyInfo proxy_info[kNumResults]; |
| std::unique_ptr<ProxyResolver::Request> request[kNumResults]; |
| |
| for (size_t i = 0; i < kNumResults; ++i) { |
| size_t resolver_i = i % kNumResolvers; |
| int rv = resolver[resolver_i]->GetProxyForURL( |
| GURL("http://foo/"), &proxy_info[i], callback[i].callback(), |
| &request[i], NetLogWithSource()); |
| EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); |
| } |
| |
| // ------------------------ |
| // Verify all of the results. |
| // ------------------------ |
| |
| const char* kExpectedForDnsJs = |
| "122.133.144.155-" // myIpAddress() |
| "null-" // dnsResolve('') |
| "__1_192.168.1.1-" // dnsResolveEx('host1') |
| "null-" // dnsResolve('host2') |
| "166.155.144.33-" // dnsResolve('host3') |
| "122.133.144.155-" // myIpAddress() |
| "166.155.144.33-" // dnsResolve('host3') |
| "__1_192.168.1.1-" // dnsResolveEx('host1') |
| "122.133.144.155-" // myIpAddress() |
| "null-" // dnsResolve('host2') |
| "-" // dnsResolveEx('host6') |
| "133.122.100.200-" // myIpAddressEx() |
| "166.155.144.44" // dnsResolve('host1') |
| ":99"; |
| |
| for (size_t i = 0; i < kNumResults; ++i) { |
| size_t resolver_i = i % kNumResolvers; |
| EXPECT_THAT(callback[i].WaitForResult(), IsOk()); |
| |
| std::string proxy_uri = proxy_info[i].proxy_server().ToURI(); |
| |
| if (resolver_i == 0 || resolver_i == 1) { |
| EXPECT_EQ(kExpectedForDnsJs, proxy_uri); |
| } else if (resolver_i == 2) { |
| EXPECT_EQ("foo:99", proxy_uri); |
| } else if (resolver_i == 3) { |
| EXPECT_EQ("166.155.144.33:", |
| proxy_uri.substr(0, proxy_uri.find(':') + 1)); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| } |
| |
| } // namespace |
| |
| } // namespace net |