1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "services/proxy_resolver/proxy_resolver_factory_impl.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/optional.h"
12 #include "base/run_loop.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/test/task_environment.h"
15 #include "mojo/public/cpp/bindings/receiver.h"
16 #include "mojo/public/cpp/bindings/remote.h"
17 #include "net/base/completion_once_callback.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/proxy_resolution/mock_proxy_resolver.h"
20 #include "net/proxy_resolution/proxy_resolve_dns_operation.h"
21 #include "net/test/event_waiter.h"
22 #include "net/test/gtest_util.h"
23 #include "services/proxy_resolver/proxy_resolver_v8_tracing.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 using net::test::IsError;
28 using net::test::IsOk;
29 
30 namespace proxy_resolver {
31 namespace {
32 
33 const char kScriptData[] = "FooBarBaz";
34 
35 class FakeProxyResolver : public ProxyResolverV8Tracing {
36  public:
FakeProxyResolver(base::OnceClosure on_destruction)37   explicit FakeProxyResolver(base::OnceClosure on_destruction)
38       : on_destruction_(std::move(on_destruction)) {}
39 
~FakeProxyResolver()40   ~FakeProxyResolver() override { std::move(on_destruction_).Run(); }
41 
42  private:
43   // ProxyResolverV8Tracing overrides.
GetProxyForURL(const GURL & url,const net::NetworkIsolationKey & network_isolation_key,net::ProxyInfo * results,net::CompletionOnceCallback callback,std::unique_ptr<net::ProxyResolver::Request> * request,std::unique_ptr<Bindings> bindings)44   void GetProxyForURL(const GURL& url,
45                       const net::NetworkIsolationKey& network_isolation_key,
46                       net::ProxyInfo* results,
47                       net::CompletionOnceCallback callback,
48                       std::unique_ptr<net::ProxyResolver::Request>* request,
49                       std::unique_ptr<Bindings> bindings) override {}
50 
51   base::OnceClosure on_destruction_;
52 };
53 
54 enum Event {
55   NONE,
56   RESOLVER_CREATED,
57   CONNECTION_ERROR,
58   RESOLVER_DESTROYED,
59 };
60 
61 class TestProxyResolverFactory : public ProxyResolverV8TracingFactory {
62  public:
63   struct PendingRequest {
64     std::unique_ptr<ProxyResolverV8Tracing>* resolver;
65     net::CompletionOnceCallback callback;
66   };
67 
TestProxyResolverFactory(net::EventWaiter<Event> * waiter)68   explicit TestProxyResolverFactory(net::EventWaiter<Event>* waiter)
69       : waiter_(waiter) {}
70 
~TestProxyResolverFactory()71   ~TestProxyResolverFactory() override {}
72 
CreateProxyResolverV8Tracing(const scoped_refptr<net::PacFileData> & pac_script,std::unique_ptr<ProxyResolverV8Tracing::Bindings> bindings,std::unique_ptr<ProxyResolverV8Tracing> * resolver,net::CompletionOnceCallback callback,std::unique_ptr<net::ProxyResolverFactory::Request> * request)73   void CreateProxyResolverV8Tracing(
74       const scoped_refptr<net::PacFileData>& pac_script,
75       std::unique_ptr<ProxyResolverV8Tracing::Bindings> bindings,
76       std::unique_ptr<ProxyResolverV8Tracing>* resolver,
77       net::CompletionOnceCallback callback,
78       std::unique_ptr<net::ProxyResolverFactory::Request>* request) override {
79     requests_handled_++;
80     waiter_->NotifyEvent(RESOLVER_CREATED);
81     EXPECT_EQ(base::ASCIIToUTF16(kScriptData), pac_script->utf16());
82     EXPECT_TRUE(resolver);
83     pending_request_ = std::make_unique<PendingRequest>();
84     pending_request_->resolver = resolver;
85     pending_request_->callback = std::move(callback);
86 
87     ASSERT_TRUE(bindings);
88 
89     bindings->Alert(base::ASCIIToUTF16("alert"));
90     bindings->OnError(10, base::ASCIIToUTF16("error"));
91     EXPECT_TRUE(bindings->GetHostResolver());
92   }
93 
requests_handled()94   size_t requests_handled() { return requests_handled_; }
pending_request()95   PendingRequest* pending_request() { return pending_request_.get(); }
96 
97  private:
98   net::EventWaiter<Event>* waiter_;
99   size_t requests_handled_ = 0;
100   std::unique_ptr<PendingRequest> pending_request_;
101 };
102 
103 class TestProxyResolverFactoryImpl : public ProxyResolverFactoryImpl {
104  public:
TestProxyResolverFactoryImpl(mojo::PendingReceiver<mojom::ProxyResolverFactory> receiver,std::unique_ptr<ProxyResolverV8TracingFactory> factory)105   TestProxyResolverFactoryImpl(
106       mojo::PendingReceiver<mojom::ProxyResolverFactory> receiver,
107       std::unique_ptr<ProxyResolverV8TracingFactory> factory)
108       : ProxyResolverFactoryImpl(std::move(receiver), std::move(factory)) {}
109 };
110 
111 }  // namespace
112 
113 class ProxyResolverFactoryImplTest
114     : public testing::Test,
115       public mojom::ProxyResolverFactoryRequestClient {
116  public:
ProxyResolverFactoryImplTest()117   ProxyResolverFactoryImplTest() {
118     std::unique_ptr<TestProxyResolverFactory> test_factory =
119         std::make_unique<TestProxyResolverFactory>(&waiter_);
120     mock_factory_ = test_factory.get();
121     mock_factory_impl_ = std::make_unique<TestProxyResolverFactoryImpl>(
122         factory_.BindNewPipeAndPassReceiver(), std::move(test_factory));
123     factory_.set_idle_handler(
124         base::TimeDelta(),
125         base::BindRepeating(&ProxyResolverFactoryImplTest::OnFactoryIdle,
126                             base::Unretained(this)));
127   }
128 
129   ~ProxyResolverFactoryImplTest() override = default;
130 
OnDisconnect()131   void OnDisconnect() { waiter_.NotifyEvent(CONNECTION_ERROR); }
132 
OnFakeProxyInstanceDestroyed()133   void OnFakeProxyInstanceDestroyed() {
134     instances_destroyed_++;
135     waiter_.NotifyEvent(RESOLVER_DESTROYED);
136   }
137 
ReportResult(int32_t error)138   void ReportResult(int32_t error) override {
139     std::move(create_callback_).Run(error);
140   }
141 
Alert(const std::string & message)142   void Alert(const std::string& message) override {}
143 
OnError(int32_t line_number,const std::string & message)144   void OnError(int32_t line_number, const std::string& message) override {}
145 
ResolveDns(const std::string & hostname,net::ProxyResolveDnsOperation operation,const net::NetworkIsolationKey & network_isolation_key,mojo::PendingRemote<mojom::HostResolverRequestClient> client)146   void ResolveDns(
147       const std::string& hostname,
148       net::ProxyResolveDnsOperation operation,
149       const net::NetworkIsolationKey& network_isolation_key,
150       mojo::PendingRemote<mojom::HostResolverRequestClient> client) override {}
151 
set_idle_callback(base::OnceClosure callback)152   void set_idle_callback(base::OnceClosure callback) {
153     idle_callback_ = std::move(callback);
154   }
155 
156  protected:
OnFactoryIdle()157   void OnFactoryIdle() {
158     if (idle_callback_)
159       std::move(idle_callback_).Run();
160   }
161 
162   base::test::TaskEnvironment task_environment_;
163   std::unique_ptr<TestProxyResolverFactoryImpl> mock_factory_impl_;
164   TestProxyResolverFactory* mock_factory_;
165   mojo::Remote<mojom::ProxyResolverFactory> factory_;
166 
167   int instances_destroyed_ = 0;
168   net::CompletionOnceCallback create_callback_;
169 
170   base::OnceClosure idle_callback_;
171 
172   net::EventWaiter<Event> waiter_;
173 };
174 
TEST_F(ProxyResolverFactoryImplTest,DisconnectProxyResolverClient)175 TEST_F(ProxyResolverFactoryImplTest, DisconnectProxyResolverClient) {
176   mojo::Remote<mojom::ProxyResolver> proxy_resolver;
177   mojo::PendingRemote<mojom::ProxyResolverFactoryRequestClient> client;
178   mojo::Receiver<ProxyResolverFactoryRequestClient> client_receiver(
179       this, client.InitWithNewPipeAndPassReceiver());
180   factory_->CreateResolver(kScriptData,
181                            proxy_resolver.BindNewPipeAndPassReceiver(),
182                            std::move(client));
183   proxy_resolver.set_disconnect_handler(base::BindOnce(
184       &ProxyResolverFactoryImplTest::OnDisconnect, base::Unretained(this)));
185   waiter_.WaitForEvent(RESOLVER_CREATED);
186   EXPECT_EQ(0, instances_destroyed_);
187   ASSERT_EQ(1u, mock_factory_->requests_handled());
188   net::TestCompletionCallback create_callback;
189   create_callback_ = create_callback.callback();
190   ASSERT_TRUE(mock_factory_->pending_request());
191   *mock_factory_->pending_request()->resolver =
192       std::make_unique<FakeProxyResolver>(base::BindOnce(
193           &ProxyResolverFactoryImplTest::OnFakeProxyInstanceDestroyed,
194           base::Unretained(this)));
195   std::move(mock_factory_->pending_request()->callback).Run(net::OK);
196   EXPECT_THAT(create_callback.WaitForResult(), IsOk());
197 
198   base::RunLoop wait_for_idle_loop;
199   set_idle_callback(wait_for_idle_loop.QuitClosure());
200 
201   proxy_resolver.reset();
202   waiter_.WaitForEvent(RESOLVER_DESTROYED);
203   EXPECT_EQ(1, instances_destroyed_);
204 
205   wait_for_idle_loop.Run();
206 }
207 
208 // Same as above, but disconnect the factory right after the CreateResolver
209 // call, which should not prevent the request from succeeding.
TEST_F(ProxyResolverFactoryImplTest,DisconnectProxyResolverFactory)210 TEST_F(ProxyResolverFactoryImplTest, DisconnectProxyResolverFactory) {
211   mojo::Remote<mojom::ProxyResolver> proxy_resolver;
212   mojo::PendingRemote<mojom::ProxyResolverFactoryRequestClient> client;
213   mojo::Receiver<ProxyResolverFactoryRequestClient> client_receiver(
214       this, client.InitWithNewPipeAndPassReceiver());
215   factory_->CreateResolver(kScriptData,
216                            proxy_resolver.BindNewPipeAndPassReceiver(),
217                            std::move(client));
218 
219   proxy_resolver.set_disconnect_handler(base::BindOnce(
220       &ProxyResolverFactoryImplTest::OnDisconnect, base::Unretained(this)));
221   waiter_.WaitForEvent(RESOLVER_CREATED);
222   EXPECT_EQ(0, instances_destroyed_);
223   ASSERT_EQ(1u, mock_factory_->requests_handled());
224   net::TestCompletionCallback create_callback;
225   create_callback_ = create_callback.callback();
226   ASSERT_TRUE(mock_factory_->pending_request());
227   *mock_factory_->pending_request()->resolver =
228       std::make_unique<FakeProxyResolver>(base::BindOnce(
229           &ProxyResolverFactoryImplTest::OnFakeProxyInstanceDestroyed,
230           base::Unretained(this)));
231   std::move(mock_factory_->pending_request()->callback).Run(net::OK);
232   EXPECT_THAT(create_callback.WaitForResult(), IsOk());
233 
234   base::RunLoop wait_for_idle_loop;
235   set_idle_callback(wait_for_idle_loop.QuitClosure());
236 
237   proxy_resolver.reset();
238   waiter_.WaitForEvent(RESOLVER_DESTROYED);
239   EXPECT_EQ(1, instances_destroyed_);
240 
241   wait_for_idle_loop.Run();
242 }
243 
TEST_F(ProxyResolverFactoryImplTest,Error)244 TEST_F(ProxyResolverFactoryImplTest, Error) {
245   mojo::Remote<mojom::ProxyResolver> proxy_resolver;
246   mojo::PendingRemote<mojom::ProxyResolverFactoryRequestClient> client;
247   mojo::Receiver<ProxyResolverFactoryRequestClient> client_receiver(
248       this, client.InitWithNewPipeAndPassReceiver());
249   factory_->CreateResolver(kScriptData,
250                            proxy_resolver.BindNewPipeAndPassReceiver(),
251                            std::move(client));
252   proxy_resolver.set_disconnect_handler(base::BindOnce(
253       &ProxyResolverFactoryImplTest::OnDisconnect, base::Unretained(this)));
254   waiter_.WaitForEvent(RESOLVER_CREATED);
255   EXPECT_EQ(0, instances_destroyed_);
256   ASSERT_EQ(1u, mock_factory_->requests_handled());
257   net::TestCompletionCallback create_callback;
258   create_callback_ = create_callback.callback();
259   ASSERT_TRUE(mock_factory_->pending_request());
260   std::move(mock_factory_->pending_request()->callback)
261       .Run(net::ERR_PAC_SCRIPT_FAILED);
262   EXPECT_THAT(create_callback.WaitForResult(),
263               IsError(net::ERR_PAC_SCRIPT_FAILED));
264 }
265 
TEST_F(ProxyResolverFactoryImplTest,DisconnectClientDuringResolverCreation)266 TEST_F(ProxyResolverFactoryImplTest, DisconnectClientDuringResolverCreation) {
267   mojo::Remote<mojom::ProxyResolver> proxy_resolver;
268   mojo::PendingRemote<mojom::ProxyResolverFactoryRequestClient> client;
269   mojo::Receiver<ProxyResolverFactoryRequestClient> client_receiver(
270       this, client.InitWithNewPipeAndPassReceiver());
271   factory_->CreateResolver(kScriptData,
272                            proxy_resolver.BindNewPipeAndPassReceiver(),
273                            std::move(client));
274   proxy_resolver.set_disconnect_handler(base::BindOnce(
275       &ProxyResolverFactoryImplTest::OnDisconnect, base::Unretained(this)));
276   waiter_.WaitForEvent(RESOLVER_CREATED);
277   EXPECT_EQ(0, instances_destroyed_);
278   ASSERT_EQ(1u, mock_factory_->requests_handled());
279   client_receiver.reset();
280   waiter_.WaitForEvent(CONNECTION_ERROR);
281 }
282 
283 }  // namespace proxy_resolver
284