1 // Copyright 2014 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/http/http_server_properties_manager.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/containers/adapters.h"
11 #include "base/feature_list.h"
12 #include "base/functional/bind.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/time/tick_clock.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "net/base/features.h"
19 #include "net/base/host_port_pair.h"
20 #include "net/base/ip_address.h"
21 #include "net/base/port_util.h"
22 #include "net/base/privacy_mode.h"
23 #include "net/http/http_server_properties.h"
24 #include "net/third_party/quiche/src/quiche/quic/platform/api/quic_hostname_utils.h"
25 #include "third_party/abseil-cpp/absl/types/optional.h"
26 #include "url/gurl.h"
27 #include "url/scheme_host_port.h"
28
29 namespace net {
30
31 namespace {
32
33 // "version" 0 indicates, http_server_properties doesn't have "version"
34 // property.
35 const int kMissingVersion = 0;
36
37 // The version number of persisted http_server_properties.
38 const int kVersionNumber = 5;
39
40 // Persist at most 200 currently-broken alternative services to disk.
41 const int kMaxBrokenAlternativeServicesToPersist = 200;
42
43 const char kServerKey[] = "server";
44 const char kQuicServerIdKey[] = "server_id";
45 const char kNetworkAnonymizationKey[] = "anonymization";
46 const char kVersionKey[] = "version";
47 const char kServersKey[] = "servers";
48 const char kSupportsSpdyKey[] = "supports_spdy";
49 const char kSupportsQuicKey[] = "supports_quic";
50 const char kQuicServers[] = "quic_servers";
51 const char kServerInfoKey[] = "server_info";
52 const char kUsedQuicKey[] = "used_quic";
53 const char kAddressKey[] = "address";
54 const char kAlternativeServiceKey[] = "alternative_service";
55 const char kProtocolKey[] = "protocol_str";
56 const char kHostKey[] = "host";
57 const char kPortKey[] = "port";
58 const char kExpirationKey[] = "expiration";
59 const char kAdvertisedAlpnsKey[] = "advertised_alpns";
60 const char kNetworkStatsKey[] = "network_stats";
61 const char kSrttKey[] = "srtt";
62 const char kBrokenAlternativeServicesKey[] = "broken_alternative_services";
63 const char kBrokenUntilKey[] = "broken_until";
64 const char kBrokenCountKey[] = "broken_count";
65
66 // Utility method to return only those AlternativeServiceInfos that should be
67 // persisted to disk. In particular, removes expired and invalid alternative
68 // services. Also checks if an alternative service for the same canonical suffix
69 // has already been saved, and if so, returns an empty list.
GetAlternativeServiceToPersist(const absl::optional<AlternativeServiceInfoVector> & alternative_services,const HttpServerProperties::ServerInfoMapKey & server_info_key,base::Time now,const HttpServerPropertiesManager::GetCannonicalSuffix & get_canonical_suffix,std::set<std::pair<std::string,NetworkAnonymizationKey>> * persisted_canonical_suffix_set)70 AlternativeServiceInfoVector GetAlternativeServiceToPersist(
71 const absl::optional<AlternativeServiceInfoVector>& alternative_services,
72 const HttpServerProperties::ServerInfoMapKey& server_info_key,
73 base::Time now,
74 const HttpServerPropertiesManager::GetCannonicalSuffix&
75 get_canonical_suffix,
76 std::set<std::pair<std::string, NetworkAnonymizationKey>>*
77 persisted_canonical_suffix_set) {
78 if (!alternative_services)
79 return AlternativeServiceInfoVector();
80 // Separate out valid, non-expired AlternativeServiceInfo entries.
81 AlternativeServiceInfoVector notbroken_alternative_service_info_vector;
82 for (const auto& alternative_service_info : alternative_services.value()) {
83 if (alternative_service_info.expiration() < now ||
84 !IsAlternateProtocolValid(
85 alternative_service_info.alternative_service().protocol)) {
86 continue;
87 }
88 notbroken_alternative_service_info_vector.push_back(
89 alternative_service_info);
90 }
91 if (notbroken_alternative_service_info_vector.empty())
92 return notbroken_alternative_service_info_vector;
93 const std::string* canonical_suffix =
94 get_canonical_suffix.Run(server_info_key.server.host());
95 if (canonical_suffix) {
96 // Don't save if have already saved information associated with the same
97 // canonical suffix.
98 std::pair<std::string, NetworkAnonymizationKey> index(
99 *canonical_suffix, server_info_key.network_anonymization_key);
100 if (persisted_canonical_suffix_set->find(index) !=
101 persisted_canonical_suffix_set->end()) {
102 return AlternativeServiceInfoVector();
103 }
104 persisted_canonical_suffix_set->emplace(std::move(index));
105 }
106 return notbroken_alternative_service_info_vector;
107 }
108
AddAlternativeServiceFieldsToDictionaryValue(const AlternativeService & alternative_service,base::Value::Dict & dict)109 void AddAlternativeServiceFieldsToDictionaryValue(
110 const AlternativeService& alternative_service,
111 base::Value::Dict& dict) {
112 dict.Set(kPortKey, alternative_service.port);
113 if (!alternative_service.host.empty()) {
114 dict.Set(kHostKey, alternative_service.host);
115 }
116 dict.Set(kProtocolKey, NextProtoToString(alternative_service.protocol));
117 }
118
119 // Fails in the case of NetworkAnonymizationKeys that can't be persisted to
120 // disk, like unique origins.
TryAddBrokenAlternativeServiceFieldsToDictionaryValue(const BrokenAlternativeService & broken_alt_service,base::Value::Dict & dict)121 bool TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
122 const BrokenAlternativeService& broken_alt_service,
123 base::Value::Dict& dict) {
124 base::Value network_anonymization_key_value;
125 if (!broken_alt_service.network_anonymization_key.ToValue(
126 &network_anonymization_key_value)) {
127 return false;
128 }
129
130 dict.Set(kNetworkAnonymizationKey,
131 std::move(network_anonymization_key_value));
132 AddAlternativeServiceFieldsToDictionaryValue(
133 broken_alt_service.alternative_service, dict);
134 return true;
135 }
136
QuicServerIdFromString(const std::string & str)137 quic::QuicServerId QuicServerIdFromString(const std::string& str) {
138 GURL url(str);
139 if (!url.is_valid()) {
140 return quic::QuicServerId();
141 }
142 HostPortPair host_port_pair = HostPortPair::FromURL(url);
143 return quic::QuicServerId(host_port_pair.host(), host_port_pair.port(),
144 url.path_piece() == "/private"
145 ? PRIVACY_MODE_ENABLED
146 : PRIVACY_MODE_DISABLED);
147 }
148
QuicServerIdToString(const quic::QuicServerId & server_id)149 std::string QuicServerIdToString(const quic::QuicServerId& server_id) {
150 HostPortPair host_port_pair(server_id.host(), server_id.port());
151 return "https://" + host_port_pair.ToString() +
152 (server_id.privacy_mode_enabled() ? "/private" : "");
153 }
154
155 // Takes in a base::Value::Dict, and whether NetworkIsolationKeys are enabled
156 // for HttpServerProperties, and extracts the NetworkAnonymizationKey stored
157 // with the |kNetworkAnonymizationKey| in the dictionary, and writes it to
158 // |out_network_anonymization_key|. Returns false if unable to load a
159 // NetworkAnonymizationKey, or the NetworkAnonymizationKey is non-empty, but
160 // |use_network_anonymization_key| is false.
GetNetworkIsolationKeyFromDict(const base::Value::Dict & dict,bool use_network_anonymization_key,NetworkAnonymizationKey * out_network_anonymization_key)161 bool GetNetworkIsolationKeyFromDict(
162 const base::Value::Dict& dict,
163 bool use_network_anonymization_key,
164 NetworkAnonymizationKey* out_network_anonymization_key) {
165 const base::Value* network_anonymization_key_value =
166 dict.Find(kNetworkAnonymizationKey);
167 NetworkAnonymizationKey network_anonymization_key;
168 if (!network_anonymization_key_value ||
169 !NetworkAnonymizationKey::FromValue(*network_anonymization_key_value,
170 &network_anonymization_key)) {
171 return false;
172 }
173
174 // Fail if NetworkIsolationKeys are disabled, but the entry has a non-empty
175 // NetworkAnonymizationKey.
176 if (!use_network_anonymization_key && !network_anonymization_key.IsEmpty())
177 return false;
178
179 *out_network_anonymization_key = std::move(network_anonymization_key);
180 return true;
181 }
182
183 } // namespace
184
185 ////////////////////////////////////////////////////////////////////////////////
186 // HttpServerPropertiesManager
187
HttpServerPropertiesManager(std::unique_ptr<HttpServerProperties::PrefDelegate> pref_delegate,OnPrefsLoadedCallback on_prefs_loaded_callback,size_t max_server_configs_stored_in_properties,NetLog * net_log,const base::TickClock * clock)188 HttpServerPropertiesManager::HttpServerPropertiesManager(
189 std::unique_ptr<HttpServerProperties::PrefDelegate> pref_delegate,
190 OnPrefsLoadedCallback on_prefs_loaded_callback,
191 size_t max_server_configs_stored_in_properties,
192 NetLog* net_log,
193 const base::TickClock* clock)
194 : pref_delegate_(std::move(pref_delegate)),
195 on_prefs_loaded_callback_(std::move(on_prefs_loaded_callback)),
196 max_server_configs_stored_in_properties_(
197 max_server_configs_stored_in_properties),
198 clock_(clock),
199 net_log_(
200 NetLogWithSource::Make(net_log,
201 NetLogSourceType::HTTP_SERVER_PROPERTIES)) {
202 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
203 DCHECK(pref_delegate_);
204 DCHECK(on_prefs_loaded_callback_);
205 DCHECK(clock_);
206
207 pref_delegate_->WaitForPrefLoad(
208 base::BindOnce(&HttpServerPropertiesManager::OnHttpServerPropertiesLoaded,
209 pref_load_weak_ptr_factory_.GetWeakPtr()));
210 net_log_.BeginEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION);
211 }
212
~HttpServerPropertiesManager()213 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
214 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
215 }
216
ReadPrefs(std::unique_ptr<HttpServerProperties::ServerInfoMap> * server_info_map,IPAddress * last_local_address_when_quic_worked,std::unique_ptr<HttpServerProperties::QuicServerInfoMap> * quic_server_info_map,std::unique_ptr<BrokenAlternativeServiceList> * broken_alternative_service_list,std::unique_ptr<RecentlyBrokenAlternativeServices> * recently_broken_alternative_services)217 void HttpServerPropertiesManager::ReadPrefs(
218 std::unique_ptr<HttpServerProperties::ServerInfoMap>* server_info_map,
219 IPAddress* last_local_address_when_quic_worked,
220 std::unique_ptr<HttpServerProperties::QuicServerInfoMap>*
221 quic_server_info_map,
222 std::unique_ptr<BrokenAlternativeServiceList>*
223 broken_alternative_service_list,
224 std::unique_ptr<RecentlyBrokenAlternativeServices>*
225 recently_broken_alternative_services) {
226 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
227
228 net_log_.EndEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION);
229
230 const base::Value::Dict& http_server_properties_dict =
231 pref_delegate_->GetServerProperties();
232
233 net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_CACHE,
234 [&] { return http_server_properties_dict.Clone(); });
235 absl::optional<int> maybe_version_number =
236 http_server_properties_dict.FindInt(kVersionKey);
237 if (!maybe_version_number.has_value() ||
238 *maybe_version_number != kVersionNumber) {
239 DVLOG(1) << "Missing or unsupported. Clearing all properties. "
240 << maybe_version_number.value_or(kMissingVersion);
241 return;
242 }
243
244 // For Version 5, data is stored in the following format.
245 // `servers` are saved in LRU order (least-recently-used item is in the
246 // front). `servers` are in the format flattened representation of
247 // (scheme/host/port) where port might be ignored if is default with scheme.
248 //
249 // "http_server_properties": {
250 // "servers": [
251 // {"https://yt3.ggpht.com" : {...}},
252 // {"http://0.client-channel.google.com:443" : {...}},
253 // {"http://0-edge-chat.facebook.com" : {...}},
254 // ...
255 // ], ...
256 // },
257 const base::Value::List* servers_list =
258 http_server_properties_dict.FindList(kServersKey);
259 if (!servers_list) {
260 DVLOG(1) << "Malformed http_server_properties for servers list.";
261 return;
262 }
263
264 ReadLastLocalAddressWhenQuicWorked(http_server_properties_dict,
265 last_local_address_when_quic_worked);
266
267 *server_info_map = std::make_unique<HttpServerProperties::ServerInfoMap>();
268 *quic_server_info_map =
269 std::make_unique<HttpServerProperties::QuicServerInfoMap>(
270 max_server_configs_stored_in_properties_);
271
272 bool use_network_anonymization_key =
273 NetworkAnonymizationKey::IsPartitioningEnabled();
274
275 // Iterate `servers_list` (least-recently-used item is in the front) so that
276 // entries are inserted into `server_info_map` from oldest to newest.
277 for (const auto& server_dict_value : *servers_list) {
278 if (!server_dict_value.is_dict()) {
279 DVLOG(1) << "Malformed http_server_properties for servers dictionary.";
280 continue;
281 }
282 AddServerData(server_dict_value.GetDict(), server_info_map->get(),
283 use_network_anonymization_key);
284 }
285
286 AddToQuicServerInfoMap(http_server_properties_dict,
287 use_network_anonymization_key,
288 quic_server_info_map->get());
289
290 // Read list containing broken and recently-broken alternative services, if
291 // it exists.
292 const base::Value::List* broken_alt_svc_list =
293 http_server_properties_dict.FindList(kBrokenAlternativeServicesKey);
294 if (broken_alt_svc_list) {
295 *broken_alternative_service_list =
296 std::make_unique<BrokenAlternativeServiceList>();
297 *recently_broken_alternative_services =
298 std::make_unique<RecentlyBrokenAlternativeServices>(
299 kMaxRecentlyBrokenAlternativeServiceEntries);
300
301 // Iterate `broken_alt_svc_list` (least-recently-used item is in the front)
302 // so that entries are inserted into `recently_broken_alternative_services`
303 // from oldest to newest.
304 for (const auto& broken_alt_svc_entry_dict_value : *broken_alt_svc_list) {
305 if (!broken_alt_svc_entry_dict_value.is_dict()) {
306 DVLOG(1) << "Malformed broken alterantive service entry.";
307 continue;
308 }
309 AddToBrokenAlternativeServices(
310 broken_alt_svc_entry_dict_value.GetDict(),
311 use_network_anonymization_key, broken_alternative_service_list->get(),
312 recently_broken_alternative_services->get());
313 }
314 }
315
316 // Set the properties loaded from prefs on |http_server_properties_impl_|.
317
318 UMA_HISTOGRAM_COUNTS_1000("Net.CountOfQuicServerInfos",
319 (*quic_server_info_map)->size());
320
321 if (*recently_broken_alternative_services) {
322 DCHECK(*broken_alternative_service_list);
323
324 UMA_HISTOGRAM_COUNTS_1000("Net.CountOfBrokenAlternativeServices",
325 (*broken_alternative_service_list)->size());
326 UMA_HISTOGRAM_COUNTS_1000("Net.CountOfRecentlyBrokenAlternativeServices",
327 (*recently_broken_alternative_services)->size());
328 }
329 }
330
AddToBrokenAlternativeServices(const base::Value::Dict & broken_alt_svc_entry_dict,bool use_network_anonymization_key,BrokenAlternativeServiceList * broken_alternative_service_list,RecentlyBrokenAlternativeServices * recently_broken_alternative_services)331 void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
332 const base::Value::Dict& broken_alt_svc_entry_dict,
333 bool use_network_anonymization_key,
334 BrokenAlternativeServiceList* broken_alternative_service_list,
335 RecentlyBrokenAlternativeServices* recently_broken_alternative_services) {
336 AlternativeService alt_service;
337 if (!ParseAlternativeServiceDict(broken_alt_svc_entry_dict, false,
338 "broken alternative services",
339 &alt_service)) {
340 return;
341 }
342
343 NetworkAnonymizationKey network_anonymization_key;
344 if (!GetNetworkIsolationKeyFromDict(broken_alt_svc_entry_dict,
345 use_network_anonymization_key,
346 &network_anonymization_key)) {
347 return;
348 }
349
350 // Each entry must contain either broken-count and/or broken-until fields.
351 bool contains_broken_count_or_broken_until = false;
352
353 // Read broken-count and add an entry for |alt_service| into
354 // |recently_broken_alternative_services|.
355 if (broken_alt_svc_entry_dict.Find(kBrokenCountKey)) {
356 absl::optional<int> broken_count =
357 broken_alt_svc_entry_dict.FindInt(kBrokenCountKey);
358 if (!broken_count.has_value()) {
359 DVLOG(1) << "Recently broken alternative service has malformed "
360 << "broken-count.";
361 return;
362 }
363 if (broken_count.value() < 0) {
364 DVLOG(1) << "Broken alternative service has negative broken-count.";
365 return;
366 }
367 recently_broken_alternative_services->Put(
368 BrokenAlternativeService(alt_service, network_anonymization_key,
369 use_network_anonymization_key),
370 broken_count.value());
371 contains_broken_count_or_broken_until = true;
372 }
373
374 // Read broken-until and add an entry for |alt_service| in
375 // |broken_alternative_service_list|.
376 if (broken_alt_svc_entry_dict.Find(kBrokenUntilKey)) {
377 const std::string* expiration_string =
378 broken_alt_svc_entry_dict.FindString(kBrokenUntilKey);
379 int64_t expiration_int64;
380 if (!expiration_string ||
381 !base::StringToInt64(*expiration_string, &expiration_int64)) {
382 DVLOG(1) << "Broken alternative service has malformed broken-until "
383 << "string.";
384 return;
385 }
386
387 time_t expiration_time_t = static_cast<time_t>(expiration_int64);
388 // Convert expiration from time_t to Time to TimeTicks
389 base::TimeTicks expiration_time_ticks =
390 clock_->NowTicks() +
391 (base::Time::FromTimeT(expiration_time_t) - base::Time::Now());
392 broken_alternative_service_list->push_back(std::make_pair(
393 BrokenAlternativeService(alt_service, network_anonymization_key,
394 use_network_anonymization_key),
395 expiration_time_ticks));
396 contains_broken_count_or_broken_until = true;
397 }
398
399 if (!contains_broken_count_or_broken_until) {
400 DVLOG(1) << "Broken alternative service has neither broken-count nor "
401 << "broken-until specified.";
402 }
403 }
404
AddServerData(const base::Value::Dict & server_dict,HttpServerProperties::ServerInfoMap * server_info_map,bool use_network_anonymization_key)405 void HttpServerPropertiesManager::AddServerData(
406 const base::Value::Dict& server_dict,
407 HttpServerProperties::ServerInfoMap* server_info_map,
408 bool use_network_anonymization_key) {
409 // Get server's scheme/host/pair.
410 const std::string* server_str = server_dict.FindString(kServerKey);
411 NetworkAnonymizationKey network_anonymization_key;
412 // Can't load entry if server name missing, or if the network isolation key is
413 // missing or invalid.
414 if (!server_str || !GetNetworkIsolationKeyFromDict(
415 server_dict, use_network_anonymization_key,
416 &network_anonymization_key)) {
417 return;
418 }
419
420 url::SchemeHostPort spdy_server((GURL(*server_str)));
421 if (spdy_server.host().empty()) {
422 DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
423 return;
424 }
425
426 HttpServerProperties::ServerInfo server_info;
427
428 server_info.supports_spdy = server_dict.FindBool(kSupportsSpdyKey);
429
430 if (ParseAlternativeServiceInfo(spdy_server, server_dict, &server_info))
431 ParseNetworkStats(spdy_server, server_dict, &server_info);
432
433 if (!server_info.empty()) {
434 server_info_map->Put(HttpServerProperties::ServerInfoMapKey(
435 std::move(spdy_server), network_anonymization_key,
436 use_network_anonymization_key),
437 std::move(server_info));
438 }
439 }
440
ParseAlternativeServiceDict(const base::Value::Dict & dict,bool host_optional,const std::string & parsing_under,AlternativeService * alternative_service)441 bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
442 const base::Value::Dict& dict,
443 bool host_optional,
444 const std::string& parsing_under,
445 AlternativeService* alternative_service) {
446 // Protocol is mandatory.
447 const std::string* protocol_str = dict.FindString(kProtocolKey);
448 if (!protocol_str) {
449 DVLOG(1) << "Malformed alternative service protocol string under: "
450 << parsing_under;
451 return false;
452 }
453 NextProto protocol = NextProtoFromString(*protocol_str);
454 if (!IsAlternateProtocolValid(protocol)) {
455 DVLOG(1) << "Invalid alternative service protocol string \"" << protocol_str
456 << "\" under: " << parsing_under;
457 return false;
458 }
459 alternative_service->protocol = protocol;
460
461 // If host is optional, it defaults to "".
462 std::string host = "";
463 const std::string* hostp = nullptr;
464 if (dict.Find(kHostKey)) {
465 hostp = dict.FindString(kHostKey);
466 if (!hostp) {
467 DVLOG(1) << "Malformed alternative service host string under: "
468 << parsing_under;
469 return false;
470 }
471 host = *hostp;
472 } else if (!host_optional) {
473 DVLOG(1) << "alternative service missing host string under: "
474 << parsing_under;
475 return false;
476 }
477 alternative_service->host = host;
478
479 // Port is mandatory.
480 absl::optional<int> maybe_port = dict.FindInt(kPortKey);
481 if (!maybe_port.has_value() || !IsPortValid(maybe_port.value())) {
482 DVLOG(1) << "Malformed alternative service port under: " << parsing_under;
483 return false;
484 }
485 alternative_service->port = static_cast<uint32_t>(maybe_port.value());
486
487 return true;
488 }
489
ParseAlternativeServiceInfoDictOfServer(const base::Value::Dict & dict,const std::string & server_str,AlternativeServiceInfo * alternative_service_info)490 bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
491 const base::Value::Dict& dict,
492 const std::string& server_str,
493 AlternativeServiceInfo* alternative_service_info) {
494 AlternativeService alternative_service;
495 if (!ParseAlternativeServiceDict(dict, true, "server " + server_str,
496 &alternative_service)) {
497 return false;
498 }
499 alternative_service_info->set_alternative_service(alternative_service);
500
501 // Expiration is optional, defaults to one day.
502 if (!dict.Find(kExpirationKey)) {
503 alternative_service_info->set_expiration(base::Time::Now() + base::Days(1));
504 } else {
505 const std::string* expiration_string = dict.FindString(kExpirationKey);
506 if (expiration_string) {
507 int64_t expiration_int64 = 0;
508 if (!base::StringToInt64(*expiration_string, &expiration_int64)) {
509 DVLOG(1) << "Malformed alternative service expiration for server: "
510 << server_str;
511 return false;
512 }
513 alternative_service_info->set_expiration(
514 base::Time::FromInternalValue(expiration_int64));
515 } else {
516 DVLOG(1) << "Malformed alternative service expiration for server: "
517 << server_str;
518 return false;
519 }
520 }
521
522 // Advertised versions list is optional.
523 if (dict.Find(kAdvertisedAlpnsKey)) {
524 const base::Value::List* versions_list = dict.FindList(kAdvertisedAlpnsKey);
525 if (!versions_list) {
526 DVLOG(1) << "Malformed alternative service advertised versions list for "
527 << "server: " << server_str;
528 return false;
529 }
530 quic::ParsedQuicVersionVector advertised_versions;
531 for (const auto& value : *versions_list) {
532 const std::string* version_string = value.GetIfString();
533 if (!version_string) {
534 DVLOG(1) << "Malformed alternative service version for server: "
535 << server_str;
536 return false;
537 }
538 quic::ParsedQuicVersion version =
539 quic::ParseQuicVersionString(*version_string);
540 if (version != quic::ParsedQuicVersion::Unsupported()) {
541 advertised_versions.push_back(version);
542 }
543 }
544 alternative_service_info->set_advertised_versions(advertised_versions);
545 }
546
547 return true;
548 }
549
ParseAlternativeServiceInfo(const url::SchemeHostPort & server,const base::Value::Dict & server_pref_dict,HttpServerProperties::ServerInfo * server_info)550 bool HttpServerPropertiesManager::ParseAlternativeServiceInfo(
551 const url::SchemeHostPort& server,
552 const base::Value::Dict& server_pref_dict,
553 HttpServerProperties::ServerInfo* server_info) {
554 DCHECK(!server_info->alternative_services.has_value());
555 const base::Value::List* alternative_service_list =
556 server_pref_dict.FindList(kAlternativeServiceKey);
557 if (!alternative_service_list) {
558 return true;
559 }
560 if (server.scheme() != "https") {
561 return false;
562 }
563
564 AlternativeServiceInfoVector alternative_service_info_vector;
565 for (const auto& alternative_service_list_item : *alternative_service_list) {
566 if (!alternative_service_list_item.is_dict())
567 return false;
568 AlternativeServiceInfo alternative_service_info;
569 if (!ParseAlternativeServiceInfoDictOfServer(
570 alternative_service_list_item.GetDict(), server.Serialize(),
571 &alternative_service_info)) {
572 return false;
573 }
574 if (base::Time::Now() < alternative_service_info.expiration()) {
575 alternative_service_info_vector.push_back(alternative_service_info);
576 }
577 }
578
579 if (alternative_service_info_vector.empty()) {
580 return false;
581 }
582
583 server_info->alternative_services = alternative_service_info_vector;
584 return true;
585 }
586
ReadLastLocalAddressWhenQuicWorked(const base::Value::Dict & http_server_properties_dict,IPAddress * last_local_address_when_quic_worked)587 void HttpServerPropertiesManager::ReadLastLocalAddressWhenQuicWorked(
588 const base::Value::Dict& http_server_properties_dict,
589 IPAddress* last_local_address_when_quic_worked) {
590 const base::Value::Dict* supports_quic_dict =
591 http_server_properties_dict.FindDict(kSupportsQuicKey);
592 if (!supports_quic_dict) {
593 return;
594 }
595 const base::Value* used_quic = supports_quic_dict->Find(kUsedQuicKey);
596 if (!used_quic || !used_quic->is_bool()) {
597 DVLOG(1) << "Malformed SupportsQuic";
598 return;
599 }
600 if (!used_quic->GetBool())
601 return;
602
603 const std::string* address = supports_quic_dict->FindString(kAddressKey);
604 if (!address ||
605 !last_local_address_when_quic_worked->AssignFromIPLiteral(*address)) {
606 DVLOG(1) << "Malformed SupportsQuic";
607 }
608 }
609
ParseNetworkStats(const url::SchemeHostPort & server,const base::Value::Dict & server_pref_dict,HttpServerProperties::ServerInfo * server_info)610 void HttpServerPropertiesManager::ParseNetworkStats(
611 const url::SchemeHostPort& server,
612 const base::Value::Dict& server_pref_dict,
613 HttpServerProperties::ServerInfo* server_info) {
614 DCHECK(!server_info->server_network_stats.has_value());
615 const base::Value::Dict* server_network_stats_dict =
616 server_pref_dict.FindDict(kNetworkStatsKey);
617 if (!server_network_stats_dict) {
618 return;
619 }
620 absl::optional<int> maybe_srtt = server_network_stats_dict->FindInt(kSrttKey);
621 if (!maybe_srtt.has_value()) {
622 DVLOG(1) << "Malformed ServerNetworkStats for server: "
623 << server.Serialize();
624 return;
625 }
626 ServerNetworkStats server_network_stats;
627 server_network_stats.srtt = base::Microseconds(maybe_srtt.value());
628 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
629 // bandwidth_estimate.
630 server_info->server_network_stats = server_network_stats;
631 }
632
AddToQuicServerInfoMap(const base::Value::Dict & http_server_properties_dict,bool use_network_anonymization_key,HttpServerProperties::QuicServerInfoMap * quic_server_info_map)633 void HttpServerPropertiesManager::AddToQuicServerInfoMap(
634 const base::Value::Dict& http_server_properties_dict,
635 bool use_network_anonymization_key,
636 HttpServerProperties::QuicServerInfoMap* quic_server_info_map) {
637 const base::Value::List* quic_server_info_list =
638 http_server_properties_dict.FindList(kQuicServers);
639 if (!quic_server_info_list) {
640 DVLOG(1) << "Malformed http_server_properties for quic_servers.";
641 return;
642 }
643
644 for (const auto& quic_server_info_value : *quic_server_info_list) {
645 const base::Value::Dict* quic_server_info_dict =
646 quic_server_info_value.GetIfDict();
647 if (!quic_server_info_dict)
648 continue;
649
650 const std::string* quic_server_id_str =
651 quic_server_info_dict->FindString(kQuicServerIdKey);
652 if (!quic_server_id_str || quic_server_id_str->empty())
653 continue;
654
655 quic::QuicServerId quic_server_id =
656 QuicServerIdFromString(*quic_server_id_str);
657 if (quic_server_id.host().empty()) {
658 DVLOG(1) << "Malformed http_server_properties for quic server: "
659 << quic_server_id_str;
660 continue;
661 }
662
663 NetworkAnonymizationKey network_anonymization_key;
664 if (!GetNetworkIsolationKeyFromDict(*quic_server_info_dict,
665 use_network_anonymization_key,
666 &network_anonymization_key)) {
667 DVLOG(1) << "Malformed http_server_properties quic server dict: "
668 << *quic_server_id_str;
669 continue;
670 }
671
672 const std::string* quic_server_info =
673 quic_server_info_dict->FindString(kServerInfoKey);
674 if (!quic_server_info) {
675 DVLOG(1) << "Malformed http_server_properties quic server info: "
676 << *quic_server_id_str;
677 continue;
678 }
679 quic_server_info_map->Put(HttpServerProperties::QuicServerInfoMapKey(
680 quic_server_id, network_anonymization_key,
681 use_network_anonymization_key),
682 *quic_server_info);
683 }
684 }
685
WriteToPrefs(const HttpServerProperties::ServerInfoMap & server_info_map,const GetCannonicalSuffix & get_canonical_suffix,const IPAddress & last_local_address_when_quic_worked,const HttpServerProperties::QuicServerInfoMap & quic_server_info_map,const BrokenAlternativeServiceList & broken_alternative_service_list,const RecentlyBrokenAlternativeServices & recently_broken_alternative_services,base::OnceClosure callback)686 void HttpServerPropertiesManager::WriteToPrefs(
687 const HttpServerProperties::ServerInfoMap& server_info_map,
688 const GetCannonicalSuffix& get_canonical_suffix,
689 const IPAddress& last_local_address_when_quic_worked,
690 const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
691 const BrokenAlternativeServiceList& broken_alternative_service_list,
692 const RecentlyBrokenAlternativeServices&
693 recently_broken_alternative_services,
694 base::OnceClosure callback) {
695 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
696
697 // If loading prefs hasn't completed, don't call it, since this will overwrite
698 // existing prefs.
699 on_prefs_loaded_callback_.Reset();
700
701 std::set<std::pair<std::string, NetworkAnonymizationKey>>
702 persisted_canonical_suffix_set;
703 const base::Time now = base::Time::Now();
704 base::Value::Dict http_server_properties_dict;
705
706 // Convert |server_info_map| to a list Value and add it to
707 // |http_server_properties_dict|.
708 base::Value::List servers_list;
709 for (const auto& [key, server_info] : server_info_map) {
710 // If can't convert the NetworkAnonymizationKey to a value, don't save to
711 // disk. Generally happens because the key is for a unique origin.
712 base::Value network_anonymization_key_value;
713 if (!key.network_anonymization_key.ToValue(
714 &network_anonymization_key_value)) {
715 continue;
716 }
717
718 base::Value::Dict server_dict;
719
720 bool supports_spdy = server_info.supports_spdy.value_or(false);
721 if (supports_spdy)
722 server_dict.Set(kSupportsSpdyKey, supports_spdy);
723
724 AlternativeServiceInfoVector alternative_services =
725 GetAlternativeServiceToPersist(server_info.alternative_services, key,
726 now, get_canonical_suffix,
727 &persisted_canonical_suffix_set);
728 if (!alternative_services.empty())
729 SaveAlternativeServiceToServerPrefs(alternative_services, server_dict);
730
731 if (server_info.server_network_stats) {
732 SaveNetworkStatsToServerPrefs(*server_info.server_network_stats,
733 server_dict);
734 }
735
736 // Don't add empty entries. This can happen if, for example, all alternative
737 // services are empty, or |supports_spdy| is set to false, and all other
738 // fields are not set.
739 if (server_dict.empty())
740 continue;
741 server_dict.Set(kServerKey, key.server.Serialize());
742 server_dict.Set(kNetworkAnonymizationKey,
743 std::move(network_anonymization_key_value));
744 servers_list.Append(std::move(server_dict));
745 }
746 // Reverse `servers_list`. The least recently used item will be in the front.
747 std::reverse(servers_list.begin(), servers_list.end());
748
749 http_server_properties_dict.Set(kServersKey, std::move(servers_list));
750
751 http_server_properties_dict.Set(kVersionKey, kVersionNumber);
752
753 SaveLastLocalAddressWhenQuicWorkedToPrefs(last_local_address_when_quic_worked,
754 http_server_properties_dict);
755
756 SaveQuicServerInfoMapToServerPrefs(quic_server_info_map,
757 http_server_properties_dict);
758
759 SaveBrokenAlternativeServicesToPrefs(
760 broken_alternative_service_list, kMaxBrokenAlternativeServicesToPersist,
761 recently_broken_alternative_services, http_server_properties_dict);
762
763 net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_PREFS,
764 [&] { return http_server_properties_dict.Clone(); });
765
766 pref_delegate_->SetServerProperties(std::move(http_server_properties_dict),
767 std::move(callback));
768 }
769
SaveAlternativeServiceToServerPrefs(const AlternativeServiceInfoVector & alternative_service_info_vector,base::Value::Dict & server_pref_dict)770 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
771 const AlternativeServiceInfoVector& alternative_service_info_vector,
772 base::Value::Dict& server_pref_dict) {
773 if (alternative_service_info_vector.empty()) {
774 return;
775 }
776 base::Value::List alternative_service_list;
777 for (const AlternativeServiceInfo& alternative_service_info :
778 alternative_service_info_vector) {
779 const AlternativeService& alternative_service =
780 alternative_service_info.alternative_service();
781 DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
782 base::Value::Dict alternative_service_dict;
783 AddAlternativeServiceFieldsToDictionaryValue(alternative_service,
784 alternative_service_dict);
785 // JSON cannot store int64_t, so expiration is converted to a string.
786 alternative_service_dict.Set(
787 kExpirationKey,
788 base::NumberToString(
789 alternative_service_info.expiration().ToInternalValue()));
790 base::Value::List advertised_versions_list;
791 for (const auto& version : alternative_service_info.advertised_versions()) {
792 advertised_versions_list.Append(quic::AlpnForVersion(version));
793 }
794 alternative_service_dict.Set(kAdvertisedAlpnsKey,
795 std::move(advertised_versions_list));
796 alternative_service_list.Append(std::move(alternative_service_dict));
797 }
798 if (alternative_service_list.size() == 0)
799 return;
800 server_pref_dict.Set(kAlternativeServiceKey,
801 std::move(alternative_service_list));
802 }
803
SaveLastLocalAddressWhenQuicWorkedToPrefs(const IPAddress & last_local_address_when_quic_worked,base::Value::Dict & http_server_properties_dict)804 void HttpServerPropertiesManager::SaveLastLocalAddressWhenQuicWorkedToPrefs(
805 const IPAddress& last_local_address_when_quic_worked,
806 base::Value::Dict& http_server_properties_dict) {
807 if (!last_local_address_when_quic_worked.IsValid())
808 return;
809
810 base::Value::Dict supports_quic_dict;
811 supports_quic_dict.Set(kUsedQuicKey, true);
812 supports_quic_dict.Set(kAddressKey,
813 last_local_address_when_quic_worked.ToString());
814 http_server_properties_dict.Set(kSupportsQuicKey,
815 std::move(supports_quic_dict));
816 }
817
SaveNetworkStatsToServerPrefs(const ServerNetworkStats & server_network_stats,base::Value::Dict & server_pref_dict)818 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
819 const ServerNetworkStats& server_network_stats,
820 base::Value::Dict& server_pref_dict) {
821 base::Value::Dict server_network_stats_dict;
822 // Because JSON doesn't support int64_t, persist int64_t as a string.
823 server_network_stats_dict.Set(
824 kSrttKey, static_cast<int>(server_network_stats.srtt.InMicroseconds()));
825 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
826 // bandwidth_estimate.
827 server_pref_dict.Set(kNetworkStatsKey, std::move(server_network_stats_dict));
828 }
829
SaveQuicServerInfoMapToServerPrefs(const HttpServerProperties::QuicServerInfoMap & quic_server_info_map,base::Value::Dict & http_server_properties_dict)830 void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
831 const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
832 base::Value::Dict& http_server_properties_dict) {
833 if (quic_server_info_map.empty())
834 return;
835 base::Value::List quic_servers_list;
836 for (const auto& [key, server_info] : base::Reversed(quic_server_info_map)) {
837 base::Value network_anonymization_key_value;
838 // Don't save entries with ephemeral NIKs.
839 if (!key.network_anonymization_key.ToValue(
840 &network_anonymization_key_value)) {
841 continue;
842 }
843
844 base::Value::Dict quic_server_pref_dict;
845 quic_server_pref_dict.Set(kQuicServerIdKey,
846 QuicServerIdToString(key.server_id));
847 quic_server_pref_dict.Set(kNetworkAnonymizationKey,
848 std::move(network_anonymization_key_value));
849 quic_server_pref_dict.Set(kServerInfoKey, server_info);
850
851 quic_servers_list.Append(std::move(quic_server_pref_dict));
852 }
853 http_server_properties_dict.Set(kQuicServers, std::move(quic_servers_list));
854 }
855
SaveBrokenAlternativeServicesToPrefs(const BrokenAlternativeServiceList & broken_alternative_service_list,size_t max_broken_alternative_services,const RecentlyBrokenAlternativeServices & recently_broken_alternative_services,base::Value::Dict & http_server_properties_dict)856 void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
857 const BrokenAlternativeServiceList& broken_alternative_service_list,
858 size_t max_broken_alternative_services,
859 const RecentlyBrokenAlternativeServices&
860 recently_broken_alternative_services,
861 base::Value::Dict& http_server_properties_dict) {
862 if (broken_alternative_service_list.empty() &&
863 recently_broken_alternative_services.empty()) {
864 return;
865 }
866
867 // JSON list will be in LRU order (least-recently-used item is in the front)
868 // according to `recently_broken_alternative_services`.
869 base::Value::List json_list;
870
871 // Maps recently-broken alternative services to the index where it's stored
872 // in |json_list|.
873 std::map<BrokenAlternativeService, size_t> json_list_index_map;
874
875 if (!recently_broken_alternative_services.empty()) {
876 for (const auto& [broken_alt_service, broken_count] :
877 base::Reversed(recently_broken_alternative_services)) {
878 base::Value::Dict entry_dict;
879 if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
880 broken_alt_service, entry_dict)) {
881 continue;
882 }
883 entry_dict.Set(kBrokenCountKey, broken_count);
884 json_list_index_map[broken_alt_service] = json_list.size();
885 json_list.Append(std::move(entry_dict));
886 }
887 }
888
889 if (!broken_alternative_service_list.empty()) {
890 // Add expiration time info from |broken_alternative_service_list| to
891 // the JSON list.
892 size_t count = 0;
893 for (auto it = broken_alternative_service_list.begin();
894 it != broken_alternative_service_list.end() &&
895 count < max_broken_alternative_services;
896 ++it, ++count) {
897 const BrokenAlternativeService& broken_alt_service = it->first;
898 base::TimeTicks expiration_time_ticks = it->second;
899 // Convert expiration from TimeTicks to Time to time_t
900 time_t expiration_time_t =
901 (base::Time::Now() + (expiration_time_ticks - clock_->NowTicks()))
902 .ToTimeT();
903 int64_t expiration_int64 = static_cast<int64_t>(expiration_time_t);
904
905 auto index_map_it = json_list_index_map.find(broken_alt_service);
906 if (index_map_it != json_list_index_map.end()) {
907 size_t json_list_index = index_map_it->second;
908 base::Value& entry_dict = json_list[json_list_index];
909 DCHECK(entry_dict.is_dict());
910 DCHECK(!entry_dict.GetDict().Find(kBrokenUntilKey));
911 entry_dict.GetDict().Set(kBrokenUntilKey,
912 base::NumberToString(expiration_int64));
913 } else {
914 base::Value::Dict entry_dict;
915 if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
916 broken_alt_service, entry_dict)) {
917 continue;
918 }
919 entry_dict.Set(kBrokenUntilKey, base::NumberToString(expiration_int64));
920 json_list.Append(std::move(entry_dict));
921 }
922 }
923 }
924
925 // This can happen if all the entries are for NetworkAnonymizationKeys for
926 // opaque origins, which isn't exactly common, but can theoretically happen.
927 if (json_list.empty())
928 return;
929
930 http_server_properties_dict.Set(kBrokenAlternativeServicesKey,
931 std::move(json_list));
932 }
933
OnHttpServerPropertiesLoaded()934 void HttpServerPropertiesManager::OnHttpServerPropertiesLoaded() {
935 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
936
937 // If prefs have already been written, nothing to do.
938 if (!on_prefs_loaded_callback_)
939 return;
940
941 std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map;
942 IPAddress last_local_address_when_quic_worked;
943 std::unique_ptr<HttpServerProperties::QuicServerInfoMap> quic_server_info_map;
944 std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list;
945 std::unique_ptr<RecentlyBrokenAlternativeServices>
946 recently_broken_alternative_services;
947
948 ReadPrefs(&server_info_map, &last_local_address_when_quic_worked,
949 &quic_server_info_map, &broken_alternative_service_list,
950 &recently_broken_alternative_services);
951
952 std::move(on_prefs_loaded_callback_)
953 .Run(std::move(server_info_map), last_local_address_when_quic_worked,
954 std::move(quic_server_info_map),
955 std::move(broken_alternative_service_list),
956 std::move(recently_broken_alternative_services));
957 }
958
959 } // namespace net
960