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