xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_internal_result.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 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_internal_result.h"
6 
7 #include <map>
8 #include <memory>
9 #include <optional>
10 #include <ostream>
11 #include <string>
12 #include <string_view>
13 #include <utility>
14 #include <vector>
15 
16 #include "base/check_op.h"
17 #include "base/json/values_util.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "net/base/connection_endpoint_metadata.h"
22 #include "net/base/host_port_pair.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/dns/https_record_rdata.h"
26 #include "net/dns/public/dns_query_type.h"
27 #include "url/url_canon.h"
28 #include "url/url_canon_stdstring.h"
29 
30 namespace net {
31 
32 namespace {
33 
34 // base::Value keys
35 constexpr std::string_view kValueDomainNameKey = "domain_name";
36 constexpr std::string_view kValueQueryTypeKey = "query_type";
37 constexpr std::string_view kValueTypeKey = "type";
38 constexpr std::string_view kValueSourceKey = "source";
39 constexpr std::string_view kValueTimedExpirationKey = "timed_expiration";
40 constexpr std::string_view kValueEndpointsKey = "endpoints";
41 constexpr std::string_view kValueStringsKey = "strings";
42 constexpr std::string_view kValueHostsKey = "hosts";
43 constexpr std::string_view kValueMetadatasKey = "metadatas";
44 constexpr std::string_view kValueMetadataWeightKey = "metadata_weight";
45 constexpr std::string_view kValueMetadataValueKey = "metadata_value";
46 constexpr std::string_view kValueErrorKey = "error";
47 constexpr std::string_view kValueAliasTargetKey = "alias_target";
48 
49 // Returns `domain_name` as-is if it could not be canonicalized.
MaybeCanonicalizeName(std::string domain_name)50 std::string MaybeCanonicalizeName(std::string domain_name) {
51   std::string canonicalized;
52   url::StdStringCanonOutput output(&canonicalized);
53   url::CanonHostInfo host_info;
54 
55   url::CanonicalizeHostVerbose(domain_name.data(),
56                                url::Component(0, domain_name.size()), &output,
57                                &host_info);
58 
59   if (host_info.family == url::CanonHostInfo::Family::NEUTRAL) {
60     output.Complete();
61     return canonicalized;
62   } else {
63     return domain_name;
64   }
65 }
66 
EndpointMetadataPairToValue(const std::pair<HttpsRecordPriority,ConnectionEndpointMetadata> & pair)67 base::Value EndpointMetadataPairToValue(
68     const std::pair<HttpsRecordPriority, ConnectionEndpointMetadata>& pair) {
69   base::Value::Dict dictionary;
70   dictionary.Set(kValueMetadataWeightKey, pair.first);
71   dictionary.Set(kValueMetadataValueKey, pair.second.ToValue());
72   return base::Value(std::move(dictionary));
73 }
74 
75 std::optional<std::pair<HttpsRecordPriority, ConnectionEndpointMetadata>>
EndpointMetadataPairFromValue(const base::Value & value)76 EndpointMetadataPairFromValue(const base::Value& value) {
77   const base::Value::Dict* dict = value.GetIfDict();
78   if (!dict)
79     return std::nullopt;
80 
81   std::optional<int> weight = dict->FindInt(kValueMetadataWeightKey);
82   if (!weight || !base::IsValueInRangeForNumericType<HttpsRecordPriority>(
83                      weight.value())) {
84     return std::nullopt;
85   }
86 
87   const base::Value* metadata_value = dict->Find(kValueMetadataValueKey);
88   if (!metadata_value)
89     return std::nullopt;
90   std::optional<ConnectionEndpointMetadata> metadata =
91       ConnectionEndpointMetadata::FromValue(*metadata_value);
92   if (!metadata)
93     return std::nullopt;
94 
95   return std::pair(base::checked_cast<HttpsRecordPriority>(weight.value()),
96                    std::move(metadata).value());
97 }
98 
QueryTypeFromValue(const base::Value & value)99 std::optional<DnsQueryType> QueryTypeFromValue(const base::Value& value) {
100   const std::string* query_type_string = value.GetIfString();
101   if (!query_type_string)
102     return std::nullopt;
103   const auto query_type_it =
104       base::ranges::find(kDnsQueryTypes, *query_type_string,
105                          &decltype(kDnsQueryTypes)::value_type::second);
106   if (query_type_it == kDnsQueryTypes.end())
107     return std::nullopt;
108 
109   return query_type_it->first;
110 }
111 
TypeToValue(HostResolverInternalResult::Type type)112 base::Value TypeToValue(HostResolverInternalResult::Type type) {
113   switch (type) {
114     case HostResolverInternalResult::Type::kData:
115       return base::Value("data");
116     case HostResolverInternalResult::Type::kMetadata:
117       return base::Value("metadata");
118     case HostResolverInternalResult::Type::kError:
119       return base::Value("error");
120     case HostResolverInternalResult::Type::kAlias:
121       return base::Value("alias");
122   }
123 }
124 
TypeFromValue(const base::Value & value)125 std::optional<HostResolverInternalResult::Type> TypeFromValue(
126     const base::Value& value) {
127   const std::string* string = value.GetIfString();
128   if (!string)
129     return std::nullopt;
130 
131   if (*string == "data") {
132     return HostResolverInternalResult::Type::kData;
133   } else if (*string == "metadata") {
134     return HostResolverInternalResult::Type::kMetadata;
135   } else if (*string == "error") {
136     return HostResolverInternalResult::Type::kError;
137   } else if (*string == "alias") {
138     return HostResolverInternalResult::Type::kAlias;
139   } else {
140     return std::nullopt;
141   }
142 }
143 
SourceToValue(HostResolverInternalResult::Source source)144 base::Value SourceToValue(HostResolverInternalResult::Source source) {
145   switch (source) {
146     case HostResolverInternalResult::Source::kDns:
147       return base::Value("dns");
148     case HostResolverInternalResult::Source::kHosts:
149       return base::Value("hosts");
150     case HostResolverInternalResult::Source::kUnknown:
151       return base::Value("unknown");
152   }
153 }
154 
SourceFromValue(const base::Value & value)155 std::optional<HostResolverInternalResult::Source> SourceFromValue(
156     const base::Value& value) {
157   const std::string* string = value.GetIfString();
158   if (!string)
159     return std::nullopt;
160 
161   if (*string == "dns") {
162     return HostResolverInternalResult::Source::kDns;
163   } else if (*string == "hosts") {
164     return HostResolverInternalResult::Source::kHosts;
165   } else if (*string == "unknown") {
166     return HostResolverInternalResult::Source::kUnknown;
167   } else {
168     return std::nullopt;
169   }
170 }
171 
172 }  // namespace
173 
174 // static
175 std::unique_ptr<HostResolverInternalResult>
FromValue(const base::Value & value)176 HostResolverInternalResult::FromValue(const base::Value& value) {
177   const base::Value::Dict* dict = value.GetIfDict();
178   if (!dict)
179     return nullptr;
180 
181   const base::Value* type_value = dict->Find(kValueTypeKey);
182   if (!type_value)
183     return nullptr;
184   std::optional<Type> type = TypeFromValue(*type_value);
185   if (!type.has_value())
186     return nullptr;
187 
188   switch (type.value()) {
189     case Type::kData:
190       return HostResolverInternalDataResult::FromValue(value);
191     case Type::kMetadata:
192       return HostResolverInternalMetadataResult::FromValue(value);
193     case Type::kError:
194       return HostResolverInternalErrorResult::FromValue(value);
195     case Type::kAlias:
196       return HostResolverInternalAliasResult::FromValue(value);
197   }
198 }
199 
AsData() const200 const HostResolverInternalDataResult& HostResolverInternalResult::AsData()
201     const {
202   CHECK_EQ(type_, Type::kData);
203   return *static_cast<const HostResolverInternalDataResult*>(this);
204 }
205 
AsData()206 HostResolverInternalDataResult& HostResolverInternalResult::AsData() {
207   CHECK_EQ(type_, Type::kData);
208   return *static_cast<HostResolverInternalDataResult*>(this);
209 }
210 
211 const HostResolverInternalMetadataResult&
AsMetadata() const212 HostResolverInternalResult::AsMetadata() const {
213   CHECK_EQ(type_, Type::kMetadata);
214   return *static_cast<const HostResolverInternalMetadataResult*>(this);
215 }
216 
AsMetadata()217 HostResolverInternalMetadataResult& HostResolverInternalResult::AsMetadata() {
218   CHECK_EQ(type_, Type::kMetadata);
219   return *static_cast<HostResolverInternalMetadataResult*>(this);
220 }
221 
AsError() const222 const HostResolverInternalErrorResult& HostResolverInternalResult::AsError()
223     const {
224   CHECK_EQ(type_, Type::kError);
225   return *static_cast<const HostResolverInternalErrorResult*>(this);
226 }
227 
AsError()228 HostResolverInternalErrorResult& HostResolverInternalResult::AsError() {
229   CHECK_EQ(type_, Type::kError);
230   return *static_cast<HostResolverInternalErrorResult*>(this);
231 }
232 
AsAlias() const233 const HostResolverInternalAliasResult& HostResolverInternalResult::AsAlias()
234     const {
235   CHECK_EQ(type_, Type::kAlias);
236   return *static_cast<const HostResolverInternalAliasResult*>(this);
237 }
238 
AsAlias()239 HostResolverInternalAliasResult& HostResolverInternalResult::AsAlias() {
240   CHECK_EQ(type_, Type::kAlias);
241   return *static_cast<HostResolverInternalAliasResult*>(this);
242 }
243 
HostResolverInternalResult(std::string domain_name,DnsQueryType query_type,std::optional<base::TimeTicks> expiration,std::optional<base::Time> timed_expiration,Type type,Source source)244 HostResolverInternalResult::HostResolverInternalResult(
245     std::string domain_name,
246     DnsQueryType query_type,
247     std::optional<base::TimeTicks> expiration,
248     std::optional<base::Time> timed_expiration,
249     Type type,
250     Source source)
251     : domain_name_(MaybeCanonicalizeName(std::move(domain_name))),
252       query_type_(query_type),
253       type_(type),
254       source_(source),
255       expiration_(expiration),
256       timed_expiration_(timed_expiration) {
257   DCHECK(!domain_name_.empty());
258   // If `expiration` has a value, `timed_expiration` must too.
259   DCHECK(!expiration_.has_value() || timed_expiration.has_value());
260 }
261 
HostResolverInternalResult(const base::Value::Dict & dict)262 HostResolverInternalResult::HostResolverInternalResult(
263     const base::Value::Dict& dict)
264     : domain_name_(*dict.FindString(kValueDomainNameKey)),
265       query_type_(QueryTypeFromValue(*dict.Find(kValueQueryTypeKey)).value()),
266       type_(TypeFromValue(*dict.Find(kValueTypeKey)).value()),
267       source_(SourceFromValue(*dict.Find(kValueSourceKey)).value()),
268       timed_expiration_(
269           dict.contains(kValueTimedExpirationKey)
270               ? base::ValueToTime(*dict.Find(kValueTimedExpirationKey))
271               : std::optional<base::Time>()) {}
272 
273 // static
ValidateValueBaseDict(const base::Value::Dict & dict,bool require_timed_expiration)274 bool HostResolverInternalResult::ValidateValueBaseDict(
275     const base::Value::Dict& dict,
276     bool require_timed_expiration) {
277   const std::string* domain_name = dict.FindString(kValueDomainNameKey);
278   if (!domain_name)
279     return false;
280 
281   const std::string* query_type_string = dict.FindString(kValueQueryTypeKey);
282   if (!query_type_string)
283     return false;
284   const auto query_type_it =
285       base::ranges::find(kDnsQueryTypes, *query_type_string,
286                          &decltype(kDnsQueryTypes)::value_type::second);
287   if (query_type_it == kDnsQueryTypes.end())
288     return false;
289 
290   const base::Value* type_value = dict.Find(kValueTypeKey);
291   if (!type_value)
292     return false;
293   std::optional<Type> type = TypeFromValue(*type_value);
294   if (!type.has_value())
295     return false;
296 
297   const base::Value* source_value = dict.Find(kValueSourceKey);
298   if (!source_value)
299     return false;
300   std::optional<Source> source = SourceFromValue(*source_value);
301   if (!source.has_value())
302     return false;
303 
304   std::optional<base::Time> timed_expiration;
305   const base::Value* timed_expiration_value =
306       dict.Find(kValueTimedExpirationKey);
307   if (require_timed_expiration && !timed_expiration_value)
308     return false;
309   if (timed_expiration_value) {
310     timed_expiration = base::ValueToTime(timed_expiration_value);
311     if (!timed_expiration.has_value())
312       return false;
313   }
314 
315   return true;
316 }
317 
ToValueBaseDict() const318 base::Value::Dict HostResolverInternalResult::ToValueBaseDict() const {
319   base::Value::Dict dict;
320 
321   dict.Set(kValueDomainNameKey, domain_name_);
322   dict.Set(kValueQueryTypeKey, kDnsQueryTypes.at(query_type_));
323   dict.Set(kValueTypeKey, TypeToValue(type_));
324   dict.Set(kValueSourceKey, SourceToValue(source_));
325 
326   // `expiration_` is not serialized because it is TimeTicks.
327 
328   if (timed_expiration_.has_value()) {
329     dict.Set(kValueTimedExpirationKey,
330              base::TimeToValue(timed_expiration_.value()));
331   }
332 
333   return dict;
334 }
335 
336 // static
337 std::unique_ptr<HostResolverInternalDataResult>
FromValue(const base::Value & value)338 HostResolverInternalDataResult::FromValue(const base::Value& value) {
339   const base::Value::Dict* dict = value.GetIfDict();
340   if (!dict || !ValidateValueBaseDict(*dict, /*require_timed_expiration=*/true))
341     return nullptr;
342 
343   const base::Value::List* endpoint_values = dict->FindList(kValueEndpointsKey);
344   if (!endpoint_values)
345     return nullptr;
346 
347   std::vector<IPEndPoint> endpoints;
348   endpoints.reserve(endpoint_values->size());
349   for (const base::Value& endpoint_value : *endpoint_values) {
350     std::optional<IPEndPoint> endpoint = IPEndPoint::FromValue(endpoint_value);
351     if (!endpoint.has_value())
352       return nullptr;
353 
354     endpoints.push_back(std::move(endpoint).value());
355   }
356 
357   const base::Value::List* string_values = dict->FindList(kValueStringsKey);
358   if (!string_values)
359     return nullptr;
360 
361   std::vector<std::string> strings;
362   strings.reserve(string_values->size());
363   for (const base::Value& string_value : *string_values) {
364     const std::string* string = string_value.GetIfString();
365     if (!string)
366       return nullptr;
367 
368     strings.push_back(*string);
369   }
370 
371   const base::Value::List* host_values = dict->FindList(kValueHostsKey);
372   if (!host_values)
373     return nullptr;
374 
375   std::vector<HostPortPair> hosts;
376   hosts.reserve(host_values->size());
377   for (const base::Value& host_value : *host_values) {
378     std::optional<HostPortPair> host = HostPortPair::FromValue(host_value);
379     if (!host.has_value())
380       return nullptr;
381 
382     hosts.push_back(std::move(host).value());
383   }
384 
385   // WrapUnique due to private constructor.
386   return base::WrapUnique(new HostResolverInternalDataResult(
387       *dict, std::move(endpoints), std::move(strings), std::move(hosts)));
388 }
389 
HostResolverInternalDataResult(std::string domain_name,DnsQueryType query_type,std::optional<base::TimeTicks> expiration,base::Time timed_expiration,Source source,std::vector<IPEndPoint> endpoints,std::vector<std::string> strings,std::vector<HostPortPair> hosts)390 HostResolverInternalDataResult::HostResolverInternalDataResult(
391     std::string domain_name,
392     DnsQueryType query_type,
393     std::optional<base::TimeTicks> expiration,
394     base::Time timed_expiration,
395     Source source,
396     std::vector<IPEndPoint> endpoints,
397     std::vector<std::string> strings,
398     std::vector<HostPortPair> hosts)
399     : HostResolverInternalResult(std::move(domain_name),
400                                  query_type,
401                                  expiration,
402                                  timed_expiration,
403                                  Type::kData,
404                                  source),
405       endpoints_(std::move(endpoints)),
406       strings_(std::move(strings)),
407       hosts_(std::move(hosts)) {
408   DCHECK(!endpoints_.empty() || !strings_.empty() || !hosts_.empty());
409 }
410 
411 HostResolverInternalDataResult::~HostResolverInternalDataResult() = default;
412 
413 std::unique_ptr<HostResolverInternalResult>
Clone() const414 HostResolverInternalDataResult::Clone() const {
415   CHECK(timed_expiration().has_value());
416   return std::make_unique<HostResolverInternalDataResult>(
417       domain_name(), query_type(), expiration(), timed_expiration().value(),
418       source(), endpoints(), strings(), hosts());
419 }
420 
ToValue() const421 base::Value HostResolverInternalDataResult::ToValue() const {
422   base::Value::Dict dict = ToValueBaseDict();
423 
424   base::Value::List endpoints_list;
425   endpoints_list.reserve(endpoints_.size());
426   for (IPEndPoint endpoint : endpoints_) {
427     endpoints_list.Append(endpoint.ToValue());
428   }
429   dict.Set(kValueEndpointsKey, std::move(endpoints_list));
430 
431   base::Value::List strings_list;
432   strings_list.reserve(strings_.size());
433   for (const std::string& string : strings_) {
434     strings_list.Append(string);
435   }
436   dict.Set(kValueStringsKey, std::move(strings_list));
437 
438   base::Value::List hosts_list;
439   hosts_list.reserve(hosts_.size());
440   for (const HostPortPair& host : hosts_) {
441     hosts_list.Append(host.ToValue());
442   }
443   dict.Set(kValueHostsKey, std::move(hosts_list));
444 
445   return base::Value(std::move(dict));
446 }
447 
HostResolverInternalDataResult(const base::Value::Dict & dict,std::vector<IPEndPoint> endpoints,std::vector<std::string> strings,std::vector<HostPortPair> hosts)448 HostResolverInternalDataResult::HostResolverInternalDataResult(
449     const base::Value::Dict& dict,
450     std::vector<IPEndPoint> endpoints,
451     std::vector<std::string> strings,
452     std::vector<HostPortPair> hosts)
453     : HostResolverInternalResult(dict),
454       endpoints_(std::move(endpoints)),
455       strings_(std::move(strings)),
456       hosts_(std::move(hosts)) {}
457 
458 // static
459 std::unique_ptr<HostResolverInternalMetadataResult>
FromValue(const base::Value & value)460 HostResolverInternalMetadataResult::FromValue(const base::Value& value) {
461   const base::Value::Dict* dict = value.GetIfDict();
462   if (!dict || !ValidateValueBaseDict(*dict, /*require_timed_expiration=*/true))
463     return nullptr;
464 
465   const base::Value::List* metadata_values = dict->FindList(kValueMetadatasKey);
466   if (!metadata_values)
467     return nullptr;
468 
469   std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata> metadatas;
470   for (const base::Value& metadata_value : *metadata_values) {
471     std::optional<std::pair<HttpsRecordPriority, ConnectionEndpointMetadata>>
472         metadata = EndpointMetadataPairFromValue(metadata_value);
473     if (!metadata.has_value())
474       return nullptr;
475     metadatas.insert(std::move(metadata).value());
476   }
477 
478   // WrapUnique due to private constructor.
479   return base::WrapUnique(
480       new HostResolverInternalMetadataResult(*dict, std::move(metadatas)));
481 }
482 
HostResolverInternalMetadataResult(std::string domain_name,DnsQueryType query_type,std::optional<base::TimeTicks> expiration,base::Time timed_expiration,Source source,std::multimap<HttpsRecordPriority,ConnectionEndpointMetadata> metadatas)483 HostResolverInternalMetadataResult::HostResolverInternalMetadataResult(
484     std::string domain_name,
485     DnsQueryType query_type,
486     std::optional<base::TimeTicks> expiration,
487     base::Time timed_expiration,
488     Source source,
489     std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata> metadatas)
490     : HostResolverInternalResult(std::move(domain_name),
491                                  query_type,
492                                  expiration,
493                                  timed_expiration,
494                                  Type::kMetadata,
495                                  source),
496       metadatas_(std::move(metadatas)) {}
497 
498 HostResolverInternalMetadataResult::~HostResolverInternalMetadataResult() =
499     default;
500 
501 std::unique_ptr<HostResolverInternalResult>
Clone() const502 HostResolverInternalMetadataResult::Clone() const {
503   CHECK(timed_expiration().has_value());
504   return std::make_unique<HostResolverInternalMetadataResult>(
505       domain_name(), query_type(), expiration(), timed_expiration().value(),
506       source(), metadatas());
507 }
508 
ToValue() const509 base::Value HostResolverInternalMetadataResult::ToValue() const {
510   base::Value::Dict dict = ToValueBaseDict();
511 
512   base::Value::List metadatas_list;
513   metadatas_list.reserve(metadatas_.size());
514   for (const std::pair<const HttpsRecordPriority, ConnectionEndpointMetadata>&
515            metadata_pair : metadatas_) {
516     metadatas_list.Append(EndpointMetadataPairToValue(metadata_pair));
517   }
518   dict.Set(kValueMetadatasKey, std::move(metadatas_list));
519 
520   return base::Value(std::move(dict));
521 }
522 
HostResolverInternalMetadataResult(const base::Value::Dict & dict,std::multimap<HttpsRecordPriority,ConnectionEndpointMetadata> metadatas)523 HostResolverInternalMetadataResult::HostResolverInternalMetadataResult(
524     const base::Value::Dict& dict,
525     std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata> metadatas)
526     : HostResolverInternalResult(dict), metadatas_(std::move(metadatas)) {}
527 
528 // static
529 std::unique_ptr<HostResolverInternalErrorResult>
FromValue(const base::Value & value)530 HostResolverInternalErrorResult::FromValue(const base::Value& value) {
531   const base::Value::Dict* dict = value.GetIfDict();
532   if (!dict ||
533       !ValidateValueBaseDict(*dict, /*require_timed_expiration=*/false)) {
534     return nullptr;
535   }
536 
537   std::optional<int> error = dict->FindInt(kValueErrorKey);
538   if (!error.has_value())
539     return nullptr;
540 
541   // WrapUnique due to private constructor.
542   return base::WrapUnique(
543       new HostResolverInternalErrorResult(*dict, error.value()));
544 }
545 
HostResolverInternalErrorResult(std::string domain_name,DnsQueryType query_type,std::optional<base::TimeTicks> expiration,std::optional<base::Time> timed_expiration,Source source,int error)546 HostResolverInternalErrorResult::HostResolverInternalErrorResult(
547     std::string domain_name,
548     DnsQueryType query_type,
549     std::optional<base::TimeTicks> expiration,
550     std::optional<base::Time> timed_expiration,
551     Source source,
552     int error)
553     : HostResolverInternalResult(std::move(domain_name),
554                                  query_type,
555                                  expiration,
556                                  timed_expiration,
557                                  Type::kError,
558                                  source),
559       error_(error) {}
560 
561 std::unique_ptr<HostResolverInternalResult>
Clone() const562 HostResolverInternalErrorResult::Clone() const {
563   return std::make_unique<HostResolverInternalErrorResult>(
564       domain_name(), query_type(), expiration(), timed_expiration(), source(),
565       error());
566 }
567 
ToValue() const568 base::Value HostResolverInternalErrorResult::ToValue() const {
569   base::Value::Dict dict = ToValueBaseDict();
570 
571   dict.Set(kValueErrorKey, error_);
572 
573   return base::Value(std::move(dict));
574 }
575 
HostResolverInternalErrorResult(const base::Value::Dict & dict,int error)576 HostResolverInternalErrorResult::HostResolverInternalErrorResult(
577     const base::Value::Dict& dict,
578     int error)
579     : HostResolverInternalResult(dict), error_(error) {
580   DCHECK_NE(error_, OK);
581 }
582 
583 // static
584 std::unique_ptr<HostResolverInternalAliasResult>
FromValue(const base::Value & value)585 HostResolverInternalAliasResult::FromValue(const base::Value& value) {
586   const base::Value::Dict* dict = value.GetIfDict();
587   if (!dict || !ValidateValueBaseDict(*dict, /*require_timed_expiration=*/true))
588     return nullptr;
589 
590   const std::string* target = dict->FindString(kValueAliasTargetKey);
591   if (!target)
592     return nullptr;
593 
594   // WrapUnique due to private constructor.
595   return base::WrapUnique(new HostResolverInternalAliasResult(*dict, *target));
596 }
597 
HostResolverInternalAliasResult(std::string domain_name,DnsQueryType query_type,std::optional<base::TimeTicks> expiration,base::Time timed_expiration,Source source,std::string alias_target)598 HostResolverInternalAliasResult::HostResolverInternalAliasResult(
599     std::string domain_name,
600     DnsQueryType query_type,
601     std::optional<base::TimeTicks> expiration,
602     base::Time timed_expiration,
603     Source source,
604     std::string alias_target)
605     : HostResolverInternalResult(std::move(domain_name),
606                                  query_type,
607                                  expiration,
608                                  timed_expiration,
609                                  Type::kAlias,
610                                  source),
611       alias_target_(MaybeCanonicalizeName(std::move(alias_target))) {
612   DCHECK(!alias_target_.empty());
613 }
614 
615 std::unique_ptr<HostResolverInternalResult>
Clone() const616 HostResolverInternalAliasResult::Clone() const {
617   CHECK(timed_expiration().has_value());
618   return std::make_unique<HostResolverInternalAliasResult>(
619       domain_name(), query_type(), expiration(), timed_expiration().value(),
620       source(), alias_target());
621 }
622 
ToValue() const623 base::Value HostResolverInternalAliasResult::ToValue() const {
624   base::Value::Dict dict = ToValueBaseDict();
625 
626   dict.Set(kValueAliasTargetKey, alias_target_);
627 
628   return base::Value(std::move(dict));
629 }
630 
HostResolverInternalAliasResult(const base::Value::Dict & dict,std::string alias_target)631 HostResolverInternalAliasResult::HostResolverInternalAliasResult(
632     const base::Value::Dict& dict,
633     std::string alias_target)
634     : HostResolverInternalResult(dict),
635       alias_target_(MaybeCanonicalizeName(std::move(alias_target))) {}
636 
637 }  // namespace net
638