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