1 // Copyright 2017 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 "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
6 
7 #include <stdint.h>
8 
9 #include <vector>
10 
11 #include "base/macros.h"
12 #include "base/optional.h"
13 #include "base/process/process.h"
14 #include "base/run_loop.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/test/bind.h"
17 #include "base/time/time.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "content/public/browser/browser_task_traits.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/service_process_host.h"
22 #include "content/public/test/browser_test.h"
23 #include "mojo/public/cpp/bindings/receiver.h"
24 #include "mojo/public/cpp/bindings/remote.h"
25 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
26 
27 namespace {
28 
29 constexpr base::TimeDelta kServiceShutdownTimeout =
30     base::TimeDelta::FromSeconds(3);
31 
32 constexpr char kPacScript[] =
33     "function FindProxyForURL(url, host) { return 'PROXY proxy.example.com:1; "
34     "DIRECT'; }";
35 
36 // Dummy consumer of a ProxyResolverFactory. It just calls CreateResolver, and
37 // keeps Mojo objects alive from when CreateResolver() is called until it's
38 // destroyed.
39 class DumbProxyResolverFactoryRequestClient
40     : public proxy_resolver::mojom::ProxyResolverFactoryRequestClient {
41  public:
42   DumbProxyResolverFactoryRequestClient() = default;
43 
~DumbProxyResolverFactoryRequestClient()44   ~DumbProxyResolverFactoryRequestClient() override {
45     EXPECT_TRUE(receiver_.is_bound());
46   }
47 
CreateResolver(proxy_resolver::mojom::ProxyResolverFactory * resolver_factory)48   void CreateResolver(
49       proxy_resolver::mojom::ProxyResolverFactory* resolver_factory) {
50     mojo::PendingRemote<
51         proxy_resolver::mojom::ProxyResolverFactoryRequestClient>
52         resolver_client;
53     receiver_.Bind(resolver_client.InitWithNewPipeAndPassReceiver());
54     resolver_factory->CreateResolver(kPacScript,
55                                      resolver_.BindNewPipeAndPassReceiver(),
56                                      std::move(resolver_client));
57     // Wait for proxy resolver to be created, to avoid any races between
58     // creating one resolver and destroying the next one.
59     run_loop_.Run();
60   }
61 
62  private:
63   // ProxyResolverFactoryRequestClient implementation:
ReportResult(int32_t error)64   void ReportResult(int32_t error) override {
65     EXPECT_EQ(net::OK, error);
66     run_loop_.Quit();
67   }
Alert(const std::string & error)68   void Alert(const std::string& error) override {}
OnError(int32_t line_number,const std::string & error)69   void OnError(int32_t line_number, const std::string& error) override {}
ResolveDns(const std::string & hostname,net::ProxyResolveDnsOperation operation,const net::NetworkIsolationKey & network_isolation_key,mojo::PendingRemote<proxy_resolver::mojom::HostResolverRequestClient> client)70   void ResolveDns(
71       const std::string& hostname,
72       net::ProxyResolveDnsOperation operation,
73       const net::NetworkIsolationKey& network_isolation_key,
74       mojo::PendingRemote<proxy_resolver::mojom::HostResolverRequestClient>
75           client) override {}
76 
77   mojo::Remote<proxy_resolver::mojom::ProxyResolver> resolver_;
78   mojo::Receiver<proxy_resolver::mojom::ProxyResolverFactoryRequestClient>
79       receiver_{this};
80   base::RunLoop run_loop_;
81 };
82 
83 using ChromeMojoProxyResolverFactoryBrowserTest = InProcessBrowserTest;
84 
85 class ProxyResolverProcessObserver
86     : public content::ServiceProcessHost::Observer {
87  public:
ProxyResolverProcessObserver()88   ProxyResolverProcessObserver() {
89     content::ServiceProcessHost::AddObserver(this);
90   }
91 
~ProxyResolverProcessObserver()92   ~ProxyResolverProcessObserver() override {
93     content::ServiceProcessHost::RemoveObserver(this);
94   }
95 
is_service_running() const96   bool is_service_running() const { return is_service_running_; }
97 
WaitForLaunch()98   void WaitForLaunch() { launch_loop_.Run(); }
WaitForDeath()99   void WaitForDeath() { death_loop_.Run(); }
100 
101  private:
102   // content::ServiceProcessHost::Observer:
OnServiceProcessLaunched(const content::ServiceProcessInfo & info)103   void OnServiceProcessLaunched(
104       const content::ServiceProcessInfo& info) override {
105     if (!info.IsService<proxy_resolver::mojom::ProxyResolverFactory>())
106       return;
107 
108     ASSERT_FALSE(is_service_running_);
109     is_service_running_ = true;
110     launch_loop_.Quit();
111   }
112 
OnServiceProcessTerminatedNormally(const content::ServiceProcessInfo & info)113   void OnServiceProcessTerminatedNormally(
114       const content::ServiceProcessInfo& info) override {
115     if (!info.IsService<proxy_resolver::mojom::ProxyResolverFactory>())
116       return;
117 
118     ASSERT_TRUE(is_service_running_);
119     is_service_running_ = false;
120     death_loop_.Quit();
121   }
122 
123  private:
124   bool is_service_running_ = false;
125   base::RunLoop launch_loop_;
126   base::RunLoop death_loop_;
127 
128   DISALLOW_COPY_AND_ASSIGN(ProxyResolverProcessObserver);
129 };
130 
131 // Ensures the proxy resolver service is started correctly and stopped when no
132 // resolvers are open.
IN_PROC_BROWSER_TEST_F(ChromeMojoProxyResolverFactoryBrowserTest,ServiceLifecycle)133 IN_PROC_BROWSER_TEST_F(ChromeMojoProxyResolverFactoryBrowserTest,
134                        ServiceLifecycle) {
135   // Set up the ProxyResolverFactory.
136   mojo::Remote<proxy_resolver::mojom::ProxyResolverFactory> resolver_factory(
137       ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver());
138 
139   ProxyResolverProcessObserver observer;
140 
141   // Create a resolver, this should create and start the service.
142   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client1 =
143       std::make_unique<DumbProxyResolverFactoryRequestClient>();
144   resolver_client1->CreateResolver(resolver_factory.get());
145   observer.WaitForLaunch();
146 
147   // Create another resolver, no new service should be created (the listener
148   // will assert if that's the case).
149   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client2 =
150       std::make_unique<DumbProxyResolverFactoryRequestClient>();
151   resolver_client2->CreateResolver(resolver_factory.get());
152 
153   // Close one resolver.
154   resolver_client1.reset();
155 
156   // The service should not be stopped as there is another resolver.
157   // Wait a little bit and check it's still running.
158   {
159     base::RunLoop run_loop;
160     content::GetUIThreadTaskRunner({})->PostDelayedTask(
161         FROM_HERE, run_loop.QuitClosure(), kServiceShutdownTimeout);
162     run_loop.Run();
163   }
164 
165   EXPECT_TRUE(observer.is_service_running());
166 
167   // Close the last resolver, the service should now go away.
168   resolver_client2.reset();
169   observer.WaitForDeath();
170 }
171 
172 // Same as above, but destroys the ProxyResolverFactory, which should have no
173 // impact on resolver lifetime.
IN_PROC_BROWSER_TEST_F(ChromeMojoProxyResolverFactoryBrowserTest,DestroyFactory)174 IN_PROC_BROWSER_TEST_F(ChromeMojoProxyResolverFactoryBrowserTest,
175                        DestroyFactory) {
176   // Set up the ProxyResolverFactory.
177   mojo::Remote<proxy_resolver::mojom::ProxyResolverFactory> resolver_factory(
178       ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver());
179 
180   ProxyResolverProcessObserver observer;
181 
182   // Create a resolver, this should create and start the service.
183   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client1 =
184       std::make_unique<DumbProxyResolverFactoryRequestClient>();
185   resolver_client1->CreateResolver(resolver_factory.get());
186   observer.WaitForLaunch();
187 
188   // Create another resolver, no new service should be created (the listener
189   // will assert if that's the case).
190   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client2 =
191       std::make_unique<DumbProxyResolverFactoryRequestClient>();
192   resolver_client2->CreateResolver(resolver_factory.get());
193 
194   // Destroy the factory. Should not result in the resolver being destroyed.
195   resolver_factory.reset();
196 
197   // Close one resolver.
198   resolver_client1.reset();
199 
200   // The service should not be stopped as there is another resolver.
201   // Wait a little bit and check it's still running.
202   {
203     base::RunLoop run_loop;
204     content::GetUIThreadTaskRunner({})->PostDelayedTask(
205         FROM_HERE, run_loop.QuitClosure(), kServiceShutdownTimeout);
206     run_loop.Run();
207   }
208 
209   EXPECT_TRUE(observer.is_service_running());
210 
211   // Close the last resolver, the service should now go away.
212   resolver_client2.reset();
213   observer.WaitForDeath();
214 }
215 
216 // Make sure the service can be started again after it's been stopped.
IN_PROC_BROWSER_TEST_F(ChromeMojoProxyResolverFactoryBrowserTest,DestroyAndCreateService)217 IN_PROC_BROWSER_TEST_F(ChromeMojoProxyResolverFactoryBrowserTest,
218                        DestroyAndCreateService) {
219   // Set up the ProxyResolverFactory.
220   mojo::Remote<proxy_resolver::mojom::ProxyResolverFactory> resolver_factory(
221       ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver());
222 
223   base::Optional<ProxyResolverProcessObserver> observer{base::in_place};
224 
225   // Create a resolver, this should create and start the service.
226   std::unique_ptr<DumbProxyResolverFactoryRequestClient> resolver_client =
227       std::make_unique<DumbProxyResolverFactoryRequestClient>();
228   resolver_client->CreateResolver(resolver_factory.get());
229   observer->WaitForLaunch();
230 
231   // Close the resolver, the service should stop.
232   resolver_client.reset();
233   observer->WaitForDeath();
234 
235   observer.emplace();
236   // Create a resolver again, using the same factory. This should create and
237   // start the service.
238   resolver_client = std::make_unique<DumbProxyResolverFactoryRequestClient>();
239   resolver_client->CreateResolver(resolver_factory.get());
240   observer->WaitForLaunch();
241 
242   // Close the resolver again, the service should stop.
243   resolver_client.reset();
244   observer->WaitForDeath();
245 }
246 
247 }  // namespace
248