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