xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_manager_service_endpoint_request_impl.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2024 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/dns/host_resolver_manager_service_endpoint_request_impl.h"
6 
7 #include "base/memory/safe_ref.h"
8 #include "base/no_destructor.h"
9 #include "base/notreached.h"
10 #include "base/types/optional_util.h"
11 #include "net/base/net_errors.h"
12 #include "net/dns/dns_alias_utility.h"
13 #include "net/dns/dns_task_results_manager.h"
14 #include "net/dns/host_resolver.h"
15 #include "net/dns/host_resolver_manager.h"
16 #include "url/scheme_host_port.h"
17 
18 namespace net {
19 
20 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::
FinalizedResult(std::vector<ServiceEndpoint> endpoints,std::set<std::string> dns_aliases)21     FinalizedResult(std::vector<ServiceEndpoint> endpoints,
22                     std::set<std::string> dns_aliases)
23     : endpoints(std::move(endpoints)), dns_aliases(std::move(dns_aliases)) {}
24 
25 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::
26     ~FinalizedResult() = default;
27 
28 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::
29     FinalizedResult(FinalizedResult&&) = default;
30 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult&
31 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::operator=(
32     FinalizedResult&&) = default;
33 
ServiceEndpointRequestImpl(url::SchemeHostPort scheme_host_port,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,ResolveHostParameters parameters,base::WeakPtr<ResolveContext> resolve_context,base::WeakPtr<HostResolverManager> manager,const base::TickClock * tick_clock)34 HostResolverManager::ServiceEndpointRequestImpl::ServiceEndpointRequestImpl(
35     url::SchemeHostPort scheme_host_port,
36     NetworkAnonymizationKey network_anonymization_key,
37     NetLogWithSource net_log,
38     ResolveHostParameters parameters,
39     base::WeakPtr<ResolveContext> resolve_context,
40     base::WeakPtr<HostResolverManager> manager,
41     const base::TickClock* tick_clock)
42     : host_(std::move(scheme_host_port)),
43       network_anonymization_key_(
44           NetworkAnonymizationKey::IsPartitioningEnabled()
45               ? std::move(network_anonymization_key)
46               : NetworkAnonymizationKey()),
47       net_log_(std::move(net_log)),
48       parameters_(std::move(parameters)),
49       resolve_context_(std::move(resolve_context)),
50       manager_(std::move(manager)),
51       tick_clock_(tick_clock),
52       priority_(parameters_.initial_priority) {}
53 
~ServiceEndpointRequestImpl()54 HostResolverManager::ServiceEndpointRequestImpl::~ServiceEndpointRequestImpl() {
55   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56   if (!job_.has_value()) {
57     return;
58   }
59 
60   LogCancelRequest();
61 
62   // Clear the delegate to avoid calling delegate's callback after destruction.
63   // The following CancelServiceEndpointRequest() could result in calling
64   // OnJobCancelled() synchronously.
65   delegate_ = nullptr;
66 
67   job_.value()->CancelServiceEndpointRequest(this);
68 }
69 
Start(Delegate * delegate)70 int HostResolverManager::ServiceEndpointRequestImpl::Start(Delegate* delegate) {
71   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
72   CHECK(!delegate_);
73   CHECK(manager_);
74 
75   if (!resolve_context_) {
76     return ERR_CONTEXT_SHUT_DOWN;
77   }
78 
79   delegate_ = delegate;
80 
81   JobKey job_key(host_, resolve_context_.get());
82   IPAddress ip_address;
83   manager_->InitializeJobKeyAndIPAddress(
84       network_anonymization_key_, parameters_, net_log_, job_key, ip_address);
85 
86   // Try to resolve locally first.
87   std::optional<HostCache::EntryStaleness> stale_info;
88   std::deque<TaskType> tasks;
89   HostCache::Entry results = manager_->ResolveLocally(
90       /*only_ipv6_reachable=*/false, job_key, ip_address,
91       parameters_.cache_usage, parameters_.secure_dns_policy,
92       parameters_.source, net_log_, host_cache(), &tasks, &stale_info);
93   if (results.error() != ERR_DNS_CACHE_MISS ||
94       parameters_.source == HostResolverSource::LOCAL_ONLY || tasks.empty()) {
95     SetFinalizedResultFromLegacyResults(results);
96     return results.error();
97   }
98 
99   manager_->CreateAndStartJobForServiceEndpointRequest(std::move(job_key),
100                                                        std::move(tasks), this);
101   return ERR_IO_PENDING;
102 }
103 
104 const std::vector<ServiceEndpoint>&
GetEndpointResults()105 HostResolverManager::ServiceEndpointRequestImpl::GetEndpointResults() {
106   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107 
108   if (finalized_result_.has_value()) {
109     return finalized_result_->endpoints;
110   }
111 
112   if (job_) {
113     CHECK(job_.value()->dns_task_results_manager());
114     return job_.value()->dns_task_results_manager()->GetCurrentEndpoints();
115   }
116 
117   NOTREACHED_NORETURN();
118 }
119 
120 const std::set<std::string>&
GetDnsAliasResults()121 HostResolverManager::ServiceEndpointRequestImpl::GetDnsAliasResults() {
122   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
123 
124   if (finalized_result_.has_value()) {
125     return finalized_result_->dns_aliases;
126   }
127 
128   if (job_) {
129     CHECK(job_.value()->dns_task_results_manager());
130     // TODO(crbug.com/41493696): Call dns_alias_utility::FixUpDnsAliases().
131     return job_.value()->dns_task_results_manager()->GetAliases();
132   }
133 
134   NOTREACHED_NORETURN();
135 }
136 
EndpointsCryptoReady()137 bool HostResolverManager::ServiceEndpointRequestImpl::EndpointsCryptoReady() {
138   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
139 
140   if (finalized_result_.has_value()) {
141     return true;
142   }
143 
144   if (job_) {
145     CHECK(job_.value()->dns_task_results_manager());
146     return job_.value()->dns_task_results_manager()->IsMetadataReady();
147   }
148 
149   NOTREACHED_NORETURN();
150 }
151 
AssignJob(base::SafeRef<Job> job)152 void HostResolverManager::ServiceEndpointRequestImpl::AssignJob(
153     base::SafeRef<Job> job) {
154   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
155   CHECK(!job_.has_value());
156   job_ = job;
157 }
158 
OnJobCompleted(const HostCache::Entry & results,bool obtained_securely)159 void HostResolverManager::ServiceEndpointRequestImpl::OnJobCompleted(
160     const HostCache::Entry& results,
161     bool obtained_securely) {
162   CHECK(job_);
163   CHECK(delegate_);
164   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
165 
166   job_.reset();
167   SetFinalizedResultFromLegacyResults(results);
168 
169   const bool is_secure_network_error =
170       obtained_securely && results.error() != OK;
171   error_info_ = ResolveErrorInfo(results.error(), is_secure_network_error);
172   delegate_->OnServiceEndpointRequestFinished(results.error());
173   // Do not add code below. `this` may be deleted at this point.
174 }
175 
OnJobCancelled()176 void HostResolverManager::ServiceEndpointRequestImpl::OnJobCancelled() {
177   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178   CHECK(job_);
179 
180   job_.reset();
181 
182   // The owner of `this` has already destroyed `this`.
183   if (!delegate_) {
184     return;
185   }
186 
187   LogCancelRequest();
188 
189   finalized_result_ = FinalizedResult(/*endpoints=*/{}, /*dns_aliases=*/{});
190   error_info_ = ResolveErrorInfo(ERR_DNS_REQUEST_CANCELLED,
191                                  /*is_secure_network_error=*/false);
192   delegate_->OnServiceEndpointRequestFinished(ERR_DNS_REQUEST_CANCELLED);
193   // Do not add code below. `this` may be deleted at this point.
194 }
195 
196 void HostResolverManager::ServiceEndpointRequestImpl::
OnServiceEndpointsChanged()197     OnServiceEndpointsChanged() {
198   // This method is called asynchronously via a posted task. `job_` could
199   // be completed or cancelled before executing the task.
200   if (finalized_result_.has_value()) {
201     return;
202   }
203 
204   CHECK(job_);
205   CHECK(job_.value()->dns_task_results_manager());
206   CHECK(delegate_);
207   delegate_->OnServiceEndpointsUpdated();
208   // Do not add code below. `this` may be deleted at this point.
209 }
210 
211 base::WeakPtr<HostResolverManager::ServiceEndpointRequestImpl>
GetWeakPtr()212 HostResolverManager::ServiceEndpointRequestImpl::GetWeakPtr() {
213   return weak_ptr_factory_.GetWeakPtr();
214 }
215 
216 void HostResolverManager::ServiceEndpointRequestImpl::
SetFinalizedResultFromLegacyResults(const HostCache::Entry & results)217     SetFinalizedResultFromLegacyResults(const HostCache::Entry& results) {
218   CHECK(!finalized_result_);
219   if (results.error() == OK && !parameters_.is_speculative) {
220     std::vector<IPEndPoint> ipv4_endpoints;
221     std::vector<IPEndPoint> ipv6_endpoints;
222     for (const auto& ip_endpoint : results.ip_endpoints()) {
223       std::vector<IPEndPoint>& ip_endpoints =
224           ip_endpoint.address().IsIPv6() ? ipv6_endpoints : ipv4_endpoints;
225       if (ip_endpoint.port() == 0) {
226         ip_endpoints.emplace_back(ip_endpoint.address(), host_.GetPort());
227       } else {
228         ip_endpoints.emplace_back(ip_endpoint);
229       }
230     }
231 
232     // See HostCache::Entry::GetEndpoints.
233     std::vector<ServiceEndpoint> endpoints;
234     if (!ipv4_endpoints.empty() || !ipv6_endpoints.empty()) {
235       for (const auto& metadata : results.GetMetadatas()) {
236         if (!base::Contains(results.canonical_names(), metadata.target_name)) {
237           continue;
238         }
239 
240         ServiceEndpoint endpoint;
241         endpoint.ipv4_endpoints = ipv4_endpoints;
242         endpoint.ipv6_endpoints = ipv6_endpoints;
243         endpoint.metadata = metadata;
244         endpoints.emplace_back(std::move(endpoint));
245       }
246 
247       // Append Non-SVCB endpoints at the end for fallback.
248       // TODO(crbug.com/41493696): Revisit how to handle non-SVCB endpoints once
249       // the connection layer starts using this API. Adding non-SVCB endpoints
250       // here might be inconsistent with intermediate results generated by
251       // DnsTaskResultsManager, which doesn't append non-SVCB endpoints.
252       ServiceEndpoint non_alternative_endpoint;
253       non_alternative_endpoint.ipv4_endpoints = ipv4_endpoints;
254       non_alternative_endpoint.ipv6_endpoints = ipv6_endpoints;
255       endpoints.emplace_back(std::move(non_alternative_endpoint));
256     }
257 
258     finalized_result_ =
259         FinalizedResult(std::move(endpoints),
260                         dns_alias_utility::FixUpDnsAliases(results.aliases()));
261   } else {
262     finalized_result_ = FinalizedResult(/*endpoints=*/{}, /*dns_aliases=*/{});
263   }
264 }
265 
LogCancelRequest()266 void HostResolverManager::ServiceEndpointRequestImpl::LogCancelRequest() {
267   net_log_.AddEvent(NetLogEventType::CANCELLED);
268   net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST);
269 }
270 
271 }  // namespace net
272