1 // Copyright 2020 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 "net/proxy_resolution/win/windows_system_proxy_resolution_service.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/memory/raw_ptr.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/run_loop.h"
13 #include "base/sequence_checker.h"
14 #include "base/task/sequenced_task_runner.h"
15 #include "net/base/network_isolation_key.h"
16 #include "net/base/proxy_server.h"
17 #include "net/base/proxy_string_util.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/proxy_resolution/configured_proxy_resolution_service.h"
20 #include "net/proxy_resolution/proxy_config.h"
21 #include "net/proxy_resolution/proxy_info.h"
22 #include "net/proxy_resolution/proxy_list.h"
23 #include "net/proxy_resolution/win/windows_system_proxy_resolution_request.h"
24 #include "net/proxy_resolution/win/windows_system_proxy_resolver.h"
25 #include "net/proxy_resolution/win/winhttp_status.h"
26 #include "net/test/gtest_util.h"
27 #include "net/test/test_with_task_environment.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "url/gurl.h"
30 
31 using net::test::IsError;
32 using net::test::IsOk;
33 
34 namespace net {
35 
36 namespace {
37 
38 const GURL kResourceUrl("https://example.test:8080/");
39 
40 class MockRequest : public WindowsSystemProxyResolver::Request {
41  public:
MockRequest(WindowsSystemProxyResolutionRequest * callback_target,const ProxyList & proxy_list,WinHttpStatus winhttp_status,int windows_error)42   MockRequest(WindowsSystemProxyResolutionRequest* callback_target,
43               const ProxyList& proxy_list,
44               WinHttpStatus winhttp_status,
45               int windows_error) {
46     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
47         FROM_HERE,
48         base::BindOnce(&MockRequest::DoCallback, weak_ptr_factory_.GetWeakPtr(),
49                        callback_target, proxy_list, winhttp_status,
50                        windows_error));
51   }
52   ~MockRequest() override = default;
53 
54  private:
DoCallback(WindowsSystemProxyResolutionRequest * callback_target,const ProxyList & proxy_list,WinHttpStatus winhttp_status,int windows_error)55   void DoCallback(WindowsSystemProxyResolutionRequest* callback_target,
56                   const ProxyList& proxy_list,
57                   WinHttpStatus winhttp_status,
58                   int windows_error) {
59     callback_target->ProxyResolutionComplete(proxy_list, winhttp_status,
60                                              windows_error);
61   }
62 
63   base::WeakPtrFactory<MockRequest> weak_ptr_factory_{this};
64 };
65 
66 class MockWindowsSystemProxyResolver : public WindowsSystemProxyResolver {
67  public:
68   MockWindowsSystemProxyResolver() = default;
69   ~MockWindowsSystemProxyResolver() override = default;
70 
add_server_to_proxy_list(const ProxyServer & proxy_server)71   void add_server_to_proxy_list(const ProxyServer& proxy_server) {
72     proxy_list_.AddProxyServer(proxy_server);
73   }
74 
set_winhttp_status(WinHttpStatus winhttp_status)75   void set_winhttp_status(WinHttpStatus winhttp_status) {
76     winhttp_status_ = winhttp_status;
77   }
78 
set_windows_error(int windows_error)79   void set_windows_error(int windows_error) { windows_error_ = windows_error; }
80 
GetProxyForUrl(const GURL & url,WindowsSystemProxyResolutionRequest * callback_target)81   std::unique_ptr<Request> GetProxyForUrl(
82       const GURL& url,
83       WindowsSystemProxyResolutionRequest* callback_target) override {
84     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
85     return std::make_unique<MockRequest>(callback_target, proxy_list_,
86                                          winhttp_status_, windows_error_);
87   }
88 
89  private:
90   ProxyList proxy_list_;
91   WinHttpStatus winhttp_status_ = WinHttpStatus::kOk;
92   int windows_error_ = 0;
93 
94   SEQUENCE_CHECKER(sequence_checker_);
95 };
96 
97 }  // namespace
98 
99 // These tests verify the behavior of the WindowsSystemProxyResolutionService in
100 // isolation by mocking out the WindowsSystemProxyResolver.
101 class WindowsSystemProxyResolutionServiceTest : public TestWithTaskEnvironment {
102  public:
SetUp()103   void SetUp() override {
104     testing::Test::SetUp();
105 
106     if (!WindowsSystemProxyResolutionService::IsSupported()) {
107       GTEST_SKIP()
108           << "Windows System Proxy Resolution is only supported on Windows 8+.";
109     }
110 
111     auto proxy_resolver = std::make_unique<MockWindowsSystemProxyResolver>();
112     proxy_resolver_ = proxy_resolver.get();
113     proxy_resolution_service_ = WindowsSystemProxyResolutionService::Create(
114         std::move(proxy_resolver), /*net_log=*/nullptr);
115     ASSERT_TRUE(proxy_resolution_service_);
116   }
117 
service()118   WindowsSystemProxyResolutionService* service() {
119     return proxy_resolution_service_.get();
120   }
121 
resolver()122   MockWindowsSystemProxyResolver* resolver() { return proxy_resolver_; }
123 
ResetProxyResolutionService()124   void ResetProxyResolutionService() { proxy_resolution_service_.reset(); }
125 
DoResolveProxyTest(const ProxyList & expected_proxy_list)126   void DoResolveProxyTest(const ProxyList& expected_proxy_list) {
127     ProxyInfo info;
128     TestCompletionCallback callback;
129     NetLogWithSource log;
130     std::unique_ptr<ProxyResolutionRequest> request;
131     int result = service()->ResolveProxy(kResourceUrl, std::string(),
132                                          NetworkAnonymizationKey(), &info,
133                                          callback.callback(), &request, log);
134 
135     ASSERT_THAT(result, IsError(ERR_IO_PENDING));
136     ASSERT_NE(request, nullptr);
137 
138     // Wait for result to come back.
139     EXPECT_THAT(callback.GetResult(result), IsOk());
140 
141     EXPECT_TRUE(expected_proxy_list.Equals(info.proxy_list()));
142     EXPECT_NE(request, nullptr);
143   }
144 
145  private:
146   std::unique_ptr<WindowsSystemProxyResolutionService>
147       proxy_resolution_service_;
148   raw_ptr<MockWindowsSystemProxyResolver, DanglingUntriaged> proxy_resolver_;
149 };
150 
TEST_F(WindowsSystemProxyResolutionServiceTest,CreateWithNullResolver)151 TEST_F(WindowsSystemProxyResolutionServiceTest, CreateWithNullResolver) {
152   std::unique_ptr<WindowsSystemProxyResolutionService>
153       proxy_resolution_service = WindowsSystemProxyResolutionService::Create(
154           /*windows_system_proxy_resolver=*/nullptr, /*net_log=*/nullptr);
155   EXPECT_FALSE(proxy_resolution_service);
156 }
157 
TEST_F(WindowsSystemProxyResolutionServiceTest,ResolveProxyFailed)158 TEST_F(WindowsSystemProxyResolutionServiceTest, ResolveProxyFailed) {
159   resolver()->set_winhttp_status(WinHttpStatus::kAborted);
160 
161   // Make sure there would be a proxy result on success.
162   const ProxyServer proxy_server =
163       PacResultElementToProxyServer("HTTPS foopy:8443");
164   resolver()->add_server_to_proxy_list(proxy_server);
165 
166   ProxyInfo info;
167   TestCompletionCallback callback;
168   NetLogWithSource log;
169   std::unique_ptr<ProxyResolutionRequest> request;
170   int result = service()->ResolveProxy(kResourceUrl, std::string(),
171                                        NetworkAnonymizationKey(), &info,
172                                        callback.callback(), &request, log);
173 
174   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
175   ASSERT_NE(request, nullptr);
176 
177   // Wait for result to come back.
178   EXPECT_THAT(callback.GetResult(result), IsOk());
179 
180   EXPECT_TRUE(info.is_direct());
181   EXPECT_NE(request, nullptr);
182 }
183 
TEST_F(WindowsSystemProxyResolutionServiceTest,ResolveProxyCancelled)184 TEST_F(WindowsSystemProxyResolutionServiceTest, ResolveProxyCancelled) {
185   // Make sure there would be a proxy result on success.
186   const ProxyServer proxy_server =
187       PacResultElementToProxyServer("HTTPS foopy:8443");
188   resolver()->add_server_to_proxy_list(proxy_server);
189 
190   ProxyInfo info;
191   TestCompletionCallback callback;
192   NetLogWithSource log;
193   std::unique_ptr<ProxyResolutionRequest> request;
194   int result = service()->ResolveProxy(kResourceUrl, std::string(),
195                                        NetworkAnonymizationKey(), &info,
196                                        callback.callback(), &request, log);
197 
198   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
199   ASSERT_NE(request, nullptr);
200 
201   // Cancel the request.
202   request.reset();
203 
204   // The proxy shouldn't resolve.
205   base::RunLoop().RunUntilIdle();
206   EXPECT_FALSE(callback.have_result());
207 }
208 
TEST_F(WindowsSystemProxyResolutionServiceTest,ResolveProxyEmptyResults)209 TEST_F(WindowsSystemProxyResolutionServiceTest, ResolveProxyEmptyResults) {
210   ProxyList expected_proxy_list;
211   DoResolveProxyTest(expected_proxy_list);
212 }
213 
TEST_F(WindowsSystemProxyResolutionServiceTest,ResolveProxyWithResults)214 TEST_F(WindowsSystemProxyResolutionServiceTest, ResolveProxyWithResults) {
215   ProxyList expected_proxy_list;
216   const ProxyServer proxy_server =
217       PacResultElementToProxyServer("HTTPS foopy:8443");
218   resolver()->add_server_to_proxy_list(proxy_server);
219   expected_proxy_list.AddProxyServer(proxy_server);
220 
221   DoResolveProxyTest(expected_proxy_list);
222 }
223 
TEST_F(WindowsSystemProxyResolutionServiceTest,MultipleProxyResolutionRequests)224 TEST_F(WindowsSystemProxyResolutionServiceTest,
225        MultipleProxyResolutionRequests) {
226   ProxyList expected_proxy_list;
227   const ProxyServer proxy_server =
228       PacResultElementToProxyServer("HTTPS foopy:8443");
229   resolver()->add_server_to_proxy_list(proxy_server);
230   expected_proxy_list.AddProxyServer(proxy_server);
231   NetLogWithSource log;
232 
233   ProxyInfo first_proxy_info;
234   TestCompletionCallback first_callback;
235   std::unique_ptr<ProxyResolutionRequest> first_request;
236   int result = service()->ResolveProxy(
237       kResourceUrl, std::string(), NetworkAnonymizationKey(), &first_proxy_info,
238       first_callback.callback(), &first_request, log);
239   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
240   ASSERT_NE(first_request, nullptr);
241 
242   ProxyInfo second_proxy_info;
243   TestCompletionCallback second_callback;
244   std::unique_ptr<ProxyResolutionRequest> second_request;
245   result = service()->ResolveProxy(
246       kResourceUrl, std::string(), NetworkAnonymizationKey(), &second_proxy_info,
247       second_callback.callback(), &second_request, log);
248   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
249   ASSERT_NE(second_request, nullptr);
250 
251   // Wait for results to come back.
252   EXPECT_THAT(first_callback.GetResult(result), IsOk());
253   EXPECT_THAT(second_callback.GetResult(result), IsOk());
254 
255   EXPECT_TRUE(expected_proxy_list.Equals(first_proxy_info.proxy_list()));
256   EXPECT_NE(first_request, nullptr);
257   EXPECT_TRUE(expected_proxy_list.Equals(second_proxy_info.proxy_list()));
258   EXPECT_NE(second_request, nullptr);
259 }
260 
TEST_F(WindowsSystemProxyResolutionServiceTest,ProxyResolutionServiceDestructionWithInFlightRequests)261 TEST_F(WindowsSystemProxyResolutionServiceTest,
262        ProxyResolutionServiceDestructionWithInFlightRequests) {
263   ProxyList expected_proxy_list;
264   const ProxyServer proxy_server =
265       PacResultElementToProxyServer("HTTPS foopy:8443");
266   resolver()->add_server_to_proxy_list(proxy_server);
267   expected_proxy_list.AddProxyServer(proxy_server);
268   NetLogWithSource log;
269 
270   ProxyInfo first_proxy_info;
271   TestCompletionCallback first_callback;
272   std::unique_ptr<ProxyResolutionRequest> first_request;
273   int result = service()->ResolveProxy(
274       kResourceUrl, std::string(), NetworkAnonymizationKey(), &first_proxy_info,
275       first_callback.callback(), &first_request, log);
276   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
277   ASSERT_NE(first_request, nullptr);
278 
279   ProxyInfo second_proxy_info;
280   TestCompletionCallback second_callback;
281   std::unique_ptr<ProxyResolutionRequest> second_request;
282   result = service()->ResolveProxy(
283       kResourceUrl, std::string(), NetworkAnonymizationKey(), &second_proxy_info,
284       second_callback.callback(), &second_request, log);
285   ASSERT_THAT(result, IsError(ERR_IO_PENDING));
286   ASSERT_NE(second_request, nullptr);
287 
288   // There are now 2 in-flight proxy resolution requests. Deleting the proxy
289   // resolution service should call the callbacks immediately and do any
290   // appropriate error handling.
291   ResetProxyResolutionService();
292   EXPECT_TRUE(first_callback.have_result());
293   EXPECT_TRUE(second_callback.have_result());
294 
295   EXPECT_TRUE(first_proxy_info.is_direct());
296   EXPECT_TRUE(second_proxy_info.is_direct());
297 }
298 
TEST_F(WindowsSystemProxyResolutionServiceTest,CastToConfiguredProxyResolutionService)299 TEST_F(WindowsSystemProxyResolutionServiceTest,
300        CastToConfiguredProxyResolutionService) {
301   auto configured_service = ConfiguredProxyResolutionService::CreateDirect();
302   ConfiguredProxyResolutionService* casted_service = configured_service.get();
303   EXPECT_FALSE(
304       service()->CastToConfiguredProxyResolutionService(&casted_service));
305   EXPECT_EQ(nullptr, casted_service);
306 }
307 
308 }  // namespace net
309