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