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.
5 #include "services/proxy_resolver/host_resolver_mojo.h"
12 #include "base/bind.h"
13 #include "base/test/task_environment.h"
14 #include "mojo/public/cpp/bindings/remote.h"
15 #include "net/base/ip_address.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/network_anonymization_key.h"
18 #include "net/base/request_priority.h"
19 #include "net/base/test_completion_callback.h"
20 #include "net/log/net_log_with_source.h"
21 #include "net/test/event_waiter.h"
22 #include "net/test/gtest_util.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 #include "url/origin.h"
28 using net::test::IsError;
29 using net::test::IsOk;
31 namespace proxy_resolver {
34 void Fail(int result) {
35 FAIL() << "Unexpected callback called with error " << result;
38 class MockMojoHostResolverRequest {
40 MockMojoHostResolverRequest(
41 mojo::PendingRemote<mojom::HostResolverRequestClient> client,
42 base::OnceClosure error_callback)
43 : client_(std::move(client)), error_callback_(std::move(error_callback)) {
44 client_.set_disconnect_handler(base::BindOnce(
45 &MockMojoHostResolverRequest::OnDisconnect, base::Unretained(this)));
48 void OnDisconnect() { std::move(error_callback_).Run(); }
51 mojo::Remote<mojom::HostResolverRequestClient> client_;
52 base::OnceClosure error_callback_;
55 struct HostResolverAction {
62 static HostResolverAction ReturnError(net::Error error) {
63 HostResolverAction result;
68 static HostResolverAction ReturnResult(
69 std::vector<net::IPAddress> addresses) {
70 HostResolverAction result;
71 result.addresses = std::move(addresses);
75 static HostResolverAction DropRequest() {
76 HostResolverAction result;
81 static HostResolverAction RetainRequest() {
82 HostResolverAction result;
83 result.action = RETAIN;
87 Action action = COMPLETE;
88 std::vector<net::IPAddress> addresses;
89 net::Error error = net::OK;
92 class MockMojoHostResolver : public HostResolverMojo::Impl {
94 // Information logged from a call to ResolveDns().
97 net::NetworkAnonymizationKey network_anonymization_key;
99 bool operator==(const RequestInfo& other) const {
100 return hostname == other.hostname &&
101 network_anonymization_key == other.network_anonymization_key;
105 explicit MockMojoHostResolver(
106 base::RepeatingClosure request_connection_error_callback)
107 : request_connection_error_callback_(
108 std::move(request_connection_error_callback)) {}
110 ~MockMojoHostResolver() override {
111 EXPECT_EQ(results_returned_, actions_.size());
114 void AddAction(HostResolverAction action) {
115 actions_.push_back(std::move(action));
118 const std::vector<RequestInfo>& request_info() const { return request_info_; }
121 const std::string& hostname,
122 net::ProxyResolveDnsOperation operation,
123 const net::NetworkAnonymizationKey& network_anonymization_key,
124 mojo::PendingRemote<mojom::HostResolverRequestClient> client) override {
125 request_info_.push_back(RequestInfo{hostname, network_anonymization_key});
126 ASSERT_LE(results_returned_, actions_.size());
127 switch (actions_[results_returned_].action) {
128 case HostResolverAction::COMPLETE:
129 mojo::Remote<mojom::HostResolverRequestClient>(std::move(client))
130 ->ReportResult(actions_[results_returned_].error,
131 actions_[results_returned_].addresses);
133 case HostResolverAction::RETAIN:
134 requests_.push_back(std::make_unique<MockMojoHostResolverRequest>(
136 base::BindOnce(request_connection_error_callback_)));
138 case HostResolverAction::DROP:
145 std::vector<HostResolverAction> actions_;
146 size_t results_returned_ = 0;
147 std::vector<RequestInfo> request_info_;
148 base::RepeatingClosure request_connection_error_callback_;
149 std::vector<std::unique_ptr<MockMojoHostResolverRequest>> requests_;
154 class HostResolverMojoTest : public testing::Test {
156 enum class ConnectionErrorSource {
159 using Waiter = net::EventWaiter<ConnectionErrorSource>;
161 HostResolverMojoTest()
162 : mock_resolver_(base::BindRepeating(&Waiter::NotifyEvent,
163 base::Unretained(&waiter_),
164 ConnectionErrorSource::REQUEST)),
165 resolver_(&mock_resolver_) {}
167 int Resolve(const std::string& hostname,
168 const net::NetworkAnonymizationKey& network_anonymization_key,
169 std::vector<net::IPAddress>* out_addresses) {
170 std::unique_ptr<ProxyHostResolver::Request> request =
171 resolver_.CreateRequest(hostname,
172 net::ProxyResolveDnsOperation::DNS_RESOLVE_EX,
173 network_anonymization_key);
175 net::TestCompletionCallback callback;
176 int result = callback.GetResult(request->Start(callback.callback()));
178 *out_addresses = request->GetResults();
182 base::test::TaskEnvironment task_environment_;
184 MockMojoHostResolver mock_resolver_;
185 HostResolverMojo resolver_;
188 TEST_F(HostResolverMojoTest, Basic) {
189 const net::SchemefulSite kSite =
190 net::SchemefulSite(GURL("https://not-example.com/"));
191 const net::NetworkAnonymizationKey kNetworkAnonymizationKey(kSite, kSite);
193 std::vector<net::IPAddress> addresses;
194 net::IPAddress address(1, 2, 3, 4);
195 addresses.push_back(address);
196 addresses.push_back(ConvertIPv4ToIPv4MappedIPv6(address));
197 mock_resolver_.AddAction(HostResolverAction::ReturnResult(addresses));
199 std::vector<net::IPAddress> result;
200 EXPECT_THAT(Resolve("example.com", kNetworkAnonymizationKey, &result),
202 EXPECT_EQ(addresses, result);
204 ASSERT_EQ(1u, mock_resolver_.request_info().size());
205 EXPECT_EQ("example.com", mock_resolver_.request_info()[0].hostname);
206 EXPECT_EQ(kNetworkAnonymizationKey,
207 mock_resolver_.request_info()[0].network_anonymization_key);
210 TEST_F(HostResolverMojoTest, ResolveCachedResult) {
211 std::vector<net::IPAddress> addresses;
212 net::IPAddress address(1, 2, 3, 4);
213 addresses.push_back(address);
214 addresses.push_back(ConvertIPv4ToIPv4MappedIPv6(address));
215 mock_resolver_.AddAction(HostResolverAction::ReturnResult(addresses));
217 // Load results into cache.
218 std::vector<net::IPAddress> result;
219 ASSERT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
221 ASSERT_EQ(1u, mock_resolver_.request_info().size());
223 // Expect results from cache.
225 EXPECT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
227 EXPECT_EQ(addresses, result);
228 EXPECT_EQ(1u, mock_resolver_.request_info().size());
231 // Make sure the cache indexes entries by NetworkAnonymizationKey.
232 TEST_F(HostResolverMojoTest, ResolveCachedResultWithNetworkAnonymizationKey) {
233 const net::SchemefulSite kSite =
234 net::SchemefulSite(GURL("https://not-example.com/"));
235 const net::NetworkAnonymizationKey kNetworkAnonymizationKey(kSite, kSite);
237 std::vector<net::IPAddress> addresses1;
238 net::IPAddress address1(1, 2, 3, 4);
239 addresses1.push_back(address1);
240 addresses1.push_back(ConvertIPv4ToIPv4MappedIPv6(address1));
241 mock_resolver_.AddAction(HostResolverAction::ReturnResult(addresses1));
243 // Load results into cache using kNetworkAnonymizationKey.
244 std::vector<net::IPAddress> result;
245 ASSERT_THAT(Resolve("example.com", kNetworkAnonymizationKey, &result),
247 ASSERT_EQ(1u, mock_resolver_.request_info().size());
249 // Expect results from cache when using kNetworkAnonymizationKey.
251 EXPECT_THAT(Resolve("example.com", kNetworkAnonymizationKey, &result),
253 EXPECT_EQ(addresses1, result);
254 EXPECT_EQ(1u, mock_resolver_.request_info().size());
256 // A request with an empty NetworkAnonymizationKey should not use results
257 // cached using kNetworkAnonymizationKey.
259 std::vector<net::IPAddress> addresses2;
260 net::IPAddress address2(2, 3, 5, 8);
261 addresses2.push_back(address2);
262 addresses2.push_back(ConvertIPv4ToIPv4MappedIPv6(address2));
263 mock_resolver_.AddAction(HostResolverAction::ReturnResult(addresses2));
266 EXPECT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
268 EXPECT_EQ(addresses2, result);
269 EXPECT_EQ(2u, mock_resolver_.request_info().size());
271 // Using the empty NetworkAnonymizationKey again should result in the second
272 // cached address list.
274 EXPECT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
276 EXPECT_EQ(addresses2, result);
277 EXPECT_EQ(2u, mock_resolver_.request_info().size());
279 // Using kNetworkAnonymizationKey again should result in the first cached
282 EXPECT_THAT(Resolve("example.com", kNetworkAnonymizationKey, &result),
284 EXPECT_EQ(addresses1, result);
285 EXPECT_EQ(2u, mock_resolver_.request_info().size());
288 TEST_F(HostResolverMojoTest, Multiple) {
289 std::vector<net::IPAddress> addresses;
290 addresses.emplace_back(1, 2, 3, 4);
291 mock_resolver_.AddAction(HostResolverAction::ReturnResult(addresses));
292 mock_resolver_.AddAction(
293 HostResolverAction::ReturnError(net::ERR_NAME_NOT_RESOLVED));
295 std::unique_ptr<ProxyHostResolver::Request> request1 =
296 resolver_.CreateRequest("example.com",
297 net::ProxyResolveDnsOperation::DNS_RESOLVE_EX,
298 net::NetworkAnonymizationKey());
299 std::unique_ptr<ProxyHostResolver::Request> request2 =
300 resolver_.CreateRequest("example.org",
301 net::ProxyResolveDnsOperation::DNS_RESOLVE_EX,
302 net::NetworkAnonymizationKey());
303 net::TestCompletionCallback callback1;
304 net::TestCompletionCallback callback2;
305 ASSERT_EQ(net::ERR_IO_PENDING, request1->Start(callback1.callback()));
306 ASSERT_EQ(net::ERR_IO_PENDING, request2->Start(callback2.callback()));
308 EXPECT_THAT(callback1.GetResult(net::ERR_IO_PENDING), IsOk());
309 EXPECT_THAT(callback2.GetResult(net::ERR_IO_PENDING),
310 IsError(net::ERR_NAME_NOT_RESOLVED));
311 EXPECT_EQ(addresses, request1->GetResults());
312 ASSERT_EQ(0u, request2->GetResults().size());
314 EXPECT_THAT(mock_resolver_.request_info(),
315 testing::ElementsAre(
316 MockMojoHostResolver::RequestInfo{
317 "example.com", net::NetworkAnonymizationKey()},
318 MockMojoHostResolver::RequestInfo{
319 "example.org", net::NetworkAnonymizationKey()}));
322 TEST_F(HostResolverMojoTest, Error) {
323 mock_resolver_.AddAction(
324 HostResolverAction::ReturnError(net::ERR_NAME_NOT_RESOLVED));
326 std::vector<net::IPAddress> result;
327 EXPECT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
328 IsError(net::ERR_NAME_NOT_RESOLVED));
329 EXPECT_TRUE(result.empty());
331 ASSERT_EQ(1u, mock_resolver_.request_info().size());
332 EXPECT_EQ("example.com", mock_resolver_.request_info()[0].hostname);
335 TEST_F(HostResolverMojoTest, EmptyResult) {
336 mock_resolver_.AddAction(HostResolverAction::ReturnError(net::OK));
338 std::vector<net::IPAddress> result;
339 EXPECT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
341 EXPECT_TRUE(result.empty());
343 ASSERT_EQ(1u, mock_resolver_.request_info().size());
346 TEST_F(HostResolverMojoTest, Cancel) {
347 mock_resolver_.AddAction(HostResolverAction::RetainRequest());
349 std::unique_ptr<ProxyHostResolver::Request> request = resolver_.CreateRequest(
350 "example.com", net::ProxyResolveDnsOperation::DNS_RESOLVE_EX,
351 net::NetworkAnonymizationKey());
352 request->Start(base::BindOnce(&Fail));
355 waiter_.WaitForEvent(ConnectionErrorSource::REQUEST);
357 ASSERT_EQ(1u, mock_resolver_.request_info().size());
358 EXPECT_EQ("example.com", mock_resolver_.request_info()[0].hostname);
361 TEST_F(HostResolverMojoTest, ImplDropsClientConnection) {
362 mock_resolver_.AddAction(HostResolverAction::DropRequest());
364 std::vector<net::IPAddress> result;
365 EXPECT_THAT(Resolve("example.com", net::NetworkAnonymizationKey(), &result),
366 IsError(net::ERR_FAILED));
367 EXPECT_TRUE(result.empty());
369 ASSERT_EQ(1u, mock_resolver_.request_info().size());
370 EXPECT_EQ("example.com", mock_resolver_.request_info()[0].hostname);
373 } // namespace proxy_resolver