• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_job.h"
6 
7 #include <deque>
8 #include <memory>
9 #include <optional>
10 #include <vector>
11 
12 #include "base/containers/linked_list.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/memory/safe_ref.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/metrics/histogram_functions.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/not_fatal_until.h"
19 #include "base/task/sequenced_task_runner.h"
20 #include "base/time/time.h"
21 #include "net/base/address_family.h"
22 #include "net/base/features.h"
23 #include "net/base/network_anonymization_key.h"
24 #include "net/base/network_handle.h"
25 #include "net/base/prioritized_dispatcher.h"
26 #include "net/base/url_util.h"
27 #include "net/dns/dns_client.h"
28 #include "net/dns/dns_task_results_manager.h"
29 #include "net/dns/host_cache.h"
30 #include "net/dns/host_resolver.h"
31 #include "net/dns/host_resolver_dns_task.h"
32 #include "net/dns/host_resolver_internal_result.h"
33 #include "net/dns/host_resolver_manager.h"
34 #include "net/dns/host_resolver_manager_request_impl.h"
35 #include "net/dns/host_resolver_manager_service_endpoint_request_impl.h"
36 #include "net/dns/host_resolver_mdns_task.h"
37 #include "net/dns/host_resolver_nat64_task.h"
38 #include "net/dns/host_resolver_system_task.h"
39 #include "net/dns/public/dns_query_type.h"
40 #include "net/dns/public/secure_dns_mode.h"
41 #include "net/log/net_log_with_source.h"
42 #include "third_party/abseil-cpp/absl/types/variant.h"
43 #include "url/url_constants.h"
44 
45 namespace net {
46 
47 namespace {
48 
49 // Default TTL for successful resolutions with HostResolverSystemTask.
50 const unsigned kCacheEntryTTLSeconds = 60;
51 
52 // Default TTL for unsuccessful resolutions with HostResolverSystemTask.
53 const unsigned kNegativeCacheEntryTTLSeconds = 0;
54 
55 // Minimum TTL for successful resolutions with HostResolverDnsTask.
56 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds;
57 
58 // ICANN uses this localhost address to indicate a name collision.
59 //
60 // The policy in Chromium is to fail host resolving if it resolves to
61 // this special address.
62 //
63 // Not however that IP literals are exempt from this policy, so it is still
64 // possible to navigate to http://127.0.53.53/ directly.
65 //
66 // For more details: https://www.icann.org/news/announcement-2-2014-08-01-en
67 const uint8_t kIcanNameCollisionIp[] = {127, 0, 53, 53};
68 
ContainsIcannNameCollisionIp(const std::vector<IPEndPoint> & endpoints)69 bool ContainsIcannNameCollisionIp(const std::vector<IPEndPoint>& endpoints) {
70   for (const auto& endpoint : endpoints) {
71     const IPAddress& addr = endpoint.address();
72     if (addr.IsIPv4() && IPAddressStartsWith(addr, kIcanNameCollisionIp)) {
73       return true;
74     }
75   }
76   return false;
77 }
78 
79 // Creates NetLog parameters for HOST_RESOLVER_MANAGER_JOB_ATTACH/DETACH events.
NetLogJobAttachParams(const NetLogSource & source,RequestPriority priority)80 base::Value::Dict NetLogJobAttachParams(const NetLogSource& source,
81                                         RequestPriority priority) {
82   base::Value::Dict dict;
83   source.AddToEventParameters(dict);
84   dict.Set("priority", RequestPriorityToString(priority));
85   return dict;
86 }
87 
IsSchemeHttpsOrWss(const HostResolver::Host & host)88 bool IsSchemeHttpsOrWss(const HostResolver::Host& host) {
89   if (!host.HasScheme()) {
90     return false;
91   }
92   const std::string& scheme = host.GetScheme();
93   return scheme == url::kHttpsScheme || scheme == url::kWssScheme;
94 }
95 
96 }  // namespace
97 
JobKey(HostResolver::Host host,ResolveContext * resolve_context)98 HostResolverManager::JobKey::JobKey(HostResolver::Host host,
99                                     ResolveContext* resolve_context)
100     : host(std::move(host)), resolve_context(resolve_context->GetWeakPtr()) {}
101 
102 HostResolverManager::JobKey::~JobKey() = default;
103 
104 HostResolverManager::JobKey::JobKey(const JobKey& other) = default;
105 HostResolverManager::JobKey& HostResolverManager::JobKey::operator=(
106     const JobKey& other) = default;
107 
operator <(const JobKey & other) const108 bool HostResolverManager::JobKey::operator<(const JobKey& other) const {
109   return std::forward_as_tuple(query_types.ToEnumBitmask(), flags, source,
110                                secure_dns_mode, &*resolve_context, host,
111                                network_anonymization_key) <
112          std::forward_as_tuple(other.query_types.ToEnumBitmask(), other.flags,
113                                other.source, other.secure_dns_mode,
114                                &*other.resolve_context, other.host,
115                                other.network_anonymization_key);
116 }
117 
operator ==(const JobKey & other) const118 bool HostResolverManager::JobKey::operator==(const JobKey& other) const {
119   return !(*this < other || other < *this);
120 }
121 
ToCacheKey(bool secure) const122 HostCache::Key HostResolverManager::JobKey::ToCacheKey(bool secure) const {
123   if (query_types.size() != 1) {
124     // This function will produce identical cache keys for `JobKey` structs
125     // that differ only in their (non-singleton) `query_types` fields. When we
126     // enable new query types, this behavior could lead to subtle bugs. That
127     // is why the following DCHECK restricts the allowable query types.
128     DCHECK(Difference(query_types, {DnsQueryType::A, DnsQueryType::AAAA,
129                                     DnsQueryType::HTTPS})
130                .empty());
131   }
132   const DnsQueryType query_type_for_key = query_types.size() == 1
133                                               ? *query_types.begin()
134                                               : DnsQueryType::UNSPECIFIED;
135   absl::variant<url::SchemeHostPort, std::string> host_for_cache;
136   if (host.HasScheme()) {
137     host_for_cache = host.AsSchemeHostPort();
138   } else {
139     host_for_cache = std::string(host.GetHostnameWithoutBrackets());
140   }
141   HostCache::Key key(std::move(host_for_cache), query_type_for_key, flags,
142                      source, network_anonymization_key);
143   key.secure = secure;
144   return key;
145 }
146 
GetTargetNetwork() const147 handles::NetworkHandle HostResolverManager::JobKey::GetTargetNetwork() const {
148   return resolve_context ? resolve_context->GetTargetNetwork()
149                          : handles::kInvalidNetworkHandle;
150 }
151 
Job(const base::WeakPtr<HostResolverManager> & resolver,JobKey key,ResolveHostParameters::CacheUsage cache_usage,HostCache * host_cache,std::deque<TaskType> tasks,RequestPriority priority,const NetLogWithSource & source_net_log,const base::TickClock * tick_clock,const HostResolver::HttpsSvcbOptions & https_svcb_options)152 HostResolverManager::Job::Job(
153     const base::WeakPtr<HostResolverManager>& resolver,
154     JobKey key,
155     ResolveHostParameters::CacheUsage cache_usage,
156     HostCache* host_cache,
157     std::deque<TaskType> tasks,
158     RequestPriority priority,
159     const NetLogWithSource& source_net_log,
160     const base::TickClock* tick_clock,
161     const HostResolver::HttpsSvcbOptions& https_svcb_options)
162     : resolver_(resolver),
163       key_(std::move(key)),
164       cache_usage_(cache_usage),
165       host_cache_(host_cache),
166       tasks_(tasks),
167       priority_tracker_(priority),
168       tick_clock_(tick_clock),
169       https_svcb_options_(https_svcb_options),
170       net_log_(
171           NetLogWithSource::Make(source_net_log.net_log(),
172                                  NetLogSourceType::HOST_RESOLVER_IMPL_JOB)) {
173   source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_CREATE_JOB);
174 
175   net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB, [&] {
176     return NetLogJobCreationParams(source_net_log.source());
177   });
178 
179   if (base::FeatureList::IsEnabled(features::kHappyEyeballsV3)) {
180     dns_task_results_manager_ = std::make_unique<DnsTaskResultsManager>(
181         this, key_.host, key_.query_types, net_log_);
182   }
183 }
184 
~Job()185 HostResolverManager::Job::~Job() {
186   bool was_queued = is_queued();
187   bool was_running = is_running();
188   // Clean up now for nice NetLog.
189   Finish();
190   if (was_running) {
191     // This Job was destroyed while still in flight.
192     net_log_.EndEventWithNetErrorCode(
193         NetLogEventType::HOST_RESOLVER_MANAGER_JOB, ERR_ABORTED);
194   } else if (was_queued) {
195     // Job was cancelled before it could run.
196     // TODO(szym): is there any benefit in having this distinction?
197     net_log_.AddEvent(NetLogEventType::CANCELLED);
198     net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB);
199   }
200   // else CompleteRequests logged EndEvent.
201   while (!requests_.empty()) {
202     // Log any remaining Requests as cancelled.
203     RequestImpl* req = requests_.head()->value();
204     req->RemoveFromList();
205     CHECK(key_ == req->GetJobKey());
206     req->OnJobCancelled(key_);
207   }
208 
209   while (!service_endpoint_requests_.empty()) {
210     ServiceEndpointRequestImpl* request =
211         service_endpoint_requests_.head()->value();
212     request->RemoveFromList();
213     request->OnJobCancelled();
214   }
215 }
216 
Schedule(bool at_head)217 void HostResolverManager::Job::Schedule(bool at_head) {
218   DCHECK(!is_queued());
219   PrioritizedDispatcher::Handle handle;
220   DCHECK(dispatched_);
221   if (!at_head) {
222     handle = resolver_->dispatcher_->Add(this, priority());
223   } else {
224     handle = resolver_->dispatcher_->AddAtHead(this, priority());
225   }
226   // The dispatcher could have started |this| in the above call to Add, which
227   // could have called Schedule again. In that case |handle| will be null,
228   // but |handle_| may have been set by the other nested call to Schedule.
229   if (!handle.is_null()) {
230     DCHECK(handle_.is_null());
231     handle_ = handle;
232   }
233 }
234 
AddRequest(RequestImpl * request)235 void HostResolverManager::Job::AddRequest(RequestImpl* request) {
236   // Job currently assumes a 1:1 correspondence between ResolveContext and
237   // HostCache. Since the ResolveContext is part of the JobKey, any request
238   // added to any existing Job should share the same HostCache.
239   DCHECK_EQ(host_cache_, request->host_cache());
240   // TODO(crbug.com/40181080): Check equality of whole host once Jobs are
241   // separated by scheme/port.
242   DCHECK_EQ(key_.host.GetHostnameWithoutBrackets(),
243             request->request_host().GetHostnameWithoutBrackets());
244 
245   request->AssignJob(weak_ptr_factory_.GetSafeRef());
246 
247   AddRequestCommon(request->priority(), request->source_net_log(),
248                    request->parameters().is_speculative);
249 
250   requests_.Append(request);
251 
252   UpdatePriority();
253 }
254 
ChangeRequestPriority(RequestImpl * req,RequestPriority priority)255 void HostResolverManager::Job::ChangeRequestPriority(RequestImpl* req,
256                                                      RequestPriority priority) {
257   DCHECK_EQ(key_.host, req->request_host());
258 
259   priority_tracker_.Remove(req->priority());
260   req->set_priority(priority);
261   priority_tracker_.Add(req->priority());
262   UpdatePriority();
263 }
264 
CancelRequest(RequestImpl * request)265 void HostResolverManager::Job::CancelRequest(RequestImpl* request) {
266   DCHECK_EQ(key_.host, request->request_host());
267   DCHECK(!requests_.empty());
268 
269   CancelRequestCommon(request->priority(), request->source_net_log());
270 
271   if (num_active_requests() > 0) {
272     UpdatePriority();
273     request->RemoveFromList();
274   } else {
275     // If we were called from a Request's callback within CompleteRequests,
276     // that Request could not have been cancelled, so num_active_requests()
277     // could not be 0. Therefore, we are not in CompleteRequests().
278     CompleteRequestsWithError(ERR_DNS_REQUEST_CANCELLED,
279                               /*task_type=*/std::nullopt);
280   }
281 }
282 
AddServiceEndpointRequest(ServiceEndpointRequestImpl * request)283 void HostResolverManager::Job::AddServiceEndpointRequest(
284     ServiceEndpointRequestImpl* request) {
285   CHECK_EQ(host_cache_, request->host_cache());
286 
287   request->AssignJob(weak_ptr_factory_.GetSafeRef());
288 
289   AddRequestCommon(request->priority(), request->net_log(),
290                    request->parameters().is_speculative);
291 
292   service_endpoint_requests_.Append(request);
293 
294   UpdatePriority();
295 }
296 
CancelServiceEndpointRequest(ServiceEndpointRequestImpl * request)297 void HostResolverManager::Job::CancelServiceEndpointRequest(
298     ServiceEndpointRequestImpl* request) {
299   CancelRequestCommon(request->priority(), request->net_log());
300 
301   if (num_active_requests() > 0) {
302     UpdatePriority();
303     request->RemoveFromList();
304   } else {
305     // See comments in CancelRequest().
306     CompleteRequestsWithError(ERR_DNS_REQUEST_CANCELLED,
307                               /*task_type=*/std::nullopt);
308   }
309 }
310 
ChangeServiceEndpointRequestPriority(ServiceEndpointRequestImpl * request,RequestPriority priority)311 void HostResolverManager::Job::ChangeServiceEndpointRequestPriority(
312     ServiceEndpointRequestImpl* request,
313     RequestPriority priority) {
314   priority_tracker_.Remove(request->priority());
315   request->set_priority(priority);
316   priority_tracker_.Add(request->priority());
317   UpdatePriority();
318 }
319 
Abort()320 void HostResolverManager::Job::Abort() {
321   CompleteRequestsWithError(ERR_NETWORK_CHANGED, /*task_type=*/std::nullopt);
322 }
323 
GetAbortInsecureDnsTaskClosure(int error,bool fallback_only)324 base::OnceClosure HostResolverManager::Job::GetAbortInsecureDnsTaskClosure(
325     int error,
326     bool fallback_only) {
327   return base::BindOnce(&Job::AbortInsecureDnsTask,
328                         weak_ptr_factory_.GetWeakPtr(), error, fallback_only);
329 }
330 
AbortInsecureDnsTask(int error,bool fallback_only)331 void HostResolverManager::Job::AbortInsecureDnsTask(int error,
332                                                     bool fallback_only) {
333   bool has_system_fallback = base::Contains(tasks_, TaskType::SYSTEM);
334   if (has_system_fallback) {
335     for (auto it = tasks_.begin(); it != tasks_.end();) {
336       if (*it == TaskType::DNS) {
337         it = tasks_.erase(it);
338       } else {
339         ++it;
340       }
341     }
342   }
343 
344   if (dns_task_ && !dns_task_->secure()) {
345     if (has_system_fallback) {
346       KillDnsTask();
347       dns_task_error_ = OK;
348       RunNextTask();
349     } else if (!fallback_only) {
350       CompleteRequestsWithError(error, /*task_type=*/std::nullopt);
351     }
352   }
353 }
354 
OnEvicted()355 void HostResolverManager::Job::OnEvicted() {
356   DCHECK(!is_running());
357   DCHECK(is_queued());
358   handle_.Reset();
359 
360   net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_EVICTED);
361 
362   // This signals to CompleteRequests that parts of this job never ran.
363   // Job must be saved in |resolver_| to be completed asynchronously.
364   // Otherwise the job will be destroyed with requests silently cancelled
365   // before completion runs.
366   DCHECK(self_iterator_);
367   base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
368       FROM_HERE, base::BindOnce(&Job::CompleteRequestsWithError,
369                                 weak_ptr_factory_.GetWeakPtr(),
370                                 ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
371                                 /*task_type=*/std::nullopt));
372 }
373 
ServeFromHosts()374 bool HostResolverManager::Job::ServeFromHosts() {
375   DCHECK_GT(num_active_requests(), 0u);
376   std::optional<HostCache::Entry> results = resolver_->ServeFromHosts(
377       key_.host.GetHostnameWithoutBrackets(), key_.query_types,
378       key_.flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6, tasks_);
379   if (results) {
380     // This will destroy the Job.
381     CompleteRequests(results.value(), base::TimeDelta(), true /* allow_cache */,
382                      true /* secure */, TaskType::HOSTS);
383     return true;
384   }
385   return false;
386 }
387 
OnAddedToJobMap(JobMap::iterator iterator)388 void HostResolverManager::Job::OnAddedToJobMap(JobMap::iterator iterator) {
389   DCHECK(!self_iterator_);
390   CHECK(iterator != resolver_->jobs_.end(), base::NotFatalUntil::M130);
391   self_iterator_ = iterator;
392 }
393 
OnRemovedFromJobMap()394 void HostResolverManager::Job::OnRemovedFromJobMap() {
395   DCHECK(self_iterator_);
396   self_iterator_ = std::nullopt;
397 }
398 
RunNextTask()399 void HostResolverManager::Job::RunNextTask() {
400   // If there are no tasks left to try, cache any stored results and complete
401   // the request with the last stored result. All stored results should be
402   // errors.
403   if (tasks_.empty()) {
404     // If there are no stored results, complete with an error.
405     if (completion_results_.size() == 0) {
406       CompleteRequestsWithError(ERR_NAME_NOT_RESOLVED,
407                                 /*task_type=*/std::nullopt);
408       return;
409     }
410 
411     // Cache all but the last result here. The last result will be cached
412     // as part of CompleteRequests.
413     for (size_t i = 0; i < completion_results_.size() - 1; ++i) {
414       const auto& result = completion_results_[i];
415       DCHECK_NE(OK, result.entry.error());
416       MaybeCacheResult(result.entry, result.ttl, result.secure);
417     }
418     const auto& last_result = completion_results_.back();
419     DCHECK_NE(OK, last_result.entry.error());
420     CompleteRequests(last_result.entry, last_result.ttl, true /* allow_cache */,
421                      last_result.secure,
422                      last_result.secure ? TaskType::SECURE_DNS : TaskType::DNS);
423     return;
424   }
425 
426   TaskType next_task = tasks_.front();
427 
428   // Schedule insecure DnsTasks and HostResolverSystemTasks with the
429   // dispatcher.
430   if (!dispatched_ &&
431       (next_task == TaskType::DNS || next_task == TaskType::SYSTEM ||
432        next_task == TaskType::MDNS)) {
433     dispatched_ = true;
434     job_running_ = false;
435     Schedule(false);
436     DCHECK(is_running() || is_queued());
437 
438     // Check for queue overflow.
439     PrioritizedDispatcher& dispatcher = *resolver_->dispatcher_;
440     if (dispatcher.num_queued_jobs() > resolver_->max_queued_jobs_) {
441       Job* evicted = static_cast<Job*>(dispatcher.EvictOldestLowest());
442       DCHECK(evicted);
443       evicted->OnEvicted();
444     }
445     return;
446   }
447 
448   if (start_time_ == base::TimeTicks()) {
449     net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_STARTED);
450     start_time_ = tick_clock_->NowTicks();
451   }
452   tasks_.pop_front();
453   job_running_ = true;
454 
455   switch (next_task) {
456     case TaskType::SYSTEM:
457       StartSystemTask();
458       break;
459     case TaskType::DNS:
460       StartDnsTask(false /* secure */);
461       break;
462     case TaskType::SECURE_DNS:
463       StartDnsTask(true /* secure */);
464       break;
465     case TaskType::MDNS:
466       StartMdnsTask();
467       break;
468     case TaskType::INSECURE_CACHE_LOOKUP:
469       InsecureCacheLookup();
470       break;
471     case TaskType::NAT64:
472       StartNat64Task();
473       break;
474     case TaskType::SECURE_CACHE_LOOKUP:
475     case TaskType::CACHE_LOOKUP:
476     case TaskType::CONFIG_PRESET:
477     case TaskType::HOSTS:
478       // These task types should have been handled synchronously in
479       // ResolveLocally() prior to Job creation.
480       NOTREACHED();
481   }
482 }
483 
NetLogJobCreationParams(const NetLogSource & source)484 base::Value::Dict HostResolverManager::Job::NetLogJobCreationParams(
485     const NetLogSource& source) {
486   base::Value::Dict dict;
487   source.AddToEventParameters(dict);
488   dict.Set("host", key_.host.ToString());
489   base::Value::List query_types_list;
490   for (DnsQueryType query_type : key_.query_types) {
491     query_types_list.Append(kDnsQueryTypes.at(query_type));
492   }
493   dict.Set("dns_query_types", std::move(query_types_list));
494   dict.Set("secure_dns_mode", base::strict_cast<int>(key_.secure_dns_mode));
495   dict.Set("network_anonymization_key",
496            key_.network_anonymization_key.ToDebugString());
497   return dict;
498 }
499 
Finish()500 void HostResolverManager::Job::Finish() {
501   if (is_running()) {
502     // Clean up but don't run any callbacks.
503     system_task_ = nullptr;
504     KillDnsTask();
505     mdns_task_ = nullptr;
506     job_running_ = false;
507 
508     if (dispatched_) {
509       // Job should only ever occupy one slot after any tasks that may have
510       // required additional slots, e.g. DnsTask, have been killed, and
511       // additional slots are expected to be vacated as part of killing the
512       // task.
513       DCHECK_EQ(1, num_occupied_job_slots_);
514       if (resolver_) {
515         resolver_->dispatcher_->OnJobFinished();
516       }
517       num_occupied_job_slots_ = 0;
518     }
519   } else if (is_queued()) {
520     DCHECK(dispatched_);
521     if (resolver_) {
522       resolver_->dispatcher_->Cancel(handle_);
523     }
524     handle_.Reset();
525   }
526 }
527 
KillDnsTask()528 void HostResolverManager::Job::KillDnsTask() {
529   if (dns_task_) {
530     if (dispatched_) {
531       while (num_occupied_job_slots_ > 1 || is_queued()) {
532         ReduceByOneJobSlot();
533       }
534     }
535     dns_task_.reset();
536   }
537   dns_task_results_manager_.reset();
538 }
539 
ReduceByOneJobSlot()540 void HostResolverManager::Job::ReduceByOneJobSlot() {
541   DCHECK_GE(num_occupied_job_slots_, 1);
542   DCHECK(dispatched_);
543   if (is_queued()) {
544     if (resolver_) {
545       resolver_->dispatcher_->Cancel(handle_);
546     }
547     handle_.Reset();
548   } else if (num_occupied_job_slots_ > 1) {
549     if (resolver_) {
550       resolver_->dispatcher_->OnJobFinished();
551     }
552     --num_occupied_job_slots_;
553   } else {
554     NOTREACHED();
555   }
556 }
557 
AddRequestCommon(RequestPriority request_priority,const NetLogWithSource & request_net_log,bool is_speculative)558 void HostResolverManager::Job::AddRequestCommon(
559     RequestPriority request_priority,
560     const NetLogWithSource& request_net_log,
561     bool is_speculative) {
562   priority_tracker_.Add(request_priority);
563   request_net_log.AddEventReferencingSource(
564       NetLogEventType::HOST_RESOLVER_MANAGER_JOB_ATTACH, net_log_.source());
565   net_log_.AddEvent(
566       NetLogEventType::HOST_RESOLVER_MANAGER_JOB_REQUEST_ATTACH, [&] {
567         return NetLogJobAttachParams(request_net_log.source(), priority());
568       });
569   if (!is_speculative) {
570     had_non_speculative_request_ = true;
571   }
572 }
573 
CancelRequestCommon(RequestPriority request_priority,const NetLogWithSource & request_net_log)574 void HostResolverManager::Job::CancelRequestCommon(
575     RequestPriority request_priority,
576     const NetLogWithSource& request_net_log) {
577   priority_tracker_.Remove(request_priority);
578   net_log_.AddEvent(
579       NetLogEventType::HOST_RESOLVER_MANAGER_JOB_REQUEST_DETACH, [&] {
580         return NetLogJobAttachParams(request_net_log.source(), priority());
581       });
582 }
583 
UpdatePriority()584 void HostResolverManager::Job::UpdatePriority() {
585   if (is_queued()) {
586     handle_ = resolver_->dispatcher_->ChangePriority(handle_, priority());
587   }
588 }
589 
Start()590 void HostResolverManager::Job::Start() {
591   handle_.Reset();
592   ++num_occupied_job_slots_;
593 
594   if (num_occupied_job_slots_ >= 2) {
595     if (!dns_task_) {
596       resolver_->dispatcher_->OnJobFinished();
597       return;
598     }
599     StartNextDnsTransaction();
600     DCHECK_EQ(num_occupied_job_slots_,
601               dns_task_->num_transactions_in_progress());
602     if (dns_task_->num_additional_transactions_needed() >= 1) {
603       Schedule(true);
604     }
605     return;
606   }
607 
608   DCHECK(!is_running());
609   DCHECK(!tasks_.empty());
610   RunNextTask();
611   // Caution: Job::Start must not complete synchronously.
612 }
613 
StartSystemTask()614 void HostResolverManager::Job::StartSystemTask() {
615   DCHECK(dispatched_);
616   DCHECK_EQ(1, num_occupied_job_slots_);
617   DCHECK(HasAddressType(key_.query_types));
618 
619   std::optional<HostResolverSystemTask::CacheParams> cache_params;
620   if (key_.resolve_context->host_resolver_cache()) {
621     cache_params.emplace(*key_.resolve_context->host_resolver_cache(),
622                          key_.network_anonymization_key);
623   }
624 
625   system_task_ = HostResolverSystemTask::Create(
626       std::string(key_.host.GetHostnameWithoutBrackets()),
627       HostResolver::DnsQueryTypeSetToAddressFamily(key_.query_types),
628       key_.flags, resolver_->host_resolver_system_params_, net_log_,
629       key_.GetTargetNetwork(), std::move(cache_params));
630 
631   // Start() could be called from within Resolve(), hence it must NOT directly
632   // call OnSystemTaskComplete, for example, on synchronous failure.
633   system_task_->Start(base::BindOnce(&Job::OnSystemTaskComplete,
634                                      base::Unretained(this),
635                                      tick_clock_->NowTicks()));
636 }
637 
OnSystemTaskComplete(base::TimeTicks start_time,const AddressList & addr_list,int,int net_error)638 void HostResolverManager::Job::OnSystemTaskComplete(
639     base::TimeTicks start_time,
640     const AddressList& addr_list,
641     int /*os_error*/,
642     int net_error) {
643   DCHECK(system_task_);
644 
645   base::TimeDelta duration = tick_clock_->NowTicks() - start_time;
646   if (net_error == OK) {
647     UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.SystemTask.SuccessTime", duration);
648   } else {
649     UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.SystemTask.FailureTime", duration);
650   }
651 
652   if (dns_task_error_ != OK && net_error == OK) {
653     // This HostResolverSystemTask was a fallback resolution after a failed
654     // insecure DnsTask.
655     resolver_->OnFallbackResolve(dns_task_error_);
656   }
657 
658   if (ContainsIcannNameCollisionIp(addr_list.endpoints())) {
659     net_error = ERR_ICANN_NAME_COLLISION;
660   }
661 
662   base::TimeDelta ttl = base::Seconds(kNegativeCacheEntryTTLSeconds);
663   if (net_error == OK) {
664     ttl = base::Seconds(kCacheEntryTTLSeconds);
665   }
666 
667   auto aliases = std::set<std::string>(addr_list.dns_aliases().begin(),
668                                        addr_list.dns_aliases().end());
669 
670   // Source unknown because the system resolver could have gotten it from a
671   // hosts file, its own cache, a DNS lookup or somewhere else.
672   // Don't store the |ttl| in cache since it's not obtained from the server.
673   CompleteRequests(
674       HostCache::Entry(
675           net_error,
676           net_error == OK ? addr_list.endpoints() : std::vector<IPEndPoint>(),
677           std::move(aliases), HostCache::Entry::SOURCE_UNKNOWN),
678       ttl, /*allow_cache=*/true, /*secure=*/false, TaskType::SYSTEM);
679 }
680 
InsecureCacheLookup()681 void HostResolverManager::Job::InsecureCacheLookup() {
682   // Insecure cache lookups for requests allowing stale results should have
683   // occurred prior to Job creation.
684   DCHECK(cache_usage_ != ResolveHostParameters::CacheUsage::STALE_ALLOWED);
685   std::optional<HostCache::EntryStaleness> stale_info;
686   std::optional<HostCache::Entry> resolved = resolver_->MaybeServeFromCache(
687       host_cache_, key_.ToCacheKey(/*secure=*/false), cache_usage_,
688       false /* ignore_secure */, net_log_, &stale_info);
689 
690   if (resolved) {
691     DCHECK(stale_info);
692     DCHECK(!stale_info.value().is_stale());
693     CompleteRequestsWithoutCache(resolved.value(), std::move(stale_info),
694                                  TaskType::INSECURE_CACHE_LOOKUP);
695   } else {
696     RunNextTask();
697   }
698 }
699 
StartDnsTask(bool secure)700 void HostResolverManager::Job::StartDnsTask(bool secure) {
701   DCHECK_EQ(secure, !dispatched_);
702   DCHECK_EQ(dispatched_ ? 1 : 0, num_occupied_job_slots_);
703   DCHECK(!resolver_->ShouldForceSystemResolverDueToTestOverride());
704 
705   // Need to create the task even if we're going to post a failure instead of
706   // running it, as a "started" job needs a task to be properly cleaned up.
707   dns_task_ = std::make_unique<HostResolverDnsTask>(
708       resolver_->dns_client_.get(), key_.host, key_.network_anonymization_key,
709       key_.query_types, &*key_.resolve_context, secure, key_.secure_dns_mode,
710       this, net_log_, tick_clock_, !tasks_.empty() /* fallback_available */,
711       https_svcb_options_);
712   dns_task_->StartNextTransaction();
713   // Schedule a second transaction, if needed. DoH queries can bypass the
714   // dispatcher and start all of their transactions immediately.
715   if (secure) {
716     while (dns_task_->num_additional_transactions_needed() >= 1) {
717       dns_task_->StartNextTransaction();
718     }
719     DCHECK_EQ(dns_task_->num_additional_transactions_needed(), 0);
720   } else if (dns_task_->num_additional_transactions_needed() >= 1) {
721     Schedule(true);
722   }
723 }
724 
StartNextDnsTransaction()725 void HostResolverManager::Job::StartNextDnsTransaction() {
726   DCHECK(dns_task_);
727   DCHECK_EQ(dns_task_->secure(), !dispatched_);
728   DCHECK(!dispatched_ || num_occupied_job_slots_ ==
729                              dns_task_->num_transactions_in_progress() + 1);
730   DCHECK_GE(dns_task_->num_additional_transactions_needed(), 1);
731   dns_task_->StartNextTransaction();
732 }
733 
OnDnsTaskFailure(const base::WeakPtr<HostResolverDnsTask> & dns_task,base::TimeDelta duration,bool allow_fallback,const HostCache::Entry & failure_results,bool secure)734 void HostResolverManager::Job::OnDnsTaskFailure(
735     const base::WeakPtr<HostResolverDnsTask>& dns_task,
736     base::TimeDelta duration,
737     bool allow_fallback,
738     const HostCache::Entry& failure_results,
739     bool secure) {
740   DCHECK_NE(OK, failure_results.error());
741 
742   if (!secure) {
743     DCHECK_NE(key_.secure_dns_mode, SecureDnsMode::kSecure);
744     UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.InsecureDnsTask.FailureTime",
745                                  duration);
746   }
747 
748   if (!dns_task) {
749     return;
750   }
751 
752   UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.Failure",
753                                total_transaction_time_queued_);
754 
755   // If one of the fallback tasks doesn't complete the request, store a result
756   // to use during request completion.
757   base::TimeDelta ttl =
758       failure_results.has_ttl() ? failure_results.ttl() : base::Seconds(0);
759   completion_results_.push_back({failure_results, ttl, secure});
760 
761   dns_task_error_ = failure_results.error();
762   KillDnsTask();
763 
764   if (!allow_fallback) {
765     tasks_.clear();
766   }
767 
768   RunNextTask();
769 }
770 
OnDnsTaskComplete(base::TimeTicks start_time,bool allow_fallback,HostResolverDnsTask::Results results,bool secure)771 void HostResolverManager::Job::OnDnsTaskComplete(
772     base::TimeTicks start_time,
773     bool allow_fallback,
774     HostResolverDnsTask::Results results,
775     bool secure) {
776   DCHECK(dns_task_);
777 
778   HostCache::Entry legacy_results(results, base::Time::Now(),
779                                   tick_clock_->NowTicks(),
780                                   HostCache::Entry::SOURCE_DNS);
781 
782   // Tasks containing address queries are only considered successful overall
783   // if they find address results. However, DnsTask may claim success if any
784   // transaction, e.g. a supplemental HTTPS transaction, finds results.
785   DCHECK(!key_.query_types.Has(DnsQueryType::UNSPECIFIED));
786   if (HasAddressType(key_.query_types) && legacy_results.error() == OK &&
787       legacy_results.ip_endpoints().empty()) {
788     legacy_results.set_error(ERR_NAME_NOT_RESOLVED);
789   }
790 
791   base::TimeDelta duration = tick_clock_->NowTicks() - start_time;
792   if (legacy_results.error() != OK) {
793     OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, allow_fallback,
794                      legacy_results, secure);
795     return;
796   }
797 
798   UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.DnsTask.SuccessTime", duration);
799 
800   UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.Success",
801                                total_transaction_time_queued_);
802 
803   // Reset the insecure DNS failure counter if an insecure DnsTask completed
804   // successfully.
805   if (!secure) {
806     resolver_->dns_client_->ClearInsecureFallbackFailures();
807   }
808 
809   base::TimeDelta bounded_ttl =
810       std::max(legacy_results.ttl(), base::Seconds(kMinimumTTLSeconds));
811 
812   if (ContainsIcannNameCollisionIp(legacy_results.ip_endpoints())) {
813     CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION,
814                               secure ? TaskType::SECURE_DNS : TaskType::DNS);
815     return;
816   }
817 
818   CompleteRequests(legacy_results, bounded_ttl, true /* allow_cache */, secure,
819                    secure ? TaskType::SECURE_DNS : TaskType::DNS);
820 }
821 
OnIntermediateTransactionsComplete(std::optional<HostResolverDnsTask::SingleTransactionResults> single_transaction_results)822 void HostResolverManager::Job::OnIntermediateTransactionsComplete(
823     std::optional<HostResolverDnsTask::SingleTransactionResults>
824         single_transaction_results) {
825   if (dispatched_) {
826     DCHECK_GE(num_occupied_job_slots_,
827               dns_task_->num_transactions_in_progress());
828     int unused_slots =
829         num_occupied_job_slots_ - dns_task_->num_transactions_in_progress();
830 
831     // Reuse vacated slots for any remaining transactions.
832     while (unused_slots > 0 &&
833            dns_task_->num_additional_transactions_needed() > 0) {
834       dns_task_->StartNextTransaction();
835       --unused_slots;
836     }
837 
838     // If all remaining transactions found a slot, no more needed from the
839     // dispatcher.
840     if (is_queued() && dns_task_->num_additional_transactions_needed() == 0) {
841       resolver_->dispatcher_->Cancel(handle_);
842       handle_.Reset();
843     }
844 
845     // Relinquish any remaining extra slots.
846     while (unused_slots > 0) {
847       ReduceByOneJobSlot();
848       --unused_slots;
849     }
850   } else if (dns_task_->num_additional_transactions_needed() >= 1) {
851     dns_task_->StartNextTransaction();
852   }
853 
854   if (dns_task_results_manager_ && single_transaction_results.has_value()) {
855     dns_task_results_manager_->ProcessDnsTransactionResults(
856         single_transaction_results->query_type,
857         std::move(single_transaction_results->results));
858     // `this` may be deleted. Do not add code below.
859   }
860 }
861 
AddTransactionTimeQueued(base::TimeDelta time_queued)862 void HostResolverManager::Job::AddTransactionTimeQueued(
863     base::TimeDelta time_queued) {
864   total_transaction_time_queued_ += time_queued;
865 }
866 
OnServiceEndpointsUpdated()867 void HostResolverManager::Job::OnServiceEndpointsUpdated() {
868   // Requests could be destroyed while executing callbacks. Post tasks
869   // instead of calling callbacks synchronously to prevent requests from being
870   // destroyed in the following for loop.
871   for (auto* request = service_endpoint_requests_.head();
872        request != service_endpoint_requests_.end(); request = request->next()) {
873     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
874         FROM_HERE,
875         base::BindOnce(&ServiceEndpointRequestImpl::OnServiceEndpointsChanged,
876                        request->value()->GetWeakPtr()));
877   }
878 }
879 
StartMdnsTask()880 void HostResolverManager::Job::StartMdnsTask() {
881   // No flags are supported for MDNS except
882   // HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 (which is not actually an
883   // input flag).
884   DCHECK_EQ(0, key_.flags & ~HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6);
885 
886   MDnsClient* client = nullptr;
887   int rv = resolver_->GetOrCreateMdnsClient(&client);
888   mdns_task_ = std::make_unique<HostResolverMdnsTask>(
889       client, std::string(key_.host.GetHostnameWithoutBrackets()),
890       key_.query_types);
891 
892   if (rv == OK) {
893     mdns_task_->Start(
894         base::BindOnce(&Job::OnMdnsTaskComplete, base::Unretained(this)));
895   } else {
896     // Could not create an mDNS client. Since we cannot complete synchronously
897     // from here, post a failure without starting the task.
898     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
899         FROM_HERE, base::BindOnce(&Job::OnMdnsImmediateFailure,
900                                   weak_ptr_factory_.GetWeakPtr(), rv));
901   }
902 }
903 
OnMdnsTaskComplete()904 void HostResolverManager::Job::OnMdnsTaskComplete() {
905   DCHECK(mdns_task_);
906   // TODO(crbug.com/40577881): Consider adding MDNS-specific logging.
907 
908   HostCache::Entry results = mdns_task_->GetResults();
909 
910   if (ContainsIcannNameCollisionIp(results.ip_endpoints())) {
911     CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION, TaskType::MDNS);
912     return;
913   }
914   // MDNS uses a separate cache, so skip saving result to cache.
915   // TODO(crbug.com/40611558): Consider merging caches.
916   CompleteRequestsWithoutCache(results, std::nullopt /* stale_info */,
917                                TaskType::MDNS);
918 }
919 
OnMdnsImmediateFailure(int rv)920 void HostResolverManager::Job::OnMdnsImmediateFailure(int rv) {
921   DCHECK(mdns_task_);
922   DCHECK_NE(OK, rv);
923 
924   CompleteRequestsWithError(rv, TaskType::MDNS);
925 }
926 
StartNat64Task()927 void HostResolverManager::Job::StartNat64Task() {
928   DCHECK(!nat64_task_);
929   nat64_task_ = std::make_unique<HostResolverNat64Task>(
930       key_.host.GetHostnameWithoutBrackets(), key_.network_anonymization_key,
931       net_log_, &*key_.resolve_context, resolver_);
932   nat64_task_->Start(base::BindOnce(&Job::OnNat64TaskComplete,
933                                     weak_ptr_factory_.GetWeakPtr()));
934 }
935 
OnNat64TaskComplete()936 void HostResolverManager::Job::OnNat64TaskComplete() {
937   DCHECK(nat64_task_);
938   HostCache::Entry results = nat64_task_->GetResults();
939   CompleteRequestsWithoutCache(results, std::nullopt /* stale_info */,
940                                TaskType::NAT64);
941 }
942 
RecordJobHistograms(const HostCache::Entry & results,std::optional<TaskType> task_type)943 void HostResolverManager::Job::RecordJobHistograms(
944     const HostCache::Entry& results,
945     std::optional<TaskType> task_type) {
946   int error = results.error();
947   // Used in UMA_HISTOGRAM_ENUMERATION. Do not renumber entries or reuse
948   // deprecated values.
949   enum Category {
950     RESOLVE_SUCCESS = 0,
951     RESOLVE_FAIL = 1,
952     RESOLVE_SPECULATIVE_SUCCESS = 2,
953     RESOLVE_SPECULATIVE_FAIL = 3,
954     RESOLVE_ABORT = 4,
955     RESOLVE_SPECULATIVE_ABORT = 5,
956     RESOLVE_MAX,  // Bounding value.
957   };
958   Category category = RESOLVE_MAX;  // Illegal value for later DCHECK only.
959 
960   base::TimeDelta duration = tick_clock_->NowTicks() - start_time_;
961   if (error == OK) {
962     if (had_non_speculative_request_) {
963       category = RESOLVE_SUCCESS;
964       UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime", duration);
965     } else {
966       category = RESOLVE_SPECULATIVE_SUCCESS;
967     }
968   } else if (error == ERR_NETWORK_CHANGED ||
969              error == ERR_HOST_RESOLVER_QUEUE_TOO_LARGE) {
970     category = had_non_speculative_request_ ? RESOLVE_ABORT
971                                             : RESOLVE_SPECULATIVE_ABORT;
972   } else {
973     if (had_non_speculative_request_) {
974       category = RESOLVE_FAIL;
975       UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime", duration);
976     } else {
977       category = RESOLVE_SPECULATIVE_FAIL;
978     }
979   }
980   DCHECK_LT(static_cast<int>(category),
981             static_cast<int>(RESOLVE_MAX));  // Be sure it was set.
982   UMA_HISTOGRAM_ENUMERATION("Net.DNS.ResolveCategory", category, RESOLVE_MAX);
983 
984   if (category == RESOLVE_FAIL ||
985       (start_time_ != base::TimeTicks() && category == RESOLVE_ABORT)) {
986     if (duration < base::Milliseconds(10)) {
987       base::UmaHistogramSparse("Net.DNS.ResolveError.Fast", std::abs(error));
988     } else {
989       base::UmaHistogramSparse("Net.DNS.ResolveError.Slow", std::abs(error));
990     }
991   }
992 
993   if (error == OK) {
994     DCHECK(task_type.has_value());
995     // Record, for HTTPS-capable queries to a host known to serve HTTPS
996     // records, whether the HTTPS record was successfully received.
997     if (key_.query_types.Has(DnsQueryType::HTTPS) &&
998         // Skip http- and ws-schemed hosts. Although they query HTTPS records,
999         // successful queries are reported as errors, which would skew the
1000         // metrics.
1001         IsSchemeHttpsOrWss(key_.host) &&
1002         IsGoogleHostWithAlpnH3(key_.host.GetHostnameWithoutBrackets())) {
1003       bool has_metadata = !results.GetMetadatas().empty();
1004       base::UmaHistogramExactLinear(
1005           "Net.DNS.H3SupportedGoogleHost.TaskTypeMetadataAvailability2",
1006           static_cast<int>(task_type.value()) * 2 + (has_metadata ? 1 : 0),
1007           (static_cast<int>(TaskType::kMaxValue) + 1) * 2);
1008     }
1009   }
1010 }
1011 
MaybeCacheResult(const HostCache::Entry & results,base::TimeDelta ttl,bool secure)1012 void HostResolverManager::Job::MaybeCacheResult(const HostCache::Entry& results,
1013                                                 base::TimeDelta ttl,
1014                                                 bool secure) {
1015   // If the request did not complete, don't cache it.
1016   if (!results.did_complete()) {
1017     return;
1018   }
1019   resolver_->CacheResult(host_cache_, key_.ToCacheKey(secure), results, ttl);
1020 }
1021 
CompleteRequests(const HostCache::Entry & results,base::TimeDelta ttl,bool allow_cache,bool secure,std::optional<TaskType> task_type)1022 void HostResolverManager::Job::CompleteRequests(
1023     const HostCache::Entry& results,
1024     base::TimeDelta ttl,
1025     bool allow_cache,
1026     bool secure,
1027     std::optional<TaskType> task_type) {
1028   CHECK(resolver_.get());
1029 
1030   // This job must be removed from resolver's |jobs_| now to make room for a
1031   // new job with the same key in case one of the OnComplete callbacks decides
1032   // to spawn one. Consequently, if the job was owned by |jobs_|, the job
1033   // deletes itself when CompleteRequests is done.
1034   std::unique_ptr<Job> self_deleter;
1035   if (self_iterator_) {
1036     self_deleter = resolver_->RemoveJob(self_iterator_.value());
1037   }
1038 
1039   Finish();
1040 
1041   if (results.error() == ERR_DNS_REQUEST_CANCELLED) {
1042     net_log_.AddEvent(NetLogEventType::CANCELLED);
1043     net_log_.EndEventWithNetErrorCode(
1044         NetLogEventType::HOST_RESOLVER_MANAGER_JOB, OK);
1045     return;
1046   }
1047 
1048   net_log_.EndEventWithNetErrorCode(NetLogEventType::HOST_RESOLVER_MANAGER_JOB,
1049                                     results.error());
1050 
1051   // Handle all caching before completing requests as completing requests may
1052   // start new requests that rely on cached results.
1053   if (allow_cache) {
1054     MaybeCacheResult(results, ttl, secure);
1055   }
1056 
1057   RecordJobHistograms(results, task_type);
1058 
1059   // Complete all of the requests that were attached to the job and
1060   // detach them.
1061   while (!requests_.empty()) {
1062     RequestImpl* req = requests_.head()->value();
1063     req->RemoveFromList();
1064     CHECK(key_ == req->GetJobKey());
1065 
1066     if (results.error() == OK && !req->parameters().is_speculative) {
1067       req->set_results(
1068           results.CopyWithDefaultPort(req->request_host().GetPort()));
1069     }
1070     req->OnJobCompleted(
1071         key_, results.error(),
1072         /*is_secure_network_error=*/secure && results.error() != OK);
1073 
1074     // Check if the resolver was destroyed as a result of running the
1075     // callback. If it was, we could continue, but we choose to bail.
1076     if (!resolver_.get()) {
1077       return;
1078     }
1079   }
1080 
1081   while (!service_endpoint_requests_.empty()) {
1082     ServiceEndpointRequestImpl* request =
1083         service_endpoint_requests_.head()->value();
1084     request->RemoveFromList();
1085     request->OnJobCompleted(results, secure);
1086     if (!resolver_.get()) {
1087       return;
1088     }
1089   }
1090 
1091   // TODO(crbug.com/40178456): Call StartBootstrapFollowup() if any of the
1092   // requests have the Bootstrap policy.  Note: A naive implementation could
1093   // cause an infinite loop if the bootstrap result has TTL=0.
1094 }
1095 
CompleteRequestsWithoutCache(const HostCache::Entry & results,std::optional<HostCache::EntryStaleness> stale_info,TaskType task_type)1096 void HostResolverManager::Job::CompleteRequestsWithoutCache(
1097     const HostCache::Entry& results,
1098     std::optional<HostCache::EntryStaleness> stale_info,
1099     TaskType task_type) {
1100   // Record the stale_info for all non-speculative requests, if it exists.
1101   if (stale_info) {
1102     for (auto* node = requests_.head(); node != requests_.end();
1103          node = node->next()) {
1104       if (!node->value()->parameters().is_speculative) {
1105         node->value()->set_stale_info(stale_info.value());
1106       }
1107     }
1108   }
1109   CompleteRequests(results, base::TimeDelta(), false /* allow_cache */,
1110                    false /* secure */, task_type);
1111 }
1112 
CompleteRequestsWithError(int net_error,std::optional<TaskType> task_type)1113 void HostResolverManager::Job::CompleteRequestsWithError(
1114     int net_error,
1115     std::optional<TaskType> task_type) {
1116   DCHECK_NE(OK, net_error);
1117   CompleteRequests(
1118       HostCache::Entry(net_error, HostCache::Entry::SOURCE_UNKNOWN),
1119       base::TimeDelta(), true /* allow_cache */, false /* secure */, task_type);
1120 }
1121 
priority() const1122 RequestPriority HostResolverManager::Job::priority() const {
1123   return priority_tracker_.highest_priority();
1124 }
1125 
1126 }  // namespace net
1127