Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / services / proxy_resolver / proxy_resolver_impl_unittest.cc
1 // Copyright 2015 The Chromium Authors
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_impl.h"
6
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/ranges/algorithm.h"
15 #include "base/run_loop.h"
16 #include "base/test/task_environment.h"
17 #include "mojo/public/cpp/bindings/receiver.h"
18 #include "net/base/completion_once_callback.h"
19 #include "net/base/net_errors.h"
20 #include "net/base/proxy_server.h"
21 #include "net/proxy_resolution/mock_proxy_resolver.h"
22 #include "net/proxy_resolution/proxy_info.h"
23 #include "net/proxy_resolution/proxy_resolve_dns_operation.h"
24 #include "net/test/event_waiter.h"
25 #include "net/test/gtest_util.h"
26 #include "services/proxy_resolver/proxy_resolver_v8_tracing.h"
27 #include "services/service_manager/public/cpp/service_context_ref.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "url/gurl.h"
31 #include "url/origin.h"
32
33 using net::test::IsError;
34 using net::test::IsOk;
35
36 namespace proxy_resolver {
37 namespace {
38
39 class TestRequestClient : public mojom::ProxyResolverRequestClient {
40  public:
41   enum Event {
42     RESULT_RECEIVED,
43     CONNECTION_ERROR,
44   };
45
46   explicit TestRequestClient(
47       mojo::PendingReceiver<mojom::ProxyResolverRequestClient> receiver);
48
49   void WaitForResult();
50
51   net::Error error() { return error_; }
52   const net::ProxyInfo& results() { return results_; }
53   net::EventWaiter<Event>& event_waiter() { return event_waiter_; }
54
55  private:
56   // mojom::ProxyResolverRequestClient override.
57   void ReportResult(int32_t error, const net::ProxyInfo& results) override;
58   void Alert(const std::string& message) override;
59   void OnError(int32_t line_number, const std::string& message) override;
60   void ResolveDns(
61       const std::string& hostname,
62       net::ProxyResolveDnsOperation operation,
63       const net::NetworkAnonymizationKey& network_anonymization_key,
64       mojo::PendingRemote<mojom::HostResolverRequestClient> client) override;
65
66   void OnDisconnect();
67
68   bool done_ = false;
69   net::Error error_ = net::ERR_FAILED;
70   net::ProxyInfo results_;
71
72   mojo::Receiver<mojom::ProxyResolverRequestClient> receiver_;
73
74   net::EventWaiter<Event> event_waiter_;
75 };
76
77 TestRequestClient::TestRequestClient(
78     mojo::PendingReceiver<mojom::ProxyResolverRequestClient> receiver)
79     : receiver_(this, std::move(receiver)) {
80   receiver_.set_disconnect_handler(
81       base::BindOnce(&TestRequestClient::OnDisconnect, base::Unretained(this)));
82 }
83
84 void TestRequestClient::WaitForResult() {
85   if (done_)
86     return;
87
88   event_waiter_.WaitForEvent(RESULT_RECEIVED);
89   ASSERT_TRUE(done_);
90 }
91
92 void TestRequestClient::ReportResult(int32_t error,
93                                      const net::ProxyInfo& results) {
94   event_waiter_.NotifyEvent(RESULT_RECEIVED);
95   ASSERT_FALSE(done_);
96   error_ = static_cast<net::Error>(error);
97   results_ = results;
98   done_ = true;
99 }
100
101 void TestRequestClient::Alert(const std::string& message) {}
102
103 void TestRequestClient::OnError(int32_t line_number,
104                                 const std::string& message) {}
105
106 void TestRequestClient::ResolveDns(
107     const std::string& hostname,
108     net::ProxyResolveDnsOperation operation,
109     const net::NetworkAnonymizationKey& network_anonymization_key,
110     mojo::PendingRemote<mojom::HostResolverRequestClient> client) {}
111
112 void TestRequestClient::OnDisconnect() {
113   event_waiter_.NotifyEvent(CONNECTION_ERROR);
114 }
115
116 class MockProxyResolverV8Tracing : public ProxyResolverV8Tracing {
117  public:
118   // TODO(mmenke): This struct violates the Google style guide, as structs
119   // aren't allowed to have private members. Fix that.
120   struct Job {
121     GURL url;
122     net::NetworkAnonymizationKey network_anonymization_key;
123     raw_ptr<net::ProxyInfo> results;
124     bool cancelled = false;
125
126     void Complete(int result) {
127       DCHECK(!callback_.is_null());
128       std::move(callback_).Run(result);
129     }
130
131     bool WasCompleted() { return callback_.is_null(); }
132
133     void SetCallback(net::CompletionOnceCallback callback) {
134       callback_ = std::move(callback);
135     }
136
137    private:
138     net::CompletionOnceCallback callback_;
139   };
140
141   class RequestImpl : public net::ProxyResolver::Request {
142    public:
143     RequestImpl(Job* job, MockProxyResolverV8Tracing* resolver)
144         : job_(job), resolver_(resolver) {}
145
146     ~RequestImpl() override {
147       if (job_->WasCompleted())
148         return;
149       job_->cancelled = true;
150       if (resolver_->cancel_callback_)
151         std::move(resolver_->cancel_callback_).Run();
152     }
153
154     net::LoadState GetLoadState() override {
155       return net::LOAD_STATE_RESOLVING_PROXY_FOR_URL;
156     }
157
158    private:
159     raw_ptr<Job> job_;
160     raw_ptr<MockProxyResolverV8Tracing> resolver_;
161   };
162
163   MockProxyResolverV8Tracing() {}
164
165   // ProxyResolverV8Tracing overrides.
166   void GetProxyForURL(
167       const GURL& url,
168       const net::NetworkAnonymizationKey& network_anonymization_key,
169       net::ProxyInfo* results,
170       net::CompletionOnceCallback callback,
171       std::unique_ptr<net::ProxyResolver::Request>* request,
172       std::unique_ptr<Bindings> bindings) override;
173
174   void WaitForCancel();
175
176   const std::vector<std::unique_ptr<Job>>& pending_jobs() {
177     return pending_jobs_;
178   }
179
180  private:
181   base::OnceClosure cancel_callback_;
182   std::vector<std::unique_ptr<Job>> pending_jobs_;
183 };
184
185 void MockProxyResolverV8Tracing::GetProxyForURL(
186     const GURL& url,
187     const net::NetworkAnonymizationKey& network_anonymization_key,
188     net::ProxyInfo* results,
189     net::CompletionOnceCallback callback,
190     std::unique_ptr<net::ProxyResolver::Request>* request,
191     std::unique_ptr<Bindings> bindings) {
192   pending_jobs_.push_back(std::make_unique<Job>());
193   auto* pending_job = pending_jobs_.back().get();
194   pending_job->url = url;
195   pending_job->network_anonymization_key = network_anonymization_key;
196   pending_job->results = results;
197   pending_job->SetCallback(std::move(callback));
198   *request = std::make_unique<RequestImpl>(pending_job, this);
199 }
200
201 void MockProxyResolverV8Tracing::WaitForCancel() {
202   while (base::ranges::any_of(pending_jobs_, &Job::cancelled)) {
203     base::RunLoop run_loop;
204     cancel_callback_ = run_loop.QuitClosure();
205     run_loop.Run();
206   }
207 }
208
209 }  // namespace
210
211 class ProxyResolverImplTest : public testing::Test {
212  public:
213   ProxyResolverImplTest() {
214     std::unique_ptr<MockProxyResolverV8Tracing> mock_resolver =
215         std::make_unique<MockProxyResolverV8Tracing>();
216     mock_proxy_resolver_ = mock_resolver.get();
217     resolver_impl_ =
218         std::make_unique<ProxyResolverImpl>(std::move(mock_resolver));
219     resolver_ = resolver_impl_.get();
220   }
221
222   ~ProxyResolverImplTest() override = default;
223
224  protected:
225   base::test::TaskEnvironment task_environment_;
226   raw_ptr<MockProxyResolverV8Tracing> mock_proxy_resolver_;
227
228   std::unique_ptr<ProxyResolverImpl> resolver_impl_;
229   raw_ptr<mojom::ProxyResolver> resolver_;
230 };
231
232 TEST_F(ProxyResolverImplTest, GetProxyForUrl) {
233   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client;
234   TestRequestClient client(remote_client.InitWithNewPipeAndPassReceiver());
235
236   resolver_->GetProxyForUrl(GURL("http://example.com"),
237                             net::NetworkAnonymizationKey(),
238                             std::move(remote_client));
239   ASSERT_EQ(1u, mock_proxy_resolver_->pending_jobs().size());
240   MockProxyResolverV8Tracing::Job* job =
241       mock_proxy_resolver_->pending_jobs()[0].get();
242   EXPECT_EQ(GURL("http://example.com"), job->url);
243
244   job->results->UsePacString(
245       "PROXY proxy.example.com:1; "
246       "SOCKS4 socks4.example.com:2; "
247       "SOCKS5 socks5.example.com:3; "
248       "HTTPS https.example.com:4; "
249       "QUIC quic.example.com:65000; "
250       "DIRECT");
251   job->Complete(net::OK);
252   client.WaitForResult();
253
254   EXPECT_THAT(client.error(), IsOk());
255   std::vector<net::ProxyServer> servers =
256       client.results().proxy_list().GetAll();
257   ASSERT_EQ(6u, servers.size());
258   EXPECT_EQ(net::ProxyServer::SCHEME_HTTP, servers[0].scheme());
259   EXPECT_EQ("proxy.example.com", servers[0].host_port_pair().host());
260   EXPECT_EQ(1, servers[0].host_port_pair().port());
261
262   EXPECT_EQ(net::ProxyServer::SCHEME_SOCKS4, servers[1].scheme());
263   EXPECT_EQ("socks4.example.com", servers[1].host_port_pair().host());
264   EXPECT_EQ(2, servers[1].host_port_pair().port());
265
266   EXPECT_EQ(net::ProxyServer::SCHEME_SOCKS5, servers[2].scheme());
267   EXPECT_EQ("socks5.example.com", servers[2].host_port_pair().host());
268   EXPECT_EQ(3, servers[2].host_port_pair().port());
269
270   EXPECT_EQ(net::ProxyServer::SCHEME_HTTPS, servers[3].scheme());
271   EXPECT_EQ("https.example.com", servers[3].host_port_pair().host());
272   EXPECT_EQ(4, servers[3].host_port_pair().port());
273
274   EXPECT_EQ(net::ProxyServer::SCHEME_QUIC, servers[4].scheme());
275   EXPECT_EQ("quic.example.com", servers[4].host_port_pair().host());
276   EXPECT_EQ(65000, servers[4].host_port_pair().port());
277
278   EXPECT_EQ(net::ProxyServer::SCHEME_DIRECT, servers[5].scheme());
279 }
280
281 TEST_F(ProxyResolverImplTest, GetProxyForUrlWithNetworkAnonymizationKey) {
282   const net::SchemefulSite kSite(
283       net::SchemefulSite(GURL("https://site.test/")));
284   const net::NetworkAnonymizationKey kNetworkAnonymizationKey(kSite, kSite);
285
286   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client;
287   TestRequestClient client(remote_client.InitWithNewPipeAndPassReceiver());
288
289   resolver_->GetProxyForUrl(GURL("http://example.com"),
290                             kNetworkAnonymizationKey, std::move(remote_client));
291   ASSERT_EQ(1u, mock_proxy_resolver_->pending_jobs().size());
292   MockProxyResolverV8Tracing::Job* job =
293       mock_proxy_resolver_->pending_jobs()[0].get();
294   EXPECT_EQ(GURL("http://example.com"), job->url);
295   EXPECT_EQ(kNetworkAnonymizationKey, job->network_anonymization_key);
296 }
297
298 TEST_F(ProxyResolverImplTest, GetProxyForUrlFailure) {
299   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client;
300   TestRequestClient client(remote_client.InitWithNewPipeAndPassReceiver());
301
302   resolver_->GetProxyForUrl(GURL("http://example.com"),
303                             net::NetworkAnonymizationKey(),
304                             std::move(remote_client));
305   ASSERT_EQ(1u, mock_proxy_resolver_->pending_jobs().size());
306   MockProxyResolverV8Tracing::Job* job =
307       mock_proxy_resolver_->pending_jobs()[0].get();
308   EXPECT_EQ(GURL("http://example.com"), job->url);
309   job->Complete(net::ERR_FAILED);
310   client.WaitForResult();
311
312   EXPECT_THAT(client.error(), IsError(net::ERR_FAILED));
313   std::vector<net::ProxyServer> proxy_servers =
314       client.results().proxy_list().GetAll();
315   EXPECT_TRUE(proxy_servers.empty());
316 }
317
318 TEST_F(ProxyResolverImplTest, GetProxyForUrlMultiple) {
319   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client1;
320   TestRequestClient client1(remote_client1.InitWithNewPipeAndPassReceiver());
321   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client2;
322   TestRequestClient client2(remote_client2.InitWithNewPipeAndPassReceiver());
323
324   resolver_->GetProxyForUrl(GURL("http://example.com"),
325                             net::NetworkAnonymizationKey(),
326                             std::move(remote_client1));
327   resolver_->GetProxyForUrl(GURL("https://example.com"),
328                             net::NetworkAnonymizationKey(),
329                             std::move(remote_client2));
330   ASSERT_EQ(2u, mock_proxy_resolver_->pending_jobs().size());
331   MockProxyResolverV8Tracing::Job* job1 =
332       mock_proxy_resolver_->pending_jobs()[0].get();
333   EXPECT_EQ(GURL("http://example.com"), job1->url);
334   MockProxyResolverV8Tracing::Job* job2 =
335       mock_proxy_resolver_->pending_jobs()[1].get();
336   EXPECT_EQ(GURL("https://example.com"), job2->url);
337   job1->results->UsePacString("HTTPS proxy.example.com:12345");
338   job1->Complete(net::OK);
339   job2->results->UsePacString("SOCKS5 another-proxy.example.com:6789");
340   job2->Complete(net::OK);
341   client1.WaitForResult();
342   client2.WaitForResult();
343
344   EXPECT_THAT(client1.error(), IsOk());
345   std::vector<net::ProxyServer> proxy_servers1 =
346       client1.results().proxy_list().GetAll();
347   ASSERT_EQ(1u, proxy_servers1.size());
348   net::ProxyServer& server1 = proxy_servers1[0];
349   EXPECT_EQ(net::ProxyServer::SCHEME_HTTPS, server1.scheme());
350   EXPECT_EQ("proxy.example.com", server1.host_port_pair().host());
351   EXPECT_EQ(12345, server1.host_port_pair().port());
352
353   EXPECT_THAT(client2.error(), IsOk());
354   std::vector<net::ProxyServer> proxy_servers2 =
355       client2.results().proxy_list().GetAll();
356   ASSERT_EQ(1u, proxy_servers1.size());
357   net::ProxyServer& server2 = proxy_servers2[0];
358   EXPECT_EQ(net::ProxyServer::SCHEME_SOCKS5, server2.scheme());
359   EXPECT_EQ("another-proxy.example.com", server2.host_port_pair().host());
360   EXPECT_EQ(6789, server2.host_port_pair().port());
361 }
362
363 TEST_F(ProxyResolverImplTest, DestroyClient) {
364   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client;
365   auto client = std::make_unique<TestRequestClient>(
366       remote_client.InitWithNewPipeAndPassReceiver());
367
368   resolver_->GetProxyForUrl(GURL("http://example.com"),
369                             net::NetworkAnonymizationKey(),
370                             std::move(remote_client));
371   ASSERT_EQ(1u, mock_proxy_resolver_->pending_jobs().size());
372   const MockProxyResolverV8Tracing::Job* job =
373       mock_proxy_resolver_->pending_jobs()[0].get();
374   EXPECT_EQ(GURL("http://example.com"), job->url);
375   job->results->UsePacString("PROXY proxy.example.com:8080");
376   client.reset();
377   mock_proxy_resolver_->WaitForCancel();
378 }
379
380 TEST_F(ProxyResolverImplTest, DestroyService) {
381   mojo::PendingRemote<mojom::ProxyResolverRequestClient> remote_client;
382   TestRequestClient client(remote_client.InitWithNewPipeAndPassReceiver());
383
384   resolver_->GetProxyForUrl(GURL("http://example.com"),
385                             net::NetworkAnonymizationKey(),
386                             std::move(remote_client));
387   ASSERT_EQ(1u, mock_proxy_resolver_->pending_jobs().size());
388   resolver_impl_.reset();
389   client.event_waiter().WaitForEvent(TestRequestClient::CONNECTION_ERROR);
390 }
391
392 }  // namespace proxy_resolver