diff options
author | sammc <sammc@chromium.org> | 2015-06-28 19:58:47 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-29 02:59:20 +0000 |
commit | f2d1ea00bc13c6e742c9c3bffa78d4c009c63e7e (patch) | |
tree | 19e908025d9cc6dbbb1068496f14e806b2b105ee | |
parent | 1e0de6aa93e9534a4c88abd457e4169f6fe4c863 (diff) | |
download | chromium_src-f2d1ea00bc13c6e742c9c3bffa78d4c009c63e7e.zip chromium_src-f2d1ea00bc13c6e742c9c3bffa78d4c009c63e7e.tar.gz chromium_src-f2d1ea00bc13c6e742c9c3bffa78d4c009c63e7e.tar.bz2 |
Split ProxyResolverV8Tracing into an implementation and a wrapper.
The implementation-specific interfaces use a Bindings interface for
reporting alerts and errors and making DNS requests. This allows a user
to provide an implementation instead of forwarding to a fixed NetLog
and HostResolver.
The wrappers implement the ProxyResolver and ProxyResolverFactory
interfaces, mostly matching the previous behavior. The one exception is
that LoadState change reporting has been removed; the one user
(MojoProxyResolverImpl) will soon use the implementation interface
directly instead.
BUG=467832
Review URL: https://codereview.chromium.org/1145153004
Cr-Commit-Position: refs/heads/master@{#336525}
23 files changed, 1883 insertions, 975 deletions
diff --git a/net/BUILD.gn b/net/BUILD.gn index 2fdc390..8edf028 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -768,6 +768,8 @@ if (use_v8_in_net) { "proxy/proxy_resolver_v8.h", "proxy/proxy_resolver_v8_tracing.cc", "proxy/proxy_resolver_v8_tracing.h", + "proxy/proxy_resolver_v8_tracing_wrapper.cc", + "proxy/proxy_resolver_v8_tracing_wrapper.h", "proxy/proxy_service_v8.cc", "proxy/proxy_service_v8.h", ] @@ -839,8 +841,6 @@ if (use_v8_in_net && !is_android) { sources = [ "dns/host_resolver_mojo.cc", "dns/host_resolver_mojo.h", - "proxy/load_state_change_coalescer.cc", - "proxy/load_state_change_coalescer.h", "proxy/mojo_proxy_resolver_factory_impl.cc", "proxy/mojo_proxy_resolver_factory_impl.h", "proxy/mojo_proxy_resolver_impl.cc", @@ -1481,6 +1481,7 @@ if (!is_android && !is_mac) { } else { sources -= [ "proxy/proxy_resolver_v8_tracing_unittest.cc", + "proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc", "proxy/proxy_resolver_v8_unittest.cc", ] } @@ -1496,7 +1497,6 @@ if (!is_android && !is_mac) { sources -= [ "dns/host_resolver_mojo_unittest.cc", "dns/mojo_host_resolver_impl_unittest.cc", - "proxy/load_state_change_coalescer_unittest.cc", "proxy/mojo_proxy_resolver_factory_impl_unittest.cc", "proxy/mojo_proxy_resolver_impl_unittest.cc", "proxy/proxy_resolver_error_observer_mojo_unittest.cc", diff --git a/net/interfaces/proxy_resolver_service.mojom b/net/interfaces/proxy_resolver_service.mojom index 68f798e..133fe8b 100644 --- a/net/interfaces/proxy_resolver_service.mojom +++ b/net/interfaces/proxy_resolver_service.mojom @@ -31,15 +31,13 @@ struct ProxyServer { interface ProxyResolver { // Use a ProxyResolverRequestClient instead of returning a result so we can - // receive load state updates and cancel in-flight requests by destroying the - // client. + // cancel in-flight requests by destroying the client. // TODO(amistry): Add BoundNetLog. GetProxyForUrl(string url, ProxyResolverRequestClient client); }; interface ProxyResolverRequestClient { ReportResult(int32 error, array<ProxyServer>? proxy_servers); - LoadStateChanged(int32 load_state); }; interface ProxyResolverErrorObserver { diff --git a/net/net.gyp b/net/net.gyp index 4482264..c450f47 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -301,6 +301,7 @@ }, { # else: !use_v8_in_net 'sources!': [ 'proxy/proxy_resolver_v8_tracing_unittest.cc', + 'proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc', 'proxy/proxy_resolver_v8_unittest.cc', ], }, @@ -317,7 +318,6 @@ 'sources!': [ 'dns/host_resolver_mojo_unittest.cc', 'dns/mojo_host_resolver_impl_unittest.cc', - 'proxy/load_state_change_coalescer_unittest.cc', 'proxy/mojo_proxy_resolver_factory_impl_unittest.cc', 'proxy/mojo_proxy_resolver_impl_unittest.cc', 'proxy/proxy_resolver_error_observer_mojo_unittest.cc', @@ -869,6 +869,8 @@ 'proxy/proxy_resolver_v8.h', 'proxy/proxy_resolver_v8_tracing.cc', 'proxy/proxy_resolver_v8_tracing.h', + 'proxy/proxy_resolver_v8_tracing_wrapper.cc', + 'proxy/proxy_resolver_v8_tracing_wrapper.h', 'proxy/proxy_service_v8.cc', 'proxy/proxy_service_v8.h', ], @@ -930,8 +932,6 @@ 'sources': [ 'dns/host_resolver_mojo.cc', 'dns/host_resolver_mojo.h', - 'proxy/load_state_change_coalescer.cc', - 'proxy/load_state_change_coalescer.h', 'proxy/mojo_proxy_resolver_factory_impl.cc', 'proxy/mojo_proxy_resolver_factory_impl.h', 'proxy/mojo_proxy_resolver_impl.cc', diff --git a/net/net.gypi b/net/net.gypi index 5a86dee..6283632 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -1480,7 +1480,6 @@ 'proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc', 'proxy/dhcp_proxy_script_fetcher_factory_unittest.cc', 'proxy/dhcp_proxy_script_fetcher_win_unittest.cc', - 'proxy/load_state_change_coalescer_unittest.cc', 'proxy/mojo_proxy_resolver_factory_impl_unittest.cc', 'proxy/mojo_proxy_resolver_impl_unittest.cc', 'proxy/multi_threaded_proxy_resolver_unittest.cc', @@ -1495,6 +1494,7 @@ 'proxy/proxy_resolver_error_observer_mojo_unittest.cc', 'proxy/proxy_resolver_factory_mojo_unittest.cc', 'proxy/proxy_resolver_v8_tracing_unittest.cc', + 'proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc', 'proxy/proxy_resolver_v8_unittest.cc', 'proxy/proxy_script_decider_unittest.cc', 'proxy/proxy_script_fetcher_impl_unittest.cc', diff --git a/net/proxy/load_state_change_coalescer.cc b/net/proxy/load_state_change_coalescer.cc deleted file mode 100644 index ae15e53..0000000 --- a/net/proxy/load_state_change_coalescer.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2015 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/load_state_change_coalescer.h" - -namespace net { - -LoadStateChangeCoalescer::LoadStateChangeCoalescer( - const base::Callback<void(LoadState)>& callback, - const base::TimeDelta& timeout, - LoadState initial_load_state) - : callback_(callback), - timeout_(timeout), - committed_load_state_(initial_load_state), - pending_load_state_(initial_load_state) { -} - -void LoadStateChangeCoalescer::LoadStateChanged(LoadState load_state) { - if (load_state == committed_load_state_) { - timer_.Stop(); - return; - } - pending_load_state_ = load_state; - timer_.Start(FROM_HERE, timeout_, this, - &LoadStateChangeCoalescer::SendLoadStateChanged); -} - -LoadStateChangeCoalescer::~LoadStateChangeCoalescer() = default; - -void LoadStateChangeCoalescer::SendLoadStateChanged() { - committed_load_state_ = pending_load_state_; - callback_.Run(pending_load_state_); -} - -} // namespace net diff --git a/net/proxy/load_state_change_coalescer.h b/net/proxy/load_state_change_coalescer.h deleted file mode 100644 index 6425385..0000000 --- a/net/proxy/load_state_change_coalescer.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015 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. - -#ifndef NET_PROXY_LOAD_STATE_CHANGE_COALESCER_H_ -#define NET_PROXY_LOAD_STATE_CHANGE_COALESCER_H_ - -#include "base/cancelable_callback.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "net/base/load_states.h" - -namespace net { - -// A class that coalesces LoadState changes. When a new LoadState is reported, -// it becomes the pending LoadState and is queued for |timeout|. If the timeout -// elapses without another new LoadState, the pending LoadState becomes the -// committed LoadState and the callback is called with that LoadState. If a new -// LoadState is reported before the timeout has elapsed, the pending LoadState -// is discarded and the new LoadState becomes the new pending LoadState, unless -// it's the same as the committed LoadState, in which case no pending LoadState -// is queued. -class LoadStateChangeCoalescer { - public: - LoadStateChangeCoalescer(const base::Callback<void(LoadState)>& callback, - const base::TimeDelta& timeout, - LoadState initial_load_state); - ~LoadStateChangeCoalescer(); - - // Adds a LoadState change to the pipeline. If it isn't coalesced, |callback_| - // will be called with |load_state| after |timeout_|. - void LoadStateChanged(LoadState load_state); - - private: - void SendLoadStateChanged(); - - // The callback to call to report a LoadState change. - const base::Callback<void(LoadState)> callback_; - - // The amount of time for which a LoadState change can be coalesced. - const base::TimeDelta timeout_; - - base::OneShotTimer<LoadStateChangeCoalescer> timer_; - LoadState committed_load_state_; - LoadState pending_load_state_; - - DISALLOW_COPY_AND_ASSIGN(LoadStateChangeCoalescer); -}; - -} // namespace net - -#endif // NET_PROXY_LOAD_STATE_CHANGE_COALESCER_H_ diff --git a/net/proxy/load_state_change_coalescer_unittest.cc b/net/proxy/load_state_change_coalescer_unittest.cc deleted file mode 100644 index e6f8303..0000000 --- a/net/proxy/load_state_change_coalescer_unittest.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2015 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/load_state_change_coalescer.h" - -#include <vector> - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -class LoadStateChangeCoalescerTest : public testing::Test { - protected: - void SetUp() override { - coalescer_.reset(new LoadStateChangeCoalescer( - base::Bind(&LoadStateChangeCoalescerTest::LoadStateChanged, - base::Unretained(this)), - base::TimeDelta(), LOAD_STATE_IDLE)); - } - - void TearDown() override { coalescer_.reset(); } - - void LoadStateChanged(LoadState load_state) { - load_state_changes_.push_back(load_state); - } - - void WaitUntilIdle() { base::RunLoop().RunUntilIdle(); } - - scoped_ptr<LoadStateChangeCoalescer> coalescer_; - std::vector<LoadState> load_state_changes_; -}; - -TEST_F(LoadStateChangeCoalescerTest, SingleChange) { - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_PROXY_FOR_URL); - WaitUntilIdle(); - ASSERT_EQ(1u, load_state_changes_.size()); - EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, load_state_changes_[0]); -} - -TEST_F(LoadStateChangeCoalescerTest, TwoChangesCoalesce) { - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_PROXY_FOR_URL); - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - WaitUntilIdle(); - ASSERT_EQ(1u, load_state_changes_.size()); - EXPECT_EQ(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT, load_state_changes_[0]); -} - -TEST_F(LoadStateChangeCoalescerTest, ThreeChangesCoalesce) { - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_PROXY_FOR_URL); - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - coalescer_->LoadStateChanged(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT); - WaitUntilIdle(); - ASSERT_EQ(1u, load_state_changes_.size()); - EXPECT_EQ(LOAD_STATE_DOWNLOADING_PROXY_SCRIPT, load_state_changes_[0]); -} - -TEST_F(LoadStateChangeCoalescerTest, CoalesceToOriginalLoadState) { - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_PROXY_FOR_URL); - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - coalescer_->LoadStateChanged(LOAD_STATE_IDLE); - WaitUntilIdle(); - EXPECT_TRUE(load_state_changes_.empty()); -} - -TEST_F(LoadStateChangeCoalescerTest, AlternateLoadStatesWithWait) { - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_PROXY_FOR_URL); - WaitUntilIdle(); - ASSERT_EQ(1u, load_state_changes_.size()); - EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, load_state_changes_[0]); - - coalescer_->LoadStateChanged(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - coalescer_->LoadStateChanged(LOAD_STATE_IDLE); - WaitUntilIdle(); - ASSERT_EQ(2u, load_state_changes_.size()); - EXPECT_EQ(LOAD_STATE_IDLE, load_state_changes_[1]); -} - -} // namespace net diff --git a/net/proxy/mojo_proxy_resolver_factory_impl.cc b/net/proxy/mojo_proxy_resolver_factory_impl.cc index 4a95aa7..834151e 100644 --- a/net/proxy/mojo_proxy_resolver_factory_impl.cc +++ b/net/proxy/mojo_proxy_resolver_factory_impl.cc @@ -13,7 +13,7 @@ #include "net/proxy/proxy_resolver_error_observer_mojo.h" #include "net/proxy/proxy_resolver_factory.h" #include "net/proxy/proxy_resolver_v8.h" -#include "net/proxy/proxy_resolver_v8_tracing.h" +#include "net/proxy/proxy_resolver_v8_tracing_wrapper.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h" namespace net { @@ -26,38 +26,12 @@ scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver( scoped_ptr<ProxyResolverFactory> CreateDefaultProxyResolver( HostResolver* host_resolver, - scoped_ptr<ProxyResolverErrorObserver> error_observer, - const ProxyResolver::LoadStateChangedCallback& callback) { - return make_scoped_ptr(new ProxyResolverFactoryV8Tracing( - host_resolver, nullptr, callback, + scoped_ptr<ProxyResolverErrorObserver> error_observer) { + return make_scoped_ptr(new ProxyResolverFactoryV8TracingWrapper( + host_resolver, nullptr, base::Bind(&ReturnErrorObserver, base::Passed(&error_observer)))); } -class LoadStateChangeForwarder - : public base::RefCounted<LoadStateChangeForwarder> { - public: - LoadStateChangeForwarder() = default; - - void OnLoadStateChanged(ProxyResolver::RequestHandle request_handle, - LoadState load_state) const { - if (!callback_.is_null()) - callback_.Run(request_handle, load_state); - } - - void set_load_state_changed_callback( - const ProxyResolver::LoadStateChangedCallback& callback) { - callback_ = callback; - } - - private: - friend class base::RefCounted<LoadStateChangeForwarder>; - ~LoadStateChangeForwarder() = default; - - ProxyResolver::LoadStateChangedCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(LoadStateChangeForwarder); -}; - // A class to manage the lifetime of a MojoProxyResolverImpl and a // HostResolverMojo. An instance will remain while the message pipes for both // mojo connections remain open. @@ -66,8 +40,6 @@ class MojoProxyResolverHolder : public mojo::ErrorHandler { MojoProxyResolverHolder( scoped_ptr<HostResolverMojo> host_resolver, scoped_ptr<ProxyResolver> proxy_resolver_impl, - const scoped_refptr<LoadStateChangeForwarder>& - load_state_change_forwarder, mojo::InterfaceRequest<interfaces::ProxyResolver> request); private: @@ -84,13 +56,9 @@ class MojoProxyResolverHolder : public mojo::ErrorHandler { MojoProxyResolverHolder::MojoProxyResolverHolder( scoped_ptr<HostResolverMojo> host_resolver, scoped_ptr<ProxyResolver> proxy_resolver_impl, - const scoped_refptr<LoadStateChangeForwarder>& load_state_change_forwarder, mojo::InterfaceRequest<interfaces::ProxyResolver> request) : host_resolver_(host_resolver.Pass()), - mojo_proxy_resolver_( - proxy_resolver_impl.Pass(), - base::Bind(&LoadStateChangeForwarder::set_load_state_changed_callback, - load_state_change_forwarder)), + mojo_proxy_resolver_(proxy_resolver_impl.Pass()), binding_(&mojo_proxy_resolver_, request.Pass()) { binding_.set_error_handler(this); host_resolver_->set_disconnect_callback(base::Bind( @@ -122,7 +90,6 @@ class MojoProxyResolverFactoryImpl::Job : public mojo::ErrorHandler { MojoProxyResolverFactoryImpl* const parent_; scoped_ptr<HostResolverMojo> host_resolver_; - scoped_refptr<LoadStateChangeForwarder> load_state_change_forwarder_; scoped_ptr<ProxyResolver> proxy_resolver_impl_; mojo::InterfaceRequest<interfaces::ProxyResolver> proxy_request_; scoped_ptr<net::ProxyResolverFactory> factory_; @@ -145,13 +112,10 @@ MojoProxyResolverFactoryImpl::Job::Job( host_resolver.Pass(), base::Bind(&MojoProxyResolverFactoryImpl::Job::OnConnectionError, base::Unretained(this)))), - load_state_change_forwarder_(new LoadStateChangeForwarder), proxy_request_(request.Pass()), factory_(proxy_resolver_factory.Run( host_resolver_.get(), - ProxyResolverErrorObserverMojo::Create(error_observer.Pass()), - base::Bind(&LoadStateChangeForwarder::OnLoadStateChanged, - load_state_change_forwarder_))), + ProxyResolverErrorObserverMojo::Create(error_observer.Pass()))), client_ptr_(client.Pass()) { client_ptr_.set_error_handler(this); factory_->CreateProxyResolver( @@ -172,9 +136,9 @@ void MojoProxyResolverFactoryImpl::Job::OnProxyResolverCreated(int error) { if (error == OK) { // The MojoProxyResolverHolder will delete itself if either // |host_resolver_| or |proxy_request_| encounters a connection error. - new MojoProxyResolverHolder( - host_resolver_.Pass(), proxy_resolver_impl_.Pass(), - load_state_change_forwarder_, proxy_request_.Pass()); + new MojoProxyResolverHolder(host_resolver_.Pass(), + proxy_resolver_impl_.Pass(), + proxy_request_.Pass()); } client_ptr_->ReportResult(error); parent_->RemoveJob(this); diff --git a/net/proxy/mojo_proxy_resolver_factory_impl.h b/net/proxy/mojo_proxy_resolver_factory_impl.h index bf652b7..f447759 100644 --- a/net/proxy/mojo_proxy_resolver_factory_impl.h +++ b/net/proxy/mojo_proxy_resolver_factory_impl.h @@ -21,8 +21,7 @@ class MojoProxyResolverFactoryImpl : public interfaces::ProxyResolverFactory { public: using Factory = base::Callback<scoped_ptr<net::ProxyResolverFactory>( HostResolver*, - scoped_ptr<ProxyResolverErrorObserver>, - const ProxyResolver::LoadStateChangedCallback&)>; + scoped_ptr<ProxyResolverErrorObserver>)>; explicit MojoProxyResolverFactoryImpl( mojo::InterfaceRequest<interfaces::ProxyResolverFactory> request); diff --git a/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc b/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc index fc1c94b..a0d9180 100644 --- a/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc +++ b/net/proxy/mojo_proxy_resolver_factory_impl_unittest.cc @@ -76,10 +76,8 @@ class MojoProxyResolverFactoryImplTest scoped_ptr<ProxyResolverFactory> CreateFakeProxyResolverFactory( HostResolver* host_resolver, - scoped_ptr<ProxyResolverErrorObserver> error_observer, - const ProxyResolver::LoadStateChangedCallback& callback) { + scoped_ptr<ProxyResolverErrorObserver> error_observer) { EXPECT_TRUE(host_resolver); - EXPECT_FALSE(callback.is_null()); DCHECK(mock_factory_owner_); return mock_factory_owner_.Pass(); } diff --git a/net/proxy/mojo_proxy_resolver_impl.cc b/net/proxy/mojo_proxy_resolver_impl.cc index c300b6e..b270438 100644 --- a/net/proxy/mojo_proxy_resolver_impl.cc +++ b/net/proxy/mojo_proxy_resolver_impl.cc @@ -8,15 +8,11 @@ #include "mojo/common/url_type_converters.h" #include "net/base/net_errors.h" #include "net/log/net_log.h" -#include "net/proxy/load_state_change_coalescer.h" #include "net/proxy/mojo_proxy_type_converters.h" #include "net/proxy/proxy_info.h" #include "net/proxy/proxy_resolver_script_data.h" namespace net { -namespace { -const int kLoadStateChangeCoalesceTimeoutMilliseconds = 10; -} class MojoProxyResolverImpl::Job : public mojo::ErrorHandler { public: @@ -27,9 +23,6 @@ class MojoProxyResolverImpl::Job : public mojo::ErrorHandler { void Start(); - // Invoked when the LoadState for this job changes. - void LoadStateChanged(LoadState load_state); - net::ProxyResolver::RequestHandle request_handle() { return request_handle_; } private: @@ -40,8 +33,6 @@ class MojoProxyResolverImpl::Job : public mojo::ErrorHandler { void GetProxyDone(int error); - void SendLoadStateChanged(LoadState load_state); - MojoProxyResolverImpl* resolver_; interfaces::ProxyResolverRequestClientPtr client_; @@ -49,33 +40,19 @@ class MojoProxyResolverImpl::Job : public mojo::ErrorHandler { GURL url_; net::ProxyResolver::RequestHandle request_handle_; bool done_; - LoadStateChangeCoalescer load_state_change_coalescer_; DISALLOW_COPY_AND_ASSIGN(Job); }; MojoProxyResolverImpl::MojoProxyResolverImpl( - scoped_ptr<net::ProxyResolver> resolver, - const base::Callback< - void(const net::ProxyResolver::LoadStateChangedCallback&)>& - load_state_change_callback_setter) + scoped_ptr<net::ProxyResolver> resolver) : resolver_(resolver.Pass()) { - load_state_change_callback_setter.Run(base::Bind( - &MojoProxyResolverImpl::LoadStateChanged, base::Unretained(this))); } MojoProxyResolverImpl::~MojoProxyResolverImpl() { STLDeleteElements(&resolve_jobs_); } -void MojoProxyResolverImpl::LoadStateChanged( - net::ProxyResolver::RequestHandle handle, - LoadState load_state) { - auto it = request_handle_to_job_.find(handle); - DCHECK(it != request_handle_to_job_.end()); - it->second->LoadStateChanged(load_state); -} - void MojoProxyResolverImpl::GetProxyForUrl( const mojo::String& url, interfaces::ProxyResolverRequestClientPtr client) { @@ -103,13 +80,7 @@ MojoProxyResolverImpl::Job::Job( client_(client.Pass()), url_(url), request_handle_(nullptr), - done_(false), - load_state_change_coalescer_( - base::Bind(&MojoProxyResolverImpl::Job::SendLoadStateChanged, - base::Unretained(this)), - base::TimeDelta::FromMilliseconds( - kLoadStateChangeCoalesceTimeoutMilliseconds), - LOAD_STATE_RESOLVING_PROXY_FOR_URL) { + done_(false) { } MojoProxyResolverImpl::Job::~Job() { @@ -130,10 +101,6 @@ void MojoProxyResolverImpl::Job::Start() { std::make_pair(request_handle_, this)); } -void MojoProxyResolverImpl::Job::LoadStateChanged(LoadState load_state) { - load_state_change_coalescer_.LoadStateChanged(load_state); -} - void MojoProxyResolverImpl::Job::GetProxyDone(int error) { done_ = true; DVLOG(1) << "GetProxyForUrl(" << url_ << ") finished with error " << error @@ -154,8 +121,4 @@ void MojoProxyResolverImpl::Job::OnConnectionError() { resolver_->DeleteJob(this); } -void MojoProxyResolverImpl::Job::SendLoadStateChanged(LoadState load_state) { - client_->LoadStateChanged(load_state); -} - } // namespace net diff --git a/net/proxy/mojo_proxy_resolver_impl.h b/net/proxy/mojo_proxy_resolver_impl.h index a99c6a4..2d801c8 100644 --- a/net/proxy/mojo_proxy_resolver_impl.h +++ b/net/proxy/mojo_proxy_resolver_impl.h @@ -18,11 +18,7 @@ namespace net { class MojoProxyResolverImpl : public interfaces::ProxyResolver { public: - MojoProxyResolverImpl( - scoped_ptr<net::ProxyResolver> resolver, - const base::Callback< - void(const net::ProxyResolver::LoadStateChangedCallback&)>& - load_state_change_callback_setter); + explicit MojoProxyResolverImpl(scoped_ptr<net::ProxyResolver> resolver); ~MojoProxyResolverImpl() override; @@ -36,10 +32,6 @@ class MojoProxyResolverImpl : public interfaces::ProxyResolver { void DeleteJob(Job* job); - // Invoked when the LoadState of a request changes. - void LoadStateChanged(net::ProxyResolver::RequestHandle handle, - LoadState load_state); - scoped_ptr<net::ProxyResolver> resolver_; std::set<Job*> resolve_jobs_; std::map<net::ProxyResolver::RequestHandle, Job*> request_handle_to_job_; diff --git a/net/proxy/mojo_proxy_resolver_impl_unittest.cc b/net/proxy/mojo_proxy_resolver_impl_unittest.cc index b9fa785..bdccf6c 100644 --- a/net/proxy/mojo_proxy_resolver_impl_unittest.cc +++ b/net/proxy/mojo_proxy_resolver_impl_unittest.cc @@ -26,7 +26,6 @@ class TestRequestClient : public interfaces::ProxyResolverRequestClient, public: enum Event { RESULT_RECEIVED, - LOAD_STATE_CHANGED, CONNECTION_ERROR, }; @@ -37,21 +36,18 @@ class TestRequestClient : public interfaces::ProxyResolverRequestClient, Error error() { return error_; } const mojo::Array<interfaces::ProxyServerPtr>& results() { return results_; } - LoadState load_state() { return load_state_; } EventWaiter<Event>& event_waiter() { return event_waiter_; } private: // interfaces::ProxyResolverRequestClient override. void ReportResult(int32_t error, mojo::Array<interfaces::ProxyServerPtr> results) override; - void LoadStateChanged(int32_t load_state) override; // mojo::ErrorHandler override. void OnConnectionError() override; bool done_ = false; Error error_ = ERR_FAILED; - LoadState load_state_ = LOAD_STATE_IDLE; mojo::Array<interfaces::ProxyServerPtr> results_; mojo::Binding<interfaces::ProxyResolverRequestClient> binding_; @@ -83,11 +79,6 @@ void TestRequestClient::ReportResult( done_ = true; } -void TestRequestClient::LoadStateChanged(int32_t load_state) { - event_waiter_.NotifyEvent(LOAD_STATE_CHANGED); - load_state_ = static_cast<LoadState>(load_state); -} - void TestRequestClient::OnConnectionError() { event_waiter_.NotifyEvent(CONNECTION_ERROR); } @@ -164,25 +155,14 @@ class MojoProxyResolverImplTest : public testing::Test { scoped_ptr<CallbackMockProxyResolver> mock_resolver( new CallbackMockProxyResolver); mock_proxy_resolver_ = mock_resolver.get(); - resolver_impl_.reset(new MojoProxyResolverImpl( - mock_resolver.Pass(), - base::Bind(&MojoProxyResolverImplTest::set_load_state_changed_callback, - base::Unretained(this)))); + resolver_impl_.reset(new MojoProxyResolverImpl(mock_resolver.Pass())); resolver_ = resolver_impl_.get(); } - void set_load_state_changed_callback( - const ProxyResolver::LoadStateChangedCallback& callback) { - EXPECT_TRUE(load_state_changed_callback_.is_null()); - EXPECT_FALSE(callback.is_null()); - load_state_changed_callback_ = callback; - } - CallbackMockProxyResolver* mock_proxy_resolver_; scoped_ptr<MojoProxyResolverImpl> resolver_impl_; interfaces::ProxyResolver* resolver_; - ProxyResolver::LoadStateChangedCallback load_state_changed_callback_; }; TEST_F(MojoProxyResolverImplTest, GetProxyForUrl) { @@ -195,12 +175,6 @@ TEST_F(MojoProxyResolverImplTest, GetProxyForUrl) { mock_proxy_resolver_->pending_requests()[0]; EXPECT_EQ(GURL("http://example.com"), request->url()); - ASSERT_FALSE(load_state_changed_callback_.is_null()); - load_state_changed_callback_.Run(request.get(), - LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - client.event_waiter().WaitForEvent(TestRequestClient::LOAD_STATE_CHANGED); - EXPECT_EQ(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT, client.load_state()); - request->results()->UsePacString( "PROXY proxy.example.com:1; " "SOCKS4 socks4.example.com:2; " diff --git a/net/proxy/proxy_resolver.h b/net/proxy/proxy_resolver.h index 11df64f..b303e2b 100644 --- a/net/proxy/proxy_resolver.h +++ b/net/proxy/proxy_resolver.h @@ -29,9 +29,6 @@ class NET_EXPORT_PRIVATE ProxyResolver { // Opaque pointer type, to return a handle to cancel outstanding requests. typedef void* RequestHandle; - using LoadStateChangedCallback = - base::Callback<void(RequestHandle, LoadState)>; - ProxyResolver() {} virtual ~ProxyResolver() {} diff --git a/net/proxy/proxy_resolver_factory_mojo.cc b/net/proxy/proxy_resolver_factory_mojo.cc index efb1514..0e5b46b 100644 --- a/net/proxy/proxy_resolver_factory_mojo.cc +++ b/net/proxy/proxy_resolver_factory_mojo.cc @@ -132,7 +132,7 @@ class ProxyResolverMojo::Job : public interfaces::ProxyResolverRequestClient, void Cancel(); // Returns the LoadState of this job. - LoadState load_state() { return load_state_; } + LoadState load_state() { return LOAD_STATE_RESOLVING_PROXY_FOR_URL; } private: // Overridden from mojo::ErrorHandler: @@ -142,13 +142,11 @@ class ProxyResolverMojo::Job : public interfaces::ProxyResolverRequestClient, void ReportResult( int32_t error, mojo::Array<interfaces::ProxyServerPtr> proxy_servers) override; - void LoadStateChanged(int32_t load_state) override; ProxyResolverMojo* resolver_; const GURL url_; ProxyInfo* results_; CompletionCallback callback_; - LoadState load_state_ = LOAD_STATE_RESOLVING_PROXY_FOR_URL; base::ThreadChecker thread_checker_; mojo::Binding<interfaces::ProxyResolverRequestClient> binding_; @@ -206,10 +204,6 @@ void ProxyResolverMojo::Job::ReportResult( callback.Run(error); } -void ProxyResolverMojo::Job::LoadStateChanged(int32_t load_state) { - load_state_ = static_cast<LoadState>(load_state); -} - ProxyResolverMojo::ProxyResolverMojo( interfaces::ProxyResolverPtr resolver_ptr, scoped_ptr<interfaces::HostResolver> host_resolver, diff --git a/net/proxy/proxy_resolver_factory_mojo_unittest.cc b/net/proxy/proxy_resolver_factory_mojo_unittest.cc index 16d670b..20214de 100644 --- a/net/proxy/proxy_resolver_factory_mojo_unittest.cc +++ b/net/proxy/proxy_resolver_factory_mojo_unittest.cc @@ -101,8 +101,6 @@ struct GetProxyForUrlAction { DISCONNECT, // Wait for the client pipe to be disconnected. WAIT_FOR_CLIENT_DISCONNECT, - // Send a LoadStateChanged message and keep the client pipe open. - SEND_LOAD_STATE_AND_BLOCK, }; GetProxyForUrlAction() {} @@ -150,13 +148,6 @@ struct GetProxyForUrlAction { return result; } - static GetProxyForUrlAction SendLoadStateChanged(const GURL& url) { - GetProxyForUrlAction result; - result.expected_url = url; - result.action = SEND_LOAD_STATE_AND_BLOCK; - return result; - } - Action action = COMPLETE; Error error = OK; mojo::Array<interfaces::ProxyServerPtr> proxy_servers; @@ -250,11 +241,6 @@ void MockMojoProxyResolver::GetProxyForUrl( case GetProxyForUrlAction::WAIT_FOR_CLIENT_DISCONNECT: ASSERT_FALSE(client.WaitForIncomingResponse()); break; - case GetProxyForUrlAction::SEND_LOAD_STATE_AND_BLOCK: - client->LoadStateChanged(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - blocked_clients_.push_back( - new interfaces::ProxyResolverRequestClientPtr(client.Pass())); - break; } WakeWaiter(); } @@ -269,7 +255,6 @@ class Request { int error() const { return error_; } const ProxyInfo& results() const { return results_; } - LoadState load_state() { return resolver_->GetLoadState(handle_); } private: ProxyResolver* resolver_; @@ -628,21 +613,6 @@ TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL) { EXPECT_EQ("DIRECT", request->results().ToPacString()); } -TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_LoadState) { - mock_proxy_resolver_.AddGetProxyAction( - GetProxyForUrlAction::SendLoadStateChanged(GURL(kExampleUrl))); - CreateProxyResolver(); - - scoped_ptr<Request> request(MakeRequest(GURL(kExampleUrl))); - EXPECT_EQ(ERR_IO_PENDING, request->Resolve()); - EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->load_state()); - while (request->load_state() == LOAD_STATE_RESOLVING_PROXY_FOR_URL) - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT, request->load_state()); - mock_proxy_resolver_.ClearBlockedClients(); - EXPECT_EQ(ERR_PAC_SCRIPT_TERMINATED, request->WaitForResult()); -} - TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleResults) { static const char kPacString[] = "PROXY foo1:80;DIRECT;SOCKS foo2:1234;" diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc index 2f528e6..01e1ef5 100644 --- a/net/proxy/proxy_resolver_v8_tracing.cc +++ b/net/proxy/proxy_resolver_v8_tracing.cc @@ -16,11 +16,9 @@ #include "base/thread_task_runner_handle.h" #include "base/threading/thread.h" #include "base/threading/thread_restrictions.h" -#include "base/values.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/dns/host_resolver.h" -#include "net/log/net_log.h" #include "net/proxy/proxy_info.h" #include "net/proxy/proxy_resolver_error_observer.h" #include "net/proxy/proxy_resolver_v8.h" @@ -58,17 +56,6 @@ const size_t kMaxUniqueResolveDnsPerExec = 20; // hit this. (In fact normal scripts should not even have alerts() or errors). const size_t kMaxAlertsAndErrorsBytes = 2048; -// Returns event parameters for a PAC error message (line number + message). -scoped_ptr<base::Value> NetLogErrorCallback( - int line_number, - const base::string16* message, - NetLogCaptureMode /* capture_mode */) { - scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - dict->SetInteger("line_number", line_number); - dict->SetString("message", *message); - return dict.Pass(); -} - // The Job class is responsible for executing GetProxyForURL() and // creating ProxyResolverV8 instances, since both of these operations share // similar code. @@ -81,8 +68,8 @@ scoped_ptr<base::Value> NetLogErrorCallback( // thread. Most methods are expected to be used exclusively on one thread // or the other. // -// The lifetime of Jobs does not exceed that of the ProxyResolverV8Tracing that -// spawned it. Destruction might happen on either the origin thread or the +// The lifetime of Jobs does not exceed that of the ProxyResolverV8TracingImpl +// that spawned it. Destruction might happen on either the origin thread or the // worker thread. class Job : public base::RefCountedThreadSafe<Job>, public ProxyResolverV8::JSBindings { @@ -90,30 +77,19 @@ class Job : public base::RefCountedThreadSafe<Job>, struct Params { Params( const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner, - HostResolver* host_resolver, - ProxyResolverErrorObserver* error_observer, - NetLog* net_log, - ProxyResolver::LoadStateChangedCallback on_load_state_changed, int* num_outstanding_callbacks) : v8_resolver(nullptr), worker_task_runner(worker_task_runner), - host_resolver(host_resolver), - error_observer(error_observer), - net_log(net_log), - on_load_state_changed(on_load_state_changed), num_outstanding_callbacks(num_outstanding_callbacks) {} ProxyResolverV8* v8_resolver; scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner; - HostResolver* host_resolver; - ProxyResolverErrorObserver* error_observer; - NetLog* net_log; - ProxyResolver::LoadStateChangedCallback on_load_state_changed; int* num_outstanding_callbacks; }; // |params| is non-owned. It contains the parameters for this Job, and must // outlive it. - explicit Job(const Params* params); + Job(const Params* params, + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings); // Called from origin thread. void StartCreateV8Resolver( @@ -124,7 +100,6 @@ class Job : public base::RefCountedThreadSafe<Job>, // Called from origin thread. void StartGetProxyForURL(const GURL& url, ProxyInfo* results, - const BoundNetLog& net_log, const CompletionCallback& callback); // Called from origin thread. @@ -159,8 +134,6 @@ class Job : public base::RefCountedThreadSafe<Job>, ProxyResolverV8* v8_resolver(); const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner(); HostResolver* host_resolver(); - ProxyResolverErrorObserver* error_observer(); - NetLog* net_log(); // Invokes the user's callback. void NotifyCaller(int result); @@ -223,11 +196,7 @@ class Job : public base::RefCountedThreadSafe<Job>, void DispatchAlertOrError(bool is_alert, int line_number, const base::string16& message); - void LogEventToCurrentRequestAndGlobally( - NetLog::EventType type, - const NetLog::ParametersCallback& parameters_callback); - - // The thread which called into ProxyResolverV8Tracing, and on which the + // The thread which called into ProxyResolverV8TracingImpl, and on which the // completion callback is expected to run. scoped_refptr<base::SingleThreadTaskRunner> origin_runner_; @@ -235,6 +204,8 @@ class Job : public base::RefCountedThreadSafe<Job>, // Initialized on origin thread and then accessed from both threads. const Params* const params_; + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings_; + // The callback to run (on the origin thread) when the Job finishes. // Should only be accessed from origin thread. CompletionCallback callback_; @@ -277,7 +248,6 @@ class Job : public base::RefCountedThreadSafe<Job>, ProxyInfo* user_results_; // Owned by caller, lives on origin thread. GURL url_; ProxyInfo results_; - BoundNetLog bound_net_log_; // --------------------------------------------------------------------------- // State for ExecuteNonBlocking() @@ -324,53 +294,42 @@ class Job : public base::RefCountedThreadSafe<Job>, AddressList pending_dns_addresses_; }; -class ProxyResolverV8Tracing : public ProxyResolver, - public base::NonThreadSafe { +class ProxyResolverV8TracingImpl : public ProxyResolverV8Tracing, + public base::NonThreadSafe { public: - // Constructs a ProxyResolver that will issue DNS requests through - // |job_params->host_resolver|, forward Javascript errors through - // |error_observer|, and log Javascript errors and alerts to - // |job_params->net_log|. When the LoadState for a request changes, - // |job_params->on_load_state_changed| will be invoked with the RequestHandle - // for that request with the new LoadState. - // - // Note that the constructor takes ownership of |error_observer|, whereas - // |job_params->host_resolver| and |job_params->net_log| are expected to - // outlive |this|. - ProxyResolverV8Tracing(scoped_ptr<ProxyResolverErrorObserver> error_observer, - scoped_ptr<base::Thread> thread, - scoped_ptr<ProxyResolverV8> resolver, - scoped_ptr<Job::Params> job_params); - - ~ProxyResolverV8Tracing() override; - - // ProxyResolver implementation: - int GetProxyForURL(const GURL& url, - ProxyInfo* results, - const CompletionCallback& callback, - RequestHandle* request, - const BoundNetLog& net_log) override; - void CancelRequest(RequestHandle request) override; - LoadState GetLoadState(RequestHandle request) const override; + ProxyResolverV8TracingImpl(scoped_ptr<base::Thread> thread, + scoped_ptr<ProxyResolverV8> resolver, + scoped_ptr<Job::Params> job_params); + + ~ProxyResolverV8TracingImpl() override; + + // ProxyResolverV8Tracing overrides. + void GetProxyForURL(const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + ProxyResolver::RequestHandle* request, + scoped_ptr<Bindings> bindings) override; + void CancelRequest(ProxyResolver::RequestHandle request) override; + LoadState GetLoadState(ProxyResolver::RequestHandle request) const override; private: // The worker thread on which the ProxyResolverV8 will be run. scoped_ptr<base::Thread> thread_; scoped_ptr<ProxyResolverV8> v8_resolver_; - scoped_ptr<ProxyResolverErrorObserver> error_observer_; - scoped_ptr<Job::Params> job_params_; // The number of outstanding (non-cancelled) jobs. int num_outstanding_callbacks_; - DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Tracing); + DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8TracingImpl); }; -Job::Job(const Job::Params* params) +Job::Job(const Job::Params* params, + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings) : origin_runner_(base::ThreadTaskRunnerHandle::Get()), params_(params), + bindings_(bindings.Pass()), event_(true, false), last_num_dns_(0), pending_dns_(NULL) { @@ -395,13 +354,11 @@ void Job::StartCreateV8Resolver( void Job::StartGetProxyForURL(const GURL& url, ProxyInfo* results, - const BoundNetLog& net_log, const CompletionCallback& callback) { CheckIsOnOriginThread(); url_ = url; user_results_ = results; - bound_net_log_ = net_log; Start(GET_PROXY_FOR_URL, false /*non-blocking*/, callback); } @@ -490,15 +447,7 @@ const scoped_refptr<base::SingleThreadTaskRunner>& Job::worker_task_runner() { } HostResolver* Job::host_resolver() { - return params_->host_resolver; -} - -ProxyResolverErrorObserver* Job::error_observer() { - return params_->error_observer; -} - -NetLog* Job::net_log() { - return params_->net_log; + return bindings_->GetHostResolver(); } void Job::NotifyCaller(int result) { @@ -746,12 +695,9 @@ void Job::DoDnsOperation() { HostResolver::RequestHandle dns_request = NULL; int result = host_resolver()->Resolve( - MakeDnsRequestInfo(pending_dns_host_, pending_dns_op_), - DEFAULT_PRIORITY, - &pending_dns_addresses_, - base::Bind(&Job::OnDnsOperationComplete, this), - &dns_request, - bound_net_log_); + MakeDnsRequestInfo(pending_dns_host_, pending_dns_op_), DEFAULT_PRIORITY, + &pending_dns_addresses_, base::Bind(&Job::OnDnsOperationComplete, this), + &dns_request, bindings_->GetBoundNetLog()); pending_dns_completed_synchronously_ = result != ERR_IO_PENDING; @@ -769,10 +715,6 @@ void Job::DoDnsOperation() { } else { DCHECK(dns_request); pending_dns_ = dns_request; - if (!params_->on_load_state_changed.is_null()) { - params_->on_load_state_changed.Run( - this, LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT); - } // OnDnsOperationComplete() will be called by host resolver on completion. } @@ -793,12 +735,6 @@ void Job::OnDnsOperationComplete(int result) { pending_dns_addresses_); pending_dns_ = NULL; - if (!params_->on_load_state_changed.is_null() && - !pending_dns_completed_synchronously_ && !cancelled_.IsSet()) { - params_->on_load_state_changed.Run(this, - LOAD_STATE_RESOLVING_PROXY_FOR_URL); - } - if (blocking_dns_) { event_.Signal(); return; @@ -949,8 +885,8 @@ void Job::DispatchAlertOrError(bool is_alert, // alerts/errors. The request might get cancelled shortly after this // check! (There is no lock being held to guarantee otherwise). // - // If this happens, then some information will get written to the NetLog - // needlessly, however the NetLog will still be alive so it shouldn't cause + // If this happens, then some information will be logged needlessly, however + // the Bindings are responsible for handling this case so it shouldn't cause // problems. if (cancelled_.IsSet()) return; @@ -961,10 +897,7 @@ void Job::DispatchAlertOrError(bool is_alert, // ------------------- VLOG(1) << "PAC-alert: " << message; - // Send to the NetLog. - LogEventToCurrentRequestAndGlobally( - NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::StringCallback("message", &message)); + bindings_->Alert(message); } else { // ------------------- // error @@ -974,41 +907,22 @@ void Job::DispatchAlertOrError(bool is_alert, else VLOG(1) << "PAC-error: " << "line: " << line_number << ": " << message; - // Send the error to the NetLog. - LogEventToCurrentRequestAndGlobally( - NetLog::TYPE_PAC_JAVASCRIPT_ERROR, - base::Bind(&NetLogErrorCallback, line_number, &message)); - - if (error_observer()) - error_observer()->OnPACScriptError(line_number, message); + bindings_->OnError(line_number, message); } } -void Job::LogEventToCurrentRequestAndGlobally( - NetLog::EventType type, - const NetLog::ParametersCallback& parameters_callback) { - CheckIsOnWorkerThread(); - bound_net_log_.AddEvent(type, parameters_callback); - - // Emit to the global NetLog event stream. - if (net_log()) - net_log()->AddGlobalEntry(type, parameters_callback); -} - -ProxyResolverV8Tracing::ProxyResolverV8Tracing( - scoped_ptr<ProxyResolverErrorObserver> error_observer, +ProxyResolverV8TracingImpl::ProxyResolverV8TracingImpl( scoped_ptr<base::Thread> thread, scoped_ptr<ProxyResolverV8> resolver, scoped_ptr<Job::Params> job_params) : thread_(thread.Pass()), v8_resolver_(resolver.Pass()), - error_observer_(error_observer.Pass()), job_params_(job_params.Pass()), num_outstanding_callbacks_(0) { job_params_->num_outstanding_callbacks = &num_outstanding_callbacks_; } -ProxyResolverV8Tracing::~ProxyResolverV8Tracing() { +ProxyResolverV8TracingImpl::~ProxyResolverV8TracingImpl() { // Note, all requests should have been cancelled. CHECK_EQ(0, num_outstanding_callbacks_); @@ -1017,50 +931,67 @@ ProxyResolverV8Tracing::~ProxyResolverV8Tracing() { thread_.reset(); } -int ProxyResolverV8Tracing::GetProxyForURL(const GURL& url, - ProxyInfo* results, - const CompletionCallback& callback, - RequestHandle* request, - const BoundNetLog& net_log) { +void ProxyResolverV8TracingImpl::GetProxyForURL( + const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + ProxyResolver::RequestHandle* request, + scoped_ptr<Bindings> bindings) { DCHECK(CalledOnValidThread()); DCHECK(!callback.is_null()); - scoped_refptr<Job> job = new Job(job_params_.get()); + scoped_refptr<Job> job = new Job(job_params_.get(), bindings.Pass()); if (request) *request = job.get(); - job->StartGetProxyForURL(url, results, net_log, callback); - return ERR_IO_PENDING; + job->StartGetProxyForURL(url, results, callback); } -void ProxyResolverV8Tracing::CancelRequest(RequestHandle request) { +void ProxyResolverV8TracingImpl::CancelRequest( + ProxyResolver::RequestHandle request) { Job* job = reinterpret_cast<Job*>(request); job->Cancel(); } -LoadState ProxyResolverV8Tracing::GetLoadState(RequestHandle request) const { +LoadState ProxyResolverV8TracingImpl::GetLoadState( + ProxyResolver::RequestHandle request) const { Job* job = reinterpret_cast<Job*>(request); return job->GetLoadState(); } -} // namespace +class ProxyResolverV8TracingFactoryImpl : public ProxyResolverV8TracingFactory { + public: + ProxyResolverV8TracingFactoryImpl(); + ~ProxyResolverV8TracingFactoryImpl() override; + + void CreateProxyResolverV8Tracing( + const scoped_refptr<ProxyResolverScriptData>& pac_script, + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings, + scoped_ptr<ProxyResolverV8Tracing>* resolver, + const CompletionCallback& callback, + scoped_ptr<ProxyResolverFactory::Request>* request) override; + + private: + class CreateJob; + + void RemoveJob(CreateJob* job); -class ProxyResolverFactoryV8Tracing::CreateJob + std::set<CreateJob*> jobs_; + + DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8TracingFactoryImpl); +}; + +class ProxyResolverV8TracingFactoryImpl::CreateJob : public ProxyResolverFactory::Request { public: - CreateJob(ProxyResolverFactoryV8Tracing* factory, - HostResolver* host_resolver, - scoped_ptr<ProxyResolverErrorObserver> error_observer, - NetLog* net_log, - const ProxyResolver::LoadStateChangedCallback& - load_state_changed_callback, + CreateJob(ProxyResolverV8TracingFactoryImpl* factory, + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings, const scoped_refptr<ProxyResolverScriptData>& pac_script, - scoped_ptr<ProxyResolver>* resolver_out, + scoped_ptr<ProxyResolverV8Tracing>* resolver_out, const CompletionCallback& callback) : factory_(factory), thread_(new base::Thread("Proxy Resolver")), - error_observer_(error_observer.Pass()), resolver_out_(resolver_out), callback_(callback), num_outstanding_callbacks_(0) { @@ -1068,14 +999,13 @@ class ProxyResolverFactoryV8Tracing::CreateJob base::Thread::Options options; options.timer_slack = base::TIMER_SLACK_MAXIMUM; CHECK(thread_->StartWithOptions(options)); - job_params_.reset(new Job::Params( - thread_->task_runner(), host_resolver, error_observer_.get(), net_log, - load_state_changed_callback, &num_outstanding_callbacks_)); - create_resolver_job_ = new Job(job_params_.get()); + job_params_.reset( + new Job::Params(thread_->task_runner(), &num_outstanding_callbacks_)); + create_resolver_job_ = new Job(job_params_.get(), bindings.Pass()); create_resolver_job_->StartCreateV8Resolver( pac_script, &v8_resolver_, base::Bind( - &ProxyResolverFactoryV8Tracing::CreateJob::OnV8ResolverCreated, + &ProxyResolverV8TracingFactoryImpl::CreateJob::OnV8ResolverCreated, base::Unretained(this))); } @@ -1101,9 +1031,8 @@ class ProxyResolverFactoryV8Tracing::CreateJob DCHECK(factory_); if (error == OK) { job_params_->v8_resolver = v8_resolver_.get(); - resolver_out_->reset( - new ProxyResolverV8Tracing(error_observer_.Pass(), thread_.Pass(), - v8_resolver_.Pass(), job_params_.Pass())); + resolver_out_->reset(new ProxyResolverV8TracingImpl( + thread_.Pass(), v8_resolver_.Pass(), job_params_.Pass())); } else { StopWorkerThread(); } @@ -1120,58 +1049,51 @@ class ProxyResolverFactoryV8Tracing::CreateJob thread_.reset(); } - ProxyResolverFactoryV8Tracing* factory_; + ProxyResolverV8TracingFactoryImpl* factory_; scoped_ptr<base::Thread> thread_; - scoped_ptr<ProxyResolverErrorObserver> error_observer_; scoped_ptr<Job::Params> job_params_; scoped_refptr<Job> create_resolver_job_; scoped_ptr<ProxyResolverV8> v8_resolver_; - scoped_ptr<ProxyResolver>* resolver_out_; + scoped_ptr<ProxyResolverV8Tracing>* resolver_out_; const CompletionCallback callback_; int num_outstanding_callbacks_; DISALLOW_COPY_AND_ASSIGN(CreateJob); }; -ProxyResolverFactoryV8Tracing::ProxyResolverFactoryV8Tracing( - HostResolver* host_resolver, - NetLog* net_log, - const ProxyResolver::LoadStateChangedCallback& callback, - const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& - error_observer_factory) - : ProxyResolverFactory(true), - host_resolver_(host_resolver), - net_log_(net_log), - load_state_changed_callback_(callback), - error_observer_factory_(error_observer_factory) { +ProxyResolverV8TracingFactoryImpl::ProxyResolverV8TracingFactoryImpl() { } -ProxyResolverFactoryV8Tracing::~ProxyResolverFactoryV8Tracing() { +ProxyResolverV8TracingFactoryImpl::~ProxyResolverV8TracingFactoryImpl() { for (auto job : jobs_) { job->FactoryDestroyed(); } } -// ProxyResolverFactory override. -int ProxyResolverFactoryV8Tracing::CreateProxyResolver( +void ProxyResolverV8TracingFactoryImpl::CreateProxyResolverV8Tracing( const scoped_refptr<ProxyResolverScriptData>& pac_script, - scoped_ptr<ProxyResolver>* resolver, + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings, + scoped_ptr<ProxyResolverV8Tracing>* resolver, const CompletionCallback& callback, - scoped_ptr<Request>* request) { - scoped_ptr<CreateJob> job(new CreateJob( - this, host_resolver_, - error_observer_factory_.is_null() ? nullptr - : error_observer_factory_.Run(), - net_log_, load_state_changed_callback_, pac_script, resolver, callback)); + scoped_ptr<ProxyResolverFactory::Request>* request) { + scoped_ptr<CreateJob> job( + new CreateJob(this, bindings.Pass(), pac_script, resolver, callback)); jobs_.insert(job.get()); *request = job.Pass(); - return ERR_IO_PENDING; } -void ProxyResolverFactoryV8Tracing::RemoveJob( - ProxyResolverFactoryV8Tracing::CreateJob* job) { +void ProxyResolverV8TracingFactoryImpl::RemoveJob( + ProxyResolverV8TracingFactoryImpl::CreateJob* job) { size_t erased = jobs_.erase(job); DCHECK_EQ(1u, erased); } +} // namespace + +// static +scoped_ptr<ProxyResolverV8TracingFactory> +ProxyResolverV8TracingFactory::Create() { + return make_scoped_ptr(new ProxyResolverV8TracingFactoryImpl()); +} + } // namespace net diff --git a/net/proxy/proxy_resolver_v8_tracing.h b/net/proxy/proxy_resolver_v8_tracing.h index c2a9de5..0b0ab35 100644 --- a/net/proxy/proxy_resolver_v8_tracing.h +++ b/net/proxy/proxy_resolver_v8_tracing.h @@ -5,8 +5,6 @@ #ifndef NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_ #define NET_PROXY_PROXY_RESOLVER_V8_TRACING_H_ -#include <set> - #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -17,50 +15,84 @@ namespace net { class HostResolver; -class NetLog; -class ProxyResolverErrorObserver; -// ProxyResolverFactoryV8Tracing is a ProxyResolverFactory that returns -// non-blocking ProxyResolver instances. Each ProxyResolver instance executes -// ProxyResolverV8 on a single helper thread, and does some magic to avoid +// ProxyResolverV8Tracing is a non-blocking proxy resolver. +class NET_EXPORT ProxyResolverV8Tracing { + public: + // Bindings is an interface used by ProxyResolverV8Tracing to delegate + // per-request functionality. Each instance will be destroyed on the origin + // thread of the ProxyResolverV8Tracing when the request completes or after + // the request is cancelled. In the cancellation case, the Bindings instance + // for a request may be destroyed after CancelRequest completes. + class Bindings { + public: + Bindings() {} + virtual ~Bindings() {} + + // Invoked in response to an alert() call by the PAC script. This may be + // called after cancellation and from any thread. + virtual void Alert(const base::string16& message) = 0; + + // Invoked in response to an error in the PAC script. This may be + // called after cancellation and from any thread. + virtual void OnError(int line_number, const base::string16& message) = 0; + + // Returns a HostResolver to use for DNS resolution. This will only be + // called from the origin thread and will never be called after + // cancellation. + virtual HostResolver* GetHostResolver() = 0; + + // Returns a BoundNetLog to be passed to the HostResolver returned by + // GetHostResolver(). This will only be called from the origin thread and + // will never be called after cancellation. + virtual BoundNetLog GetBoundNetLog() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Bindings); + }; + + virtual ~ProxyResolverV8Tracing() {} + + // Gets a list of proxy servers to use for |url|. This request always + // runs asynchronously and notifies the result by running |callback|. If the + // result code is OK then the request was successful and |results| contains + // the proxy resolution information. If |request| is non-null, |*request| is + // written to, and can be passed to CancelRequest(). + virtual void GetProxyForURL(const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + ProxyResolver::RequestHandle* request, + scoped_ptr<Bindings> bindings) = 0; + + // Cancels |request|. + virtual void CancelRequest(ProxyResolver::RequestHandle request) = 0; + + // Gets the LoadState for |request|. + virtual LoadState GetLoadState( + ProxyResolver::RequestHandle request) const = 0; +}; + +// A factory for ProxyResolverV8Tracing instances. The default implementation, +// returned by Create(), creates ProxyResolverV8Tracing instances that execute +// ProxyResolverV8 on a single helper thread, and do some magic to avoid // blocking in DNS. For more details see the design document: // https://docs.google.com/a/google.com/document/d/16Ij5OcVnR3s0MH4Z5XkhI9VTPoMJdaBn9rKreAmGOdE/edit?pli=1 -class NET_EXPORT ProxyResolverFactoryV8Tracing : public ProxyResolverFactory { +class NET_EXPORT ProxyResolverV8TracingFactory { public: - // Note that |host_resolver| and |net_log| are expected to outlive |this| and - // any ProxyResolver instances created using |this|. |error_observer_factory| - // will be invoked once per CreateProxyResolver() call to create a - // ProxyResolverErrorObserver to be used by the ProxyResolver instance - // returned by that call. - ProxyResolverFactoryV8Tracing( - HostResolver* host_resolver, - NetLog* net_log, - const ProxyResolver::LoadStateChangedCallback& callback, - const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& - error_observer_factory); - ~ProxyResolverFactoryV8Tracing() override; - - // ProxyResolverFactory override. - int CreateProxyResolver( + ProxyResolverV8TracingFactory() {} + virtual ~ProxyResolverV8TracingFactory() = default; + + virtual void CreateProxyResolverV8Tracing( const scoped_refptr<ProxyResolverScriptData>& pac_script, - scoped_ptr<ProxyResolver>* resolver, + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings, + scoped_ptr<ProxyResolverV8Tracing>* resolver, const CompletionCallback& callback, - scoped_ptr<Request>* request) override; + scoped_ptr<ProxyResolverFactory::Request>* request) = 0; - private: - class CreateJob; + static scoped_ptr<ProxyResolverV8TracingFactory> Create(); - void RemoveJob(CreateJob* job); - - HostResolver* const host_resolver_; - NetLog* const net_log_; - const ProxyResolver::LoadStateChangedCallback load_state_changed_callback_; - const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()> - error_observer_factory_; - - std::set<CreateJob*> jobs_; - - DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryV8Tracing); + private: + DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8TracingFactory); }; } // namespace net diff --git a/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_unittest.cc index 296853c..6eda3b8 100644 --- a/net/proxy/proxy_resolver_v8_tracing_unittest.cc +++ b/net/proxy/proxy_resolver_v8_tracing_unittest.cc @@ -7,11 +7,8 @@ #include <string> #include "base/files/file_util.h" -#include "base/message_loop/message_loop.h" #include "base/path_service.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" +#include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" @@ -21,11 +18,7 @@ #include "net/dns/host_cache.h" #include "net/dns/mock_host_resolver.h" #include "net/log/net_log.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/proxy_info.h" -#include "net/proxy/proxy_resolver_error_observer.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -39,7 +32,7 @@ class ProxyResolverV8TracingTest : public testing::Test { // 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::MessageLoop::current()->RunUntilIdle(); + base::RunLoop().RunUntilIdle(); } }; @@ -62,154 +55,153 @@ scoped_refptr<ProxyResolverScriptData> LoadScriptData(const char* filename) { return ProxyResolverScriptData::FromUTF8(file_contents); } -scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver( - scoped_ptr<ProxyResolverErrorObserver> error_observer) { - return error_observer; -} - -scoped_ptr<ProxyResolver> CreateResolver( - NetLog* net_log, - HostResolver* host_resolver, - scoped_ptr<ProxyResolverErrorObserver> error_observer, - const char* filename) { - scoped_ptr<ProxyResolver> resolver; - ProxyResolverFactoryV8Tracing factory( - host_resolver, net_log, ProxyResolver::LoadStateChangedCallback(), - base::Bind(&ReturnErrorObserver, base::Passed(&error_observer))); - TestCompletionCallback callback; - scoped_ptr<ProxyResolverFactory::Request> request; - int rv = factory.CreateProxyResolver(LoadScriptData(filename), &resolver, - callback.callback(), &request); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - EXPECT_TRUE(resolver); - return resolver.Pass(); -} - -class MockErrorObserver : public ProxyResolverErrorObserver { +class MockBindings { public: - MockErrorObserver() : event_(true, false) {} + explicit MockBindings(HostResolver* host_resolver) + : host_resolver_(host_resolver), event_(true, false) {} - void OnPACScriptError(int line_number, const base::string16& error) override { - { - base::AutoLock l(lock_); - output += base::StringPrintf("Error: line %d: %s\n", line_number, - base::UTF16ToASCII(error).c_str()); - } + void Alert(const base::string16& message) { + base::AutoLock l(lock_); + alerts_.push_back(base::UTF16ToASCII(message)); + } + void OnError(int line_number, const base::string16& error) { + base::AutoLock l(lock_); + errors_.push_back(std::make_pair(line_number, base::UTF16ToASCII(error))); event_.Signal(); } - std::string GetOutput() { + HostResolver* host_resolver() { return host_resolver_; } + + std::vector<std::string> GetAlerts() { + base::AutoLock l(lock_); + return alerts_; + } + + std::vector<std::pair<int, std::string>> GetErrors() { base::AutoLock l(lock_); - return output; + return errors_; } - void WaitForOutput() { - event_.Wait(); + void WaitForError() { event_.Wait(); } + + scoped_ptr<ProxyResolverV8Tracing::Bindings> CreateBindings() { + return make_scoped_ptr(new ForwardingBindings(this)); } private: + class ForwardingBindings : public ProxyResolverV8Tracing::Bindings { + public: + ForwardingBindings(MockBindings* bindings) : bindings_(bindings) {} + + // ProxyResolverV8Tracing::Bindings overrides. + void Alert(const base::string16& message) override { + bindings_->Alert(message); + } + + void OnError(int line_number, const base::string16& error) override { + bindings_->OnError(line_number, error); + } + + BoundNetLog GetBoundNetLog() override { return BoundNetLog(); } + + HostResolver* GetHostResolver() override { + return bindings_->host_resolver(); + } + + private: + MockBindings* bindings_; + }; + base::Lock lock_; - std::string output; + std::vector<std::string> alerts_; + std::vector<std::pair<int, std::string>> errors_; + HostResolver* const host_resolver_; base::WaitableEvent event_; }; +scoped_ptr<ProxyResolverV8Tracing> CreateResolver( + scoped_ptr<ProxyResolverV8Tracing::Bindings> bindings, + const char* filename) { + scoped_ptr<ProxyResolverV8Tracing> resolver; + scoped_ptr<ProxyResolverV8TracingFactory> factory( + ProxyResolverV8TracingFactory::Create()); + TestCompletionCallback callback; + scoped_ptr<ProxyResolverFactory::Request> request; + factory->CreateProxyResolverV8Tracing(LoadScriptData(filename), + bindings.Pass(), &resolver, + callback.callback(), &request); + EXPECT_EQ(OK, callback.WaitForResult()); + EXPECT_TRUE(resolver); + return resolver.Pass(); +} + TEST_F(ProxyResolverV8TracingTest, Simple) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - &log, &host_resolver, make_scoped_ptr(error_observer), "simple.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "simple.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); 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()); + // There were no alerts or errors. + EXPECT_TRUE(mock_bindings.GetAlerts().empty()); + EXPECT_TRUE(mock_bindings.GetErrors().empty()); } TEST_F(ProxyResolverV8TracingTest, JavascriptError) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - &log, &host_resolver, make_scoped_ptr(error_observer), "error.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "error.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - EXPECT_TRUE( - LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR, - NetLog::PHASE_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()); - } + // Check the output -- there was 1 alert and 1 javascript error. + ASSERT_EQ(1u, mock_bindings.GetAlerts().size()); + EXPECT_EQ("Prepare to DIE!", mock_bindings.GetAlerts()[0]); + ASSERT_EQ(1u, mock_bindings.GetErrors().size()); + EXPECT_EQ(5, mock_bindings.GetErrors()[0].first); + EXPECT_EQ("Uncaught TypeError: Cannot read property 'split' of null", + mock_bindings.GetErrors()[0].second); } TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "too_many_alerts.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "too_many_alerts.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); // Iteration1 does a DNS resolve @@ -220,45 +212,32 @@ TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) { 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - } + EXPECT_TRUE(mock_bindings.GetErrors().empty()); + + // Check the alerts -- the script generated 50 alerts. + std::vector<std::string> alerts = mock_bindings.GetAlerts(); + ASSERT_EQ(50u, alerts.size()); + for (size_t i = 0; i < alerts.size(); i++) { + EXPECT_EQ("Gee, all these alerts are silly!", alerts[i]); } } // Verify that buffered alerts cannot grow unboundedly, even when the message is // empty string. TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "too_many_empty_alerts.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = CreateResolver( + mock_bindings.CreateBindings(), "too_many_empty_alerts.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI()); @@ -266,22 +245,13 @@ TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) { 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - } + EXPECT_TRUE(mock_bindings.GetErrors().empty()); + + // Check the alerts -- the script generated 1000 alerts. + std::vector<std::string> alerts = mock_bindings.GetAlerts(); + ASSERT_EQ(1000u, alerts.size()); + for (size_t i = 0; i < alerts.size(); i++) { + EXPECT_EQ("", alerts[i]); } } @@ -289,10 +259,8 @@ TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) { // verifies the final result, and that the underlying DNS resolver received // the correct set of queries. TEST_F(ProxyResolverV8TracingTest, Dns) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddRuleForAddressFamily( "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44"); @@ -306,17 +274,16 @@ TEST_F(ProxyResolverV8TracingTest, Dns) { "*", ADDRESS_FAMILY_IPV4, "122.133.144.155"); host_resolver.rules()->AddRule("*", "133.122.100.200"); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - &log, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback.WaitForResult()); // The test does 13 DNS resolution, however only 7 of them are unique. @@ -341,48 +308,34 @@ TEST_F(ProxyResolverV8TracingTest, Dns) { 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson()); - } + EXPECT_TRUE(mock_bindings.GetErrors().empty()); + + // The script generated 1 alert. + ASSERT_EQ(1u, mock_bindings.GetAlerts().size()); + EXPECT_EQ("iteration: 7", mock_bindings.GetAlerts()[0]); } // 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(ProxyResolverV8TracingTest, DnsChecksCache) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddRule("foopy", "166.155.144.11"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - &log, &host_resolver, make_scoped_ptr(error_observer), "simple_dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "simple_dns.js"); TestCompletionCallback callback1; TestCompletionCallback callback2; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, - callback1.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, + callback1.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback1.WaitForResult()); // The test does 2 DNS resolutions. @@ -391,11 +344,10 @@ TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) { // The first request took 2 restarts, hence on g_iteration=3. EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI()); - rv = - resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info, - callback2.callback(), NULL, request_log.bound()); + resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info, + callback2.callback(), NULL, + mock_bindings.CreateBindings()); - EXPECT_EQ(ERR_IO_PENDING, rv); EXPECT_EQ(OK, callback2.WaitForResult()); EXPECT_EQ(4u, host_resolver.num_resolve()); @@ -403,37 +355,31 @@ TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) { // 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()); + // There were no alerts or errors. + EXPECT_TRUE(mock_bindings.GetAlerts().empty()); + EXPECT_TRUE(mock_bindings.GetErrors().empty()); } // 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(ProxyResolverV8TracingTest, FallBackToSynchronous1) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); 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"); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "global_sideffects1.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "global_sideffects1.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); // The script itself only does 2 DNS resolves per execution, however it @@ -445,32 +391,18 @@ TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous1) { 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson()); - } + EXPECT_TRUE(mock_bindings.GetErrors().empty()); + + ASSERT_EQ(1u, mock_bindings.GetAlerts().size()); + EXPECT_EQ("iteration: 4", mock_bindings.GetAlerts()[0]); } // 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(ProxyResolverV8TracingTest, FallBackToSynchronous2) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddRule("host1", "166.155.144.11"); host_resolver.rules()->AddRule("host2", "166.155.144.22"); @@ -478,29 +410,24 @@ TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) { host_resolver.rules()->AddRule("host4", "166.155.144.44"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "global_sideffects2.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "global_sideffects2.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); 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()); + // There were no alerts or errors. + EXPECT_TRUE(mock_bindings.GetAlerts().empty()); + EXPECT_TRUE(mock_bindings.GetErrors().empty()); } // This test runs a weird PAC script that yields a never ending sequence @@ -508,25 +435,21 @@ TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) { // DNS resolves per request limit (20) after which every DNS resolve will // fail. TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddRule("host*", "166.155.144.11"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "global_sideffects3.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "global_sideffects3.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); EXPECT_EQ(20u, host_resolver.num_resolve()); @@ -540,11 +463,11 @@ TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) { "null:21", proxy_info.proxy_server().ToURI()); // No errors. - EXPECT_EQ("", error_observer->GetOutput()); + EXPECT_TRUE(mock_bindings.GetErrors().empty()); - // Check the NetLogs -- 1 alert was logged. - EXPECT_EQ(1u, log.GetSize()); - EXPECT_EQ(1u, request_log.GetSize()); + // 1 alert. + EXPECT_EQ(1u, mock_bindings.GetAlerts().size()); + EXPECT_EQ("iteration: 21", mock_bindings.GetAlerts()[0]); } // This test runs a weird PAC script that yields a never ending sequence @@ -552,25 +475,21 @@ TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) { // DNS resolves per request limit (20) after which every DNS resolve will // fail. TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddRule("host*", "166.155.144.11"); host_resolver.rules()->AddRule("*", "122.133.144.155"); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "global_sideffects4.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "global_sideffects4.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); EXPECT_EQ(20u, host_resolver.num_resolve()); @@ -578,26 +497,23 @@ TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) { EXPECT_EQ("null21:34", proxy_info.proxy_server().ToURI()); // No errors. - EXPECT_EQ("", error_observer->GetOutput()); + EXPECT_TRUE(mock_bindings.GetErrors().empty()); - // Check the NetLogs -- 1 alert was logged. - EXPECT_EQ(1u, log.GetSize()); - EXPECT_EQ(1u, request_log.GetSize()); + // 1 alert. + EXPECT_EQ(1u, mock_bindings.GetAlerts().size()); + EXPECT_EQ("iteration: 21", mock_bindings.GetAlerts()[0]); } void DnsDuringInitHelper(bool synchronous_host_resolver) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; + MockBindings mock_bindings(&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"); - scoped_ptr<ProxyResolver> resolver = - CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), - "dns_during_init.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns_during_init.js"); // Initialization did 2 dnsResolves. EXPECT_EQ(2u, host_resolver.num_resolve()); @@ -611,10 +527,9 @@ void DnsDuringInitHelper(bool synchronous_host_resolver) { TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - callback.callback(), NULL, request_log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); // Fetched host1 and host2 again, since the ones done during initialization @@ -624,21 +539,10 @@ void DnsDuringInitHelper(bool synchronous_host_resolver) { 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - EXPECT_TRUE( - LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, - NetLog::PHASE_NONE)); - - EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson()); - EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson()); + // 2 alerts. + ASSERT_EQ(2u, mock_bindings.GetAlerts().size()); + EXPECT_EQ("Watsup", mock_bindings.GetAlerts()[0]); + EXPECT_EQ("Watsup2", mock_bindings.GetAlerts()[1]); } // Tests a PAC script which does DNS resolves during initialization. @@ -660,22 +564,21 @@ void CrashCallback(int) { // times. TEST_F(ProxyResolverV8TracingTest, CancelAll) { MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddSimulatedFailure("*"); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns.js"); const size_t kNumRequests = 5; ProxyInfo proxy_info[kNumRequests]; ProxyResolver::RequestHandle 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], - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info[i], + base::Bind(&CrashCallback), &request[i], + mock_bindings.CreateBindings()); } for (size_t i = 0; i < kNumRequests; ++i) { @@ -688,12 +591,12 @@ TEST_F(ProxyResolverV8TracingTest, CancelAll) { // times. TEST_F(ProxyResolverV8TracingTest, CancelSome) { MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddSimulatedFailure("*"); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns.js"); ProxyInfo proxy_info1; ProxyInfo proxy_info2; @@ -701,14 +604,12 @@ TEST_F(ProxyResolverV8TracingTest, CancelSome) { ProxyResolver::RequestHandle request2; TestCompletionCallback callback; - int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, - base::Bind(&CrashCallback), &request1, - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2, - callback.callback(), &request2, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + mock_bindings.CreateBindings()); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2, + callback.callback(), &request2, + mock_bindings.CreateBindings()); resolver->CancelRequest(request1); @@ -719,12 +620,12 @@ TEST_F(ProxyResolverV8TracingTest, CancelSome) { // posted a task the completion task back to origin thread. TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) { MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddSimulatedFailure("*"); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - nullptr, &host_resolver, make_scoped_ptr(error_observer), "error.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "error.js"); ProxyInfo proxy_info1; ProxyInfo proxy_info2; @@ -734,18 +635,17 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) { ProxyResolver::RequestHandle request3; TestCompletionCallback callback; - int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, - base::Bind(&CrashCallback), &request1, - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + mock_bindings.CreateBindings()); - rv = resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info2, - callback.callback(), &request2, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://throw-an-error"), &proxy_info2, + callback.callback(), &request2, + mock_bindings.CreateBindings()); // Wait until the first request has finished running on the worker thread. // (The second request will output an error). - error_observer->WaitForOutput(); + mock_bindings.WaitForError(); // Cancel the first request, while it has a pending completion task on // the origin thread. @@ -754,10 +654,9 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) { EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); // Start another request, to make sure it is able to complete. - rv = resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"), - &proxy_info3, callback.callback(), &request3, - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"), + &proxy_info3, callback.callback(), &request3, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); @@ -836,29 +735,25 @@ class BlockableHostResolver : public HostResolver { // when the request has an outstanding DNS request in flight. TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) { BlockableHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns.js"); ProxyInfo proxy_info1; ProxyInfo proxy_info2; ProxyResolver::RequestHandle request1; ProxyResolver::RequestHandle request2; - int rv = resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1, - base::Bind(&CrashCallback), &request1, - BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + mock_bindings.CreateBindings()); host_resolver.WaitUntilRequestIsReceived(); - rv = resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2, - base::Bind(&CrashCallback), &request2, - BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2, + base::Bind(&CrashCallback), &request2, + mock_bindings.CreateBindings()); host_resolver.WaitUntilRequestIsReceived(); @@ -872,7 +767,7 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) { // should have been cancelled. } -void CancelRequestAndPause(ProxyResolver* resolver, +void CancelRequestAndPause(ProxyResolverV8Tracing* resolver, ProxyResolver::RequestHandle request) { resolver->CancelRequest(request); @@ -887,19 +782,17 @@ void CancelRequestAndPause(ProxyResolver* resolver, // cancellation while the worker thread is waiting on this event. TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) { BlockableHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns.js"); ProxyInfo proxy_info; ProxyResolver::RequestHandle request; - int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - base::Bind(&CrashCallback), &request, - BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + base::Bind(&CrashCallback), &request, + mock_bindings.CreateBindings()); host_resolver.SetAction( base::Bind(CancelRequestAndPause, resolver.get(), request)); @@ -916,19 +809,17 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) { // the request is sent to the host resolver. TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) { MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "dns.js"); ProxyInfo proxy_info; ProxyResolver::RequestHandle request; - int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, - base::Bind(&CrashCallback), &request, - BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + base::Bind(&CrashCallback), &request, + mock_bindings.CreateBindings()); // 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 @@ -942,19 +833,15 @@ TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) { TEST_F(ProxyResolverV8TracingTest, CancelCreateResolverWhileOutstandingBlockingDns) { BlockableHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - ProxyResolverFactoryV8Tracing factory( - &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(), - base::Bind(&ReturnErrorObserver, - base::Passed(make_scoped_ptr(error_observer)))); - - scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverV8TracingFactory> factory( + ProxyResolverV8TracingFactory::Create()); + scoped_ptr<ProxyResolverV8Tracing> resolver; scoped_ptr<ProxyResolverFactory::Request> request; - int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), - &resolver, base::Bind(&CrashCallback), - &request); - EXPECT_EQ(ERR_IO_PENDING, rv); + factory->CreateProxyResolverV8Tracing( + LoadScriptData("dns_during_init.js"), mock_bindings.CreateBindings(), + &resolver, base::Bind(&CrashCallback), &request); host_resolver.WaitUntilRequestIsReceived(); @@ -964,20 +851,17 @@ TEST_F(ProxyResolverV8TracingTest, TEST_F(ProxyResolverV8TracingTest, DeleteFactoryWhileOutstandingBlockingDns) { BlockableHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverV8Tracing> resolver; scoped_ptr<ProxyResolverFactory::Request> request; { - ProxyResolverFactoryV8Tracing factory( - &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(), - base::Bind(&ReturnErrorObserver, - base::Passed(make_scoped_ptr(error_observer)))); - - int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), - &resolver, base::Bind(&CrashCallback), - &request); - EXPECT_EQ(ERR_IO_PENDING, rv); + scoped_ptr<ProxyResolverV8TracingFactory> factory( + ProxyResolverV8TracingFactory::Create()); + + factory->CreateProxyResolverV8Tracing( + LoadScriptData("dns_during_init.js"), mock_bindings.CreateBindings(), + &resolver, base::Bind(&CrashCallback), &request); host_resolver.WaitUntilRequestIsReceived(); } EXPECT_EQ(1, host_resolver.num_cancelled_requests()); @@ -985,20 +869,17 @@ TEST_F(ProxyResolverV8TracingTest, DeleteFactoryWhileOutstandingBlockingDns) { TEST_F(ProxyResolverV8TracingTest, ErrorLoadingScript) { BlockableHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); - ProxyResolverFactoryV8Tracing factory( - &host_resolver, nullptr, ProxyResolver::LoadStateChangedCallback(), - base::Bind(&ReturnErrorObserver, - base::Passed(make_scoped_ptr(error_observer)))); - - scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverV8TracingFactory> factory( + ProxyResolverV8TracingFactory::Create()); + scoped_ptr<ProxyResolverV8Tracing> resolver; scoped_ptr<ProxyResolverFactory::Request> request; TestCompletionCallback callback; - int rv = - factory.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver, - callback.callback(), &request); - EXPECT_EQ(ERR_IO_PENDING, rv); + factory->CreateProxyResolverV8Tracing( + LoadScriptData("error_on_load.js"), mock_bindings.CreateBindings(), + &resolver, callback.callback(), &request); + EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); EXPECT_FALSE(resolver); } @@ -1006,25 +887,21 @@ TEST_F(ProxyResolverV8TracingTest, ErrorLoadingScript) { // 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(ProxyResolverV8TracingTest, Terminate) { - TestNetLog log; - BoundTestNetLog request_log; MockCachingHostResolver host_resolver; - MockErrorObserver* error_observer = new MockErrorObserver; + MockBindings mock_bindings(&host_resolver); host_resolver.rules()->AddRule("host1", "182.111.0.222"); host_resolver.rules()->AddRule("host2", "111.33.44.55"); - scoped_ptr<ProxyResolver> resolver = CreateResolver( - &log, &host_resolver, make_scoped_ptr(error_observer), "terminate.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver = + CreateResolver(mock_bindings.CreateBindings(), "terminate.js"); TestCompletionCallback callback; ProxyInfo proxy_info; - int rv = - resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, - callback.callback(), NULL, request_log.bound()); - - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, + callback.callback(), NULL, + mock_bindings.CreateBindings()); EXPECT_EQ(OK, callback.WaitForResult()); // The test does 2 DNS resolutions. @@ -1032,11 +909,9 @@ TEST_F(ProxyResolverV8TracingTest, Terminate) { 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()); + // No errors or alerts. + EXPECT_TRUE(mock_bindings.GetErrors().empty()); + EXPECT_TRUE(mock_bindings.GetAlerts().empty()); } // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run @@ -1048,6 +923,7 @@ TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) { // Setup resolver0 // ------------------------ MockHostResolver host_resolver0; + MockBindings mock_bindings0(&host_resolver0); host_resolver0.rules()->AddRuleForAddressFamily( "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44"); host_resolver0.rules() @@ -1059,38 +935,35 @@ TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) { host_resolver0.rules()->AddRuleForAddressFamily( "*", ADDRESS_FAMILY_IPV4, "122.133.144.155"); host_resolver0.rules()->AddRule("*", "133.122.100.200"); - scoped_ptr<ProxyResolver> resolver0 = - CreateResolver(nullptr, &host_resolver0, - make_scoped_ptr(new MockErrorObserver), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver0 = + CreateResolver(mock_bindings0.CreateBindings(), "dns.js"); // ------------------------ // Setup resolver1 // ------------------------ - scoped_ptr<ProxyResolver> resolver1 = - CreateResolver(nullptr, &host_resolver0, - make_scoped_ptr(new MockErrorObserver), "dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver1 = + CreateResolver(mock_bindings0.CreateBindings(), "dns.js"); // ------------------------ // Setup resolver2 // ------------------------ - scoped_ptr<ProxyResolver> resolver2 = - CreateResolver(nullptr, &host_resolver0, - make_scoped_ptr(new MockErrorObserver), "simple.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver2 = + CreateResolver(mock_bindings0.CreateBindings(), "simple.js"); // ------------------------ // Setup resolver3 // ------------------------ MockHostResolver host_resolver3; + MockBindings mock_bindings3(&host_resolver3); host_resolver3.rules()->AddRule("foo", "166.155.144.33"); - scoped_ptr<ProxyResolver> resolver3 = - CreateResolver(nullptr, &host_resolver3, - make_scoped_ptr(new MockErrorObserver), "simple_dns.js"); + scoped_ptr<ProxyResolverV8Tracing> resolver3 = + CreateResolver(mock_bindings3.CreateBindings(), "simple_dns.js"); // ------------------------ // Queue up work for each resolver (which will be running in parallel). // ------------------------ - ProxyResolver* resolver[] = { + ProxyResolverV8Tracing* resolver[] = { resolver0.get(), resolver1.get(), resolver2.get(), resolver3.get(), }; @@ -1102,10 +975,10 @@ TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) { for (size_t i = 0; i < kNumResults; ++i) { size_t resolver_i = i % kNumResolvers; - int rv = resolver[resolver_i]->GetProxyForURL( + resolver[resolver_i]->GetProxyForURL( GURL("http://foo/"), &proxy_info[i], callback[i].callback(), NULL, - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); + resolver_i == 3 ? mock_bindings3.CreateBindings() + : mock_bindings0.CreateBindings()); } // ------------------------ diff --git a/net/proxy/proxy_resolver_v8_tracing_wrapper.cc b/net/proxy/proxy_resolver_v8_tracing_wrapper.cc new file mode 100644 index 0000000..01dde66 --- /dev/null +++ b/net/proxy/proxy_resolver_v8_tracing_wrapper.cc @@ -0,0 +1,193 @@ +// Copyright 2015 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/proxy_resolver_v8_tracing_wrapper.h" + +#include <string> + +#include "base/bind.h" +#include "base/values.h" +#include "net/base/net_errors.h" +#include "net/log/net_log.h" +#include "net/proxy/proxy_resolver_error_observer.h" + +namespace net { +namespace { + +// Returns event parameters for a PAC error message (line number + message). +scoped_ptr<base::Value> NetLogErrorCallback( + int line_number, + const base::string16* message, + NetLogCaptureMode /* capture_mode */) { + scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + dict->SetInteger("line_number", line_number); + dict->SetString("message", *message); + return dict.Pass(); +} + +class BindingsImpl : public ProxyResolverV8Tracing::Bindings { + public: + BindingsImpl(ProxyResolverErrorObserver* error_observer, + HostResolver* host_resolver, + NetLog* net_log, + const BoundNetLog& bound_net_log) + : error_observer_(error_observer), + host_resolver_(host_resolver), + net_log_(net_log), + bound_net_log_(bound_net_log) {} + + // ProxyResolverV8Tracing::Bindings overrides. + void Alert(const base::string16& message) override { + // Send to the NetLog. + LogEventToCurrentRequestAndGlobally( + NetLog::TYPE_PAC_JAVASCRIPT_ALERT, + NetLog::StringCallback("message", &message)); + } + + void OnError(int line_number, const base::string16& message) override { + // Send the error to the NetLog. + LogEventToCurrentRequestAndGlobally( + NetLog::TYPE_PAC_JAVASCRIPT_ERROR, + base::Bind(&NetLogErrorCallback, line_number, &message)); + if (error_observer_) + error_observer_->OnPACScriptError(line_number, message); + } + + HostResolver* GetHostResolver() override { return host_resolver_; } + + BoundNetLog GetBoundNetLog() override { return bound_net_log_; } + + private: + void LogEventToCurrentRequestAndGlobally( + NetLog::EventType type, + const NetLog::ParametersCallback& parameters_callback) { + bound_net_log_.AddEvent(type, parameters_callback); + + // Emit to the global NetLog event stream. + if (net_log_) + net_log_->AddGlobalEntry(type, parameters_callback); + } + + ProxyResolverErrorObserver* error_observer_; + HostResolver* host_resolver_; + NetLog* net_log_; + BoundNetLog bound_net_log_; +}; + +class ProxyResolverV8TracingWrapper : public ProxyResolver { + public: + ProxyResolverV8TracingWrapper( + scoped_ptr<ProxyResolverV8Tracing> resolver_impl, + NetLog* net_log, + HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer); + + int GetProxyForURL(const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + RequestHandle* request, + const BoundNetLog& net_log) override; + + void CancelRequest(RequestHandle request) override; + + LoadState GetLoadState(RequestHandle request) const override; + + private: + scoped_ptr<ProxyResolverV8Tracing> resolver_impl_; + NetLog* net_log_; + HostResolver* host_resolver_; + scoped_ptr<ProxyResolverErrorObserver> error_observer_; + + DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8TracingWrapper); +}; + +ProxyResolverV8TracingWrapper::ProxyResolverV8TracingWrapper( + scoped_ptr<ProxyResolverV8Tracing> resolver_impl, + NetLog* net_log, + HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer) + : resolver_impl_(resolver_impl.Pass()), + net_log_(net_log), + host_resolver_(host_resolver), + error_observer_(error_observer.Pass()) { +} + +int ProxyResolverV8TracingWrapper::GetProxyForURL( + const GURL& url, + ProxyInfo* results, + const CompletionCallback& callback, + RequestHandle* request, + const BoundNetLog& net_log) { + resolver_impl_->GetProxyForURL( + url, results, callback, request, + make_scoped_ptr(new BindingsImpl(error_observer_.get(), host_resolver_, + net_log_, net_log))); + return ERR_IO_PENDING; +} + +void ProxyResolverV8TracingWrapper::CancelRequest(RequestHandle request) { + resolver_impl_->CancelRequest(request); +} + +LoadState ProxyResolverV8TracingWrapper::GetLoadState( + RequestHandle request) const { + return resolver_impl_->GetLoadState(request); +} + +} // namespace + +ProxyResolverFactoryV8TracingWrapper::ProxyResolverFactoryV8TracingWrapper( + HostResolver* host_resolver, + NetLog* net_log, + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& + error_observer_factory) + : ProxyResolverFactory(true), + factory_impl_(ProxyResolverV8TracingFactory::Create()), + host_resolver_(host_resolver), + net_log_(net_log), + error_observer_factory_(error_observer_factory) { +} + +ProxyResolverFactoryV8TracingWrapper::~ProxyResolverFactoryV8TracingWrapper() = + default; + +int ProxyResolverFactoryV8TracingWrapper::CreateProxyResolver( + const scoped_refptr<ProxyResolverScriptData>& pac_script, + scoped_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + scoped_ptr<Request>* request) { + scoped_ptr<scoped_ptr<ProxyResolverV8Tracing>> v8_resolver( + new scoped_ptr<ProxyResolverV8Tracing>); + scoped_ptr<ProxyResolverErrorObserver> error_observer = + error_observer_factory_.Run(); + // Note: Argument evaluation order is unspecified, so make copies before + // passing |v8_resolver| and |error_observer|. + scoped_ptr<ProxyResolverV8Tracing>* v8_resolver_local = v8_resolver.get(); + ProxyResolverErrorObserver* error_observer_local = error_observer.get(); + factory_impl_->CreateProxyResolverV8Tracing( + pac_script, + make_scoped_ptr(new BindingsImpl(error_observer_local, host_resolver_, + net_log_, BoundNetLog())), + v8_resolver_local, + base::Bind(&ProxyResolverFactoryV8TracingWrapper::OnProxyResolverCreated, + base::Unretained(this), base::Passed(&v8_resolver), resolver, + callback, base::Passed(&error_observer)), + request); + return ERR_IO_PENDING; +} + +void ProxyResolverFactoryV8TracingWrapper::OnProxyResolverCreated( + scoped_ptr<scoped_ptr<ProxyResolverV8Tracing>> v8_resolver, + scoped_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + scoped_ptr<ProxyResolverErrorObserver> error_observer, + int error) { + if (error == OK) { + resolver->reset(new ProxyResolverV8TracingWrapper( + v8_resolver->Pass(), net_log_, host_resolver_, error_observer.Pass())); + } + callback.Run(error); +} + +} // namespace net diff --git a/net/proxy/proxy_resolver_v8_tracing_wrapper.h b/net/proxy/proxy_resolver_v8_tracing_wrapper.h new file mode 100644 index 0000000..28343d8 --- /dev/null +++ b/net/proxy/proxy_resolver_v8_tracing_wrapper.h @@ -0,0 +1,65 @@ +// Copyright 2015 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. + +#ifndef NET_PROXY_PROXY_RESOLVER_V8_TRACING_WRAPPER_H_ +#define NET_PROXY_PROXY_RESOLVER_V8_TRACING_WRAPPER_H_ + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "net/base/net_export.h" +#include "net/proxy/proxy_resolver.h" +#include "net/proxy/proxy_resolver_factory.h" +#include "net/proxy/proxy_resolver_v8_tracing.h" + +namespace net { + +class HostResolver; +class NetLog; +class ProxyResolverErrorObserver; + +// A wrapper for ProxyResolverV8TracingFactory that implements the +// ProxyResolverFactory interface. +class NET_EXPORT ProxyResolverFactoryV8TracingWrapper + : public ProxyResolverFactory { + public: + // Note that |host_resolver| and |net_log| are expected to outlive |this| and + // any ProxyResolver instances created using |this|. |error_observer_factory| + // will be invoked once per CreateProxyResolver() call to create a + // ProxyResolverErrorObserver to be used by the ProxyResolver instance + // returned by that call. + ProxyResolverFactoryV8TracingWrapper( + HostResolver* host_resolver, + NetLog* net_log, + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()>& + error_observer_factory); + ~ProxyResolverFactoryV8TracingWrapper() override; + + // ProxyResolverFactory override. + int CreateProxyResolver( + const scoped_refptr<ProxyResolverScriptData>& pac_script, + scoped_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + scoped_ptr<Request>* request) override; + + private: + void OnProxyResolverCreated( + scoped_ptr<scoped_ptr<ProxyResolverV8Tracing>> v8_resolver, + scoped_ptr<ProxyResolver>* resolver, + const CompletionCallback& callback, + scoped_ptr<ProxyResolverErrorObserver> error_observer, + int error); + + scoped_ptr<ProxyResolverV8TracingFactory> factory_impl_; + HostResolver* const host_resolver_; + NetLog* const net_log_; + const base::Callback<scoped_ptr<ProxyResolverErrorObserver>()> + error_observer_factory_; + + DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryV8TracingWrapper); +}; + +} // namespace net + +#endif // NET_PROXY_PROXY_RESOLVER_V8_TRACING_WRAPPER_H_ diff --git a/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc new file mode 100644 index 0000000..7a77b82 --- /dev/null +++ b/net/proxy/proxy_resolver_v8_tracing_wrapper_unittest.cc @@ -0,0 +1,1145 @@ +// 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/proxy_resolver_v8_tracing_wrapper.h" + +#include <string> + +#include "base/files/file_util.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.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.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/proxy_info.h" +#include "net/proxy/proxy_resolver_error_observer.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace net { + +namespace { + +class ProxyResolverV8TracingWrapperTest : public testing::Test { + 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::MessageLoop::current()->RunUntilIdle(); + } +}; + +scoped_refptr<ProxyResolverScriptData> LoadScriptData(const char* filename) { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &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 ProxyResolverScriptData::FromUTF8(file_contents); +} + +scoped_ptr<ProxyResolverErrorObserver> ReturnErrorObserver( + scoped_ptr<ProxyResolverErrorObserver> error_observer) { + return error_observer; +} + +scoped_ptr<ProxyResolver> CreateResolver( + NetLog* net_log, + HostResolver* host_resolver, + scoped_ptr<ProxyResolverErrorObserver> error_observer, + const char* filename) { + scoped_ptr<ProxyResolver> resolver; + ProxyResolverFactoryV8TracingWrapper factory( + host_resolver, net_log, + base::Bind(&ReturnErrorObserver, base::Passed(&error_observer))); + TestCompletionCallback callback; + scoped_ptr<ProxyResolverFactory::Request> request; + int rv = factory.CreateProxyResolver(LoadScriptData(filename), &resolver, + callback.callback(), &request); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + EXPECT_TRUE(resolver); + return resolver.Pass(); +} + +class MockErrorObserver : public ProxyResolverErrorObserver { + public: + MockErrorObserver() : event_(true, false) {} + + void OnPACScriptError(int line_number, const base::string16& error) override { + { + base::AutoLock l(lock_); + output += base::StringPrintf("Error: line %d: %s\n", line_number, + base::UTF16ToASCII(error).c_str()); + } + event_.Signal(); + } + + std::string GetOutput() { + base::AutoLock l(lock_); + return output; + } + + void WaitForOutput() { event_.Wait(); } + + private: + base::Lock lock_; + std::string output; + + base::WaitableEvent event_; +}; + +TEST_F(ProxyResolverV8TracingWrapperTest, Simple) { + TestNetLog log; + BoundTestNetLog request_log; + MockCachingHostResolver host_resolver; + MockErrorObserver* error_observer = new MockErrorObserver; + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "simple.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + 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; + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "error.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); + + 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, + NetLog::PHASE_NONE)); + EXPECT_TRUE(LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR, + NetLog::PHASE_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; + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "too_many_alerts.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + // 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, NetLog::PHASE_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; + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "too_many_empty_alerts.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, NetLog::PHASE_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"); + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + // 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, + NetLog::PHASE_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"); + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "simple_dns.js"); + + TestCompletionCallback callback1; + TestCompletionCallback callback2; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, + callback1.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback1.WaitForResult()); + + // 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()); + + rv = + resolver->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info, + callback2.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback2.WaitForResult()); + + 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"); + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects1.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + // 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, + NetLog::PHASE_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"); + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects2.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + 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"); + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects3.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + 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"); + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(error_observer), + "global_sideffects4.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + 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"); + + scoped_ptr<ProxyResolver> resolver = + CreateResolver(&log, &host_resolver, make_scoped_ptr(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; + + int rv = + resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + // 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, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, + NetLog::PHASE_NONE)); + EXPECT_TRUE(LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT, + NetLog::PHASE_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("*"); + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + + const size_t kNumRequests = 5; + ProxyInfo proxy_info[kNumRequests]; + ProxyResolver::RequestHandle 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], + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + } + + for (size_t i = 0; i < kNumRequests; ++i) { + resolver->CancelRequest(request[i]); + } +} + +// 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("*"); + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + + ProxyInfo proxy_info1; + ProxyInfo proxy_info2; + ProxyResolver::RequestHandle request1; + ProxyResolver::RequestHandle request2; + TestCompletionCallback callback; + + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info2, + callback.callback(), &request2, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + resolver->CancelRequest(request1); + + EXPECT_EQ(OK, callback.WaitForResult()); +} + +// 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("*"); + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "error.js"); + + ProxyInfo proxy_info1; + ProxyInfo proxy_info2; + ProxyInfo proxy_info3; + ProxyResolver::RequestHandle request1; + ProxyResolver::RequestHandle request2; + ProxyResolver::RequestHandle request3; + TestCompletionCallback callback; + + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = resolver->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info2, + callback.callback(), &request2, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + // Wait until the first request has finished running on the worker thread. + // (The second request will output an error). + error_observer->WaitForOutput(); + + // Cancel the first request, while it has a pending completion task on + // the origin thread. + resolver->CancelRequest(request1); + + EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); + + // Start another request, to make sure it is able to complete. + rv = resolver->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"), + &proxy_info3, callback.callback(), &request3, + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + EXPECT_EQ(OK, callback.WaitForResult()); + + EXPECT_EQ("i-approve-this-message:42", proxy_info3.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) {} + + int Resolve(const RequestInfo& info, + RequestPriority priority, + AddressList* addresses, + const CompletionCallback& callback, + RequestHandle* out_req, + const BoundNetLog& 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::MessageLoop::current()->Quit(); + + // 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 = reinterpret_cast<RequestHandle*>(1); // Magic value. + + // 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 BoundNetLog& net_log) override { + NOTREACHED(); + return ERR_DNS_CACHE_MISS; + } + + void CancelRequest(RequestHandle req) override { + EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req); + 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::MessageLoop::current()->Run(); + DCHECK(waiting_for_resolve_); + waiting_for_resolve_ = false; + } + + int num_cancelled_requests() const { return num_cancelled_requests_; } + + private: + 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; + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + + ProxyInfo proxy_info1; + ProxyInfo proxy_info2; + ProxyResolver::RequestHandle request1; + ProxyResolver::RequestHandle request2; + + int rv = resolver->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1, + base::Bind(&CrashCallback), &request1, + BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + + host_resolver.WaitUntilRequestIsReceived(); + + rv = resolver->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2, + base::Bind(&CrashCallback), &request2, + BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + + host_resolver.WaitUntilRequestIsReceived(); + + resolver->CancelRequest(request1); + resolver->CancelRequest(request2); + + 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(ProxyResolver* resolver, + ProxyResolver::RequestHandle request) { + resolver->CancelRequest(request); + + // 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; + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + + ProxyInfo proxy_info; + ProxyResolver::RequestHandle request; + + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + base::Bind(&CrashCallback), &request, + BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + + host_resolver.SetAction( + base::Bind(CancelRequestAndPause, resolver.get(), request)); + + host_resolver.WaitUntilRequestIsReceived(); + + // At this point the host resolver ran Resolve(), and should have cancelled + // the request. + + EXPECT_EQ(1, host_resolver.num_cancelled_requests()); +} + +// 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; + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + nullptr, &host_resolver, make_scoped_ptr(error_observer), "dns.js"); + + ProxyInfo proxy_info; + ProxyResolver::RequestHandle request; + + int rv = resolver->GetProxyForURL(GURL("http://foo/"), &proxy_info, + base::Bind(&CrashCallback), &request, + BoundNetLog()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + + // 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)); + resolver->CancelRequest(request); + + 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(make_scoped_ptr(error_observer)))); + + scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverFactory::Request> request; + int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), + &resolver, base::Bind(&CrashCallback), + &request); + EXPECT_EQ(ERR_IO_PENDING, rv); + + 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; + + scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverFactory::Request> request; + { + ProxyResolverFactoryV8TracingWrapper factory( + &host_resolver, nullptr, + base::Bind(&ReturnErrorObserver, + base::Passed(make_scoped_ptr(error_observer)))); + + int rv = factory.CreateProxyResolver(LoadScriptData("dns_during_init.js"), + &resolver, base::Bind(&CrashCallback), + &request); + EXPECT_EQ(ERR_IO_PENDING, rv); + 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(make_scoped_ptr(error_observer)))); + + scoped_ptr<ProxyResolver> resolver; + scoped_ptr<ProxyResolverFactory::Request> request; + TestCompletionCallback callback; + int rv = + factory.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver, + callback.callback(), &request); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult()); + 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"); + + scoped_ptr<ProxyResolver> resolver = CreateResolver( + &log, &host_resolver, make_scoped_ptr(error_observer), "terminate.js"); + + TestCompletionCallback callback; + ProxyInfo proxy_info; + + int rv = + resolver->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info, + callback.callback(), NULL, request_log.bound()); + + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + // 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"); + scoped_ptr<ProxyResolver> resolver0 = + CreateResolver(nullptr, &host_resolver0, + make_scoped_ptr(new MockErrorObserver), "dns.js"); + + // ------------------------ + // Setup resolver1 + // ------------------------ + scoped_ptr<ProxyResolver> resolver1 = + CreateResolver(nullptr, &host_resolver0, + make_scoped_ptr(new MockErrorObserver), "dns.js"); + + // ------------------------ + // Setup resolver2 + // ------------------------ + scoped_ptr<ProxyResolver> resolver2 = + CreateResolver(nullptr, &host_resolver0, + make_scoped_ptr(new MockErrorObserver), "simple.js"); + + // ------------------------ + // Setup resolver3 + // ------------------------ + MockHostResolver host_resolver3; + host_resolver3.rules()->AddRule("foo", "166.155.144.33"); + scoped_ptr<ProxyResolver> resolver3 = + CreateResolver(nullptr, &host_resolver3, + make_scoped_ptr(new 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]; + + 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(), NULL, + BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + } + + // ------------------------ + // 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_EQ(OK, callback[i].WaitForResult()); + + 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 diff --git a/net/proxy/proxy_service_v8.cc b/net/proxy/proxy_service_v8.cc index 3634613..46a6605 100644 --- a/net/proxy/proxy_service_v8.cc +++ b/net/proxy/proxy_service_v8.cc @@ -10,7 +10,7 @@ #include "net/proxy/network_delegate_error_observer.h" #include "net/proxy/proxy_resolver.h" #include "net/proxy/proxy_resolver_factory.h" -#include "net/proxy/proxy_resolver_v8_tracing.h" +#include "net/proxy/proxy_resolver_v8_tracing_wrapper.h" #include "net/proxy/proxy_service.h" namespace net { @@ -30,8 +30,8 @@ ProxyService* CreateProxyServiceUsingV8ProxyResolver( ProxyService* proxy_service = new ProxyService( proxy_config_service, - make_scoped_ptr(new ProxyResolverFactoryV8Tracing( - host_resolver, net_log, ProxyResolver::LoadStateChangedCallback(), + make_scoped_ptr(new ProxyResolverFactoryV8TracingWrapper( + host_resolver, net_log, base::Bind(&NetworkDelegateErrorObserver::Create, network_delegate, base::ThreadTaskRunnerHandle::Get()))), net_log); |