• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // TODO(mmenke): Rename this once more information is stored in this map.
319   UMA_HISTOGRAM_COUNTS_1M("Net.HttpServerProperties.CountOfServers",
320                           (*server_info_map)->size());
321 
322   UMA_HISTOGRAM_COUNTS_1000("Net.CountOfQuicServerInfos",
323                             (*quic_server_info_map)->size());
324 
325   if (*recently_broken_alternative_services) {
326     DCHECK(*broken_alternative_service_list);
327 
328     UMA_HISTOGRAM_COUNTS_1000("Net.CountOfBrokenAlternativeServices",
329                               (*broken_alternative_service_list)->size());
330     UMA_HISTOGRAM_COUNTS_1000("Net.CountOfRecentlyBrokenAlternativeServices",
331                               (*recently_broken_alternative_services)->size());
332   }
333 }
334 
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)335 void HttpServerPropertiesManager::AddToBrokenAlternativeServices(
336     const base::Value::Dict& broken_alt_svc_entry_dict,
337     bool use_network_anonymization_key,
338     BrokenAlternativeServiceList* broken_alternative_service_list,
339     RecentlyBrokenAlternativeServices* recently_broken_alternative_services) {
340   AlternativeService alt_service;
341   if (!ParseAlternativeServiceDict(broken_alt_svc_entry_dict, false,
342                                    "broken alternative services",
343                                    &alt_service)) {
344     return;
345   }
346 
347   NetworkAnonymizationKey network_anonymization_key;
348   if (!GetNetworkIsolationKeyFromDict(broken_alt_svc_entry_dict,
349                                       use_network_anonymization_key,
350                                       &network_anonymization_key)) {
351     return;
352   }
353 
354   // Each entry must contain either broken-count and/or broken-until fields.
355   bool contains_broken_count_or_broken_until = false;
356 
357   // Read broken-count and add an entry for |alt_service| into
358   // |recently_broken_alternative_services|.
359   if (broken_alt_svc_entry_dict.Find(kBrokenCountKey)) {
360     absl::optional<int> broken_count =
361         broken_alt_svc_entry_dict.FindInt(kBrokenCountKey);
362     if (!broken_count.has_value()) {
363       DVLOG(1) << "Recently broken alternative service has malformed "
364                << "broken-count.";
365       return;
366     }
367     if (broken_count.value() < 0) {
368       DVLOG(1) << "Broken alternative service has negative broken-count.";
369       return;
370     }
371     recently_broken_alternative_services->Put(
372         BrokenAlternativeService(alt_service, network_anonymization_key,
373                                  use_network_anonymization_key),
374         broken_count.value());
375     contains_broken_count_or_broken_until = true;
376   }
377 
378   // Read broken-until and add an entry for |alt_service| in
379   // |broken_alternative_service_list|.
380   if (broken_alt_svc_entry_dict.Find(kBrokenUntilKey)) {
381     const std::string* expiration_string =
382         broken_alt_svc_entry_dict.FindString(kBrokenUntilKey);
383     int64_t expiration_int64;
384     if (!expiration_string ||
385         !base::StringToInt64(*expiration_string, &expiration_int64)) {
386       DVLOG(1) << "Broken alternative service has malformed broken-until "
387                << "string.";
388       return;
389     }
390 
391     time_t expiration_time_t = static_cast<time_t>(expiration_int64);
392     // Convert expiration from time_t to Time to TimeTicks
393     base::TimeTicks expiration_time_ticks =
394         clock_->NowTicks() +
395         (base::Time::FromTimeT(expiration_time_t) - base::Time::Now());
396     broken_alternative_service_list->push_back(std::make_pair(
397         BrokenAlternativeService(alt_service, network_anonymization_key,
398                                  use_network_anonymization_key),
399         expiration_time_ticks));
400     contains_broken_count_or_broken_until = true;
401   }
402 
403   if (!contains_broken_count_or_broken_until) {
404     DVLOG(1) << "Broken alternative service has neither broken-count nor "
405              << "broken-until specified.";
406   }
407 }
408 
AddServerData(const base::Value::Dict & server_dict,HttpServerProperties::ServerInfoMap * server_info_map,bool use_network_anonymization_key)409 void HttpServerPropertiesManager::AddServerData(
410     const base::Value::Dict& server_dict,
411     HttpServerProperties::ServerInfoMap* server_info_map,
412     bool use_network_anonymization_key) {
413   // Get server's scheme/host/pair.
414   const std::string* server_str = server_dict.FindString(kServerKey);
415   NetworkAnonymizationKey network_anonymization_key;
416   // Can't load entry if server name missing, or if the network isolation key is
417   // missing or invalid.
418   if (!server_str || !GetNetworkIsolationKeyFromDict(
419                          server_dict, use_network_anonymization_key,
420                          &network_anonymization_key)) {
421     return;
422   }
423 
424   url::SchemeHostPort spdy_server((GURL(*server_str)));
425   if (spdy_server.host().empty()) {
426     DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
427     return;
428   }
429 
430   HttpServerProperties::ServerInfo server_info;
431 
432   server_info.supports_spdy = server_dict.FindBool(kSupportsSpdyKey);
433 
434   if (ParseAlternativeServiceInfo(spdy_server, server_dict, &server_info))
435     ParseNetworkStats(spdy_server, server_dict, &server_info);
436 
437   if (!server_info.empty()) {
438     server_info_map->Put(HttpServerProperties::ServerInfoMapKey(
439                              std::move(spdy_server), network_anonymization_key,
440                              use_network_anonymization_key),
441                          std::move(server_info));
442   }
443 }
444 
ParseAlternativeServiceDict(const base::Value::Dict & dict,bool host_optional,const std::string & parsing_under,AlternativeService * alternative_service)445 bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
446     const base::Value::Dict& dict,
447     bool host_optional,
448     const std::string& parsing_under,
449     AlternativeService* alternative_service) {
450   // Protocol is mandatory.
451   const std::string* protocol_str = dict.FindString(kProtocolKey);
452   if (!protocol_str) {
453     DVLOG(1) << "Malformed alternative service protocol string under: "
454              << parsing_under;
455     return false;
456   }
457   NextProto protocol = NextProtoFromString(*protocol_str);
458   if (!IsAlternateProtocolValid(protocol)) {
459     DVLOG(1) << "Invalid alternative service protocol string \"" << protocol_str
460              << "\" under: " << parsing_under;
461     return false;
462   }
463   alternative_service->protocol = protocol;
464 
465   // If host is optional, it defaults to "".
466   std::string host = "";
467   const std::string* hostp = nullptr;
468   if (dict.Find(kHostKey)) {
469     hostp = dict.FindString(kHostKey);
470     if (!hostp) {
471       DVLOG(1) << "Malformed alternative service host string under: "
472                << parsing_under;
473       return false;
474     }
475     host = *hostp;
476   } else if (!host_optional) {
477     DVLOG(1) << "alternative service missing host string under: "
478              << parsing_under;
479     return false;
480   }
481   alternative_service->host = host;
482 
483   // Port is mandatory.
484   absl::optional<int> maybe_port = dict.FindInt(kPortKey);
485   if (!maybe_port.has_value() || !IsPortValid(maybe_port.value())) {
486     DVLOG(1) << "Malformed alternative service port under: " << parsing_under;
487     return false;
488   }
489   alternative_service->port = static_cast<uint32_t>(maybe_port.value());
490 
491   return true;
492 }
493 
ParseAlternativeServiceInfoDictOfServer(const base::Value::Dict & dict,const std::string & server_str,AlternativeServiceInfo * alternative_service_info)494 bool HttpServerPropertiesManager::ParseAlternativeServiceInfoDictOfServer(
495     const base::Value::Dict& dict,
496     const std::string& server_str,
497     AlternativeServiceInfo* alternative_service_info) {
498   AlternativeService alternative_service;
499   if (!ParseAlternativeServiceDict(dict, true, "server " + server_str,
500                                    &alternative_service)) {
501     return false;
502   }
503   alternative_service_info->set_alternative_service(alternative_service);
504 
505   // Expiration is optional, defaults to one day.
506   if (!dict.Find(kExpirationKey)) {
507     alternative_service_info->set_expiration(base::Time::Now() + base::Days(1));
508   } else {
509     const std::string* expiration_string = dict.FindString(kExpirationKey);
510     if (expiration_string) {
511       int64_t expiration_int64 = 0;
512       if (!base::StringToInt64(*expiration_string, &expiration_int64)) {
513         DVLOG(1) << "Malformed alternative service expiration for server: "
514                  << server_str;
515         return false;
516       }
517       alternative_service_info->set_expiration(
518           base::Time::FromInternalValue(expiration_int64));
519     } else {
520       DVLOG(1) << "Malformed alternative service expiration for server: "
521                << server_str;
522       return false;
523     }
524   }
525 
526   // Advertised versions list is optional.
527   if (dict.Find(kAdvertisedAlpnsKey)) {
528     const base::Value::List* versions_list = dict.FindList(kAdvertisedAlpnsKey);
529     if (!versions_list) {
530       DVLOG(1) << "Malformed alternative service advertised versions list for "
531                << "server: " << server_str;
532       return false;
533     }
534     quic::ParsedQuicVersionVector advertised_versions;
535     for (const auto& value : *versions_list) {
536       const std::string* version_string = value.GetIfString();
537       if (!version_string) {
538         DVLOG(1) << "Malformed alternative service version for server: "
539                  << server_str;
540         return false;
541       }
542       quic::ParsedQuicVersion version =
543           quic::ParseQuicVersionString(*version_string);
544       if (version != quic::ParsedQuicVersion::Unsupported()) {
545         advertised_versions.push_back(version);
546       }
547     }
548     alternative_service_info->set_advertised_versions(advertised_versions);
549   }
550 
551   return true;
552 }
553 
ParseAlternativeServiceInfo(const url::SchemeHostPort & server,const base::Value::Dict & server_pref_dict,HttpServerProperties::ServerInfo * server_info)554 bool HttpServerPropertiesManager::ParseAlternativeServiceInfo(
555     const url::SchemeHostPort& server,
556     const base::Value::Dict& server_pref_dict,
557     HttpServerProperties::ServerInfo* server_info) {
558   DCHECK(!server_info->alternative_services.has_value());
559   const base::Value::List* alternative_service_list =
560       server_pref_dict.FindList(kAlternativeServiceKey);
561   if (!alternative_service_list) {
562     return true;
563   }
564   if (server.scheme() != "https") {
565     return false;
566   }
567 
568   AlternativeServiceInfoVector alternative_service_info_vector;
569   for (const auto& alternative_service_list_item : *alternative_service_list) {
570     if (!alternative_service_list_item.is_dict())
571       return false;
572     AlternativeServiceInfo alternative_service_info;
573     if (!ParseAlternativeServiceInfoDictOfServer(
574             alternative_service_list_item.GetDict(), server.Serialize(),
575             &alternative_service_info)) {
576       return false;
577     }
578     if (base::Time::Now() < alternative_service_info.expiration()) {
579       alternative_service_info_vector.push_back(alternative_service_info);
580     }
581   }
582 
583   if (alternative_service_info_vector.empty()) {
584     return false;
585   }
586 
587   server_info->alternative_services = alternative_service_info_vector;
588   return true;
589 }
590 
ReadLastLocalAddressWhenQuicWorked(const base::Value::Dict & http_server_properties_dict,IPAddress * last_local_address_when_quic_worked)591 void HttpServerPropertiesManager::ReadLastLocalAddressWhenQuicWorked(
592     const base::Value::Dict& http_server_properties_dict,
593     IPAddress* last_local_address_when_quic_worked) {
594   const base::Value::Dict* supports_quic_dict =
595       http_server_properties_dict.FindDict(kSupportsQuicKey);
596   if (!supports_quic_dict) {
597     return;
598   }
599   const base::Value* used_quic = supports_quic_dict->Find(kUsedQuicKey);
600   if (!used_quic || !used_quic->is_bool()) {
601     DVLOG(1) << "Malformed SupportsQuic";
602     return;
603   }
604   if (!used_quic->GetBool())
605     return;
606 
607   const std::string* address = supports_quic_dict->FindString(kAddressKey);
608   if (!address ||
609       !last_local_address_when_quic_worked->AssignFromIPLiteral(*address)) {
610     DVLOG(1) << "Malformed SupportsQuic";
611   }
612 }
613 
ParseNetworkStats(const url::SchemeHostPort & server,const base::Value::Dict & server_pref_dict,HttpServerProperties::ServerInfo * server_info)614 void HttpServerPropertiesManager::ParseNetworkStats(
615     const url::SchemeHostPort& server,
616     const base::Value::Dict& server_pref_dict,
617     HttpServerProperties::ServerInfo* server_info) {
618   DCHECK(!server_info->server_network_stats.has_value());
619   const base::Value::Dict* server_network_stats_dict =
620       server_pref_dict.FindDict(kNetworkStatsKey);
621   if (!server_network_stats_dict) {
622     return;
623   }
624   absl::optional<int> maybe_srtt = server_network_stats_dict->FindInt(kSrttKey);
625   if (!maybe_srtt.has_value()) {
626     DVLOG(1) << "Malformed ServerNetworkStats for server: "
627              << server.Serialize();
628     return;
629   }
630   ServerNetworkStats server_network_stats;
631   server_network_stats.srtt = base::Microseconds(maybe_srtt.value());
632   // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
633   // bandwidth_estimate.
634   server_info->server_network_stats = server_network_stats;
635 }
636 
AddToQuicServerInfoMap(const base::Value::Dict & http_server_properties_dict,bool use_network_anonymization_key,HttpServerProperties::QuicServerInfoMap * quic_server_info_map)637 void HttpServerPropertiesManager::AddToQuicServerInfoMap(
638     const base::Value::Dict& http_server_properties_dict,
639     bool use_network_anonymization_key,
640     HttpServerProperties::QuicServerInfoMap* quic_server_info_map) {
641   const base::Value::List* quic_server_info_list =
642       http_server_properties_dict.FindList(kQuicServers);
643   if (!quic_server_info_list) {
644     DVLOG(1) << "Malformed http_server_properties for quic_servers.";
645     return;
646   }
647 
648   for (const auto& quic_server_info_value : *quic_server_info_list) {
649     const base::Value::Dict* quic_server_info_dict =
650         quic_server_info_value.GetIfDict();
651     if (!quic_server_info_dict)
652       continue;
653 
654     const std::string* quic_server_id_str =
655         quic_server_info_dict->FindString(kQuicServerIdKey);
656     if (!quic_server_id_str || quic_server_id_str->empty())
657       continue;
658 
659     quic::QuicServerId quic_server_id =
660         QuicServerIdFromString(*quic_server_id_str);
661     if (quic_server_id.host().empty()) {
662       DVLOG(1) << "Malformed http_server_properties for quic server: "
663                << quic_server_id_str;
664       continue;
665     }
666 
667     NetworkAnonymizationKey network_anonymization_key;
668     if (!GetNetworkIsolationKeyFromDict(*quic_server_info_dict,
669                                         use_network_anonymization_key,
670                                         &network_anonymization_key)) {
671       DVLOG(1) << "Malformed http_server_properties quic server dict: "
672                << *quic_server_id_str;
673       continue;
674     }
675 
676     const std::string* quic_server_info =
677         quic_server_info_dict->FindString(kServerInfoKey);
678     if (!quic_server_info) {
679       DVLOG(1) << "Malformed http_server_properties quic server info: "
680                << *quic_server_id_str;
681       continue;
682     }
683     quic_server_info_map->Put(HttpServerProperties::QuicServerInfoMapKey(
684                                   quic_server_id, network_anonymization_key,
685                                   use_network_anonymization_key),
686                               *quic_server_info);
687   }
688 }
689 
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)690 void HttpServerPropertiesManager::WriteToPrefs(
691     const HttpServerProperties::ServerInfoMap& server_info_map,
692     const GetCannonicalSuffix& get_canonical_suffix,
693     const IPAddress& last_local_address_when_quic_worked,
694     const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
695     const BrokenAlternativeServiceList& broken_alternative_service_list,
696     const RecentlyBrokenAlternativeServices&
697         recently_broken_alternative_services,
698     base::OnceClosure callback) {
699   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
700 
701   // If loading prefs hasn't completed, don't call it, since this will overwrite
702   // existing prefs.
703   on_prefs_loaded_callback_.Reset();
704 
705   std::set<std::pair<std::string, NetworkAnonymizationKey>>
706       persisted_canonical_suffix_set;
707   const base::Time now = base::Time::Now();
708   base::Value::Dict http_server_properties_dict;
709 
710   // Convert |server_info_map| to a list Value and add it to
711   // |http_server_properties_dict|.
712   base::Value::List servers_list;
713   for (const auto& [key, server_info] : server_info_map) {
714     // If can't convert the NetworkAnonymizationKey to a value, don't save to
715     // disk. Generally happens because the key is for a unique origin.
716     base::Value network_anonymization_key_value;
717     if (!key.network_anonymization_key.ToValue(
718             &network_anonymization_key_value)) {
719       continue;
720     }
721 
722     base::Value::Dict server_dict;
723 
724     bool supports_spdy = server_info.supports_spdy.value_or(false);
725     if (supports_spdy)
726       server_dict.Set(kSupportsSpdyKey, supports_spdy);
727 
728     AlternativeServiceInfoVector alternative_services =
729         GetAlternativeServiceToPersist(server_info.alternative_services, key,
730                                        now, get_canonical_suffix,
731                                        &persisted_canonical_suffix_set);
732     if (!alternative_services.empty())
733       SaveAlternativeServiceToServerPrefs(alternative_services, server_dict);
734 
735     if (server_info.server_network_stats) {
736       SaveNetworkStatsToServerPrefs(*server_info.server_network_stats,
737                                     server_dict);
738     }
739 
740     // Don't add empty entries. This can happen if, for example, all alternative
741     // services are empty, or |supports_spdy| is set to false, and all other
742     // fields are not set.
743     if (server_dict.empty())
744       continue;
745     server_dict.Set(kServerKey, key.server.Serialize());
746     server_dict.Set(kNetworkAnonymizationKey,
747                     std::move(network_anonymization_key_value));
748     servers_list.Append(std::move(server_dict));
749   }
750   // Reverse `servers_list`. The least recently used item will be in the front.
751   std::reverse(servers_list.begin(), servers_list.end());
752 
753   http_server_properties_dict.Set(kServersKey, std::move(servers_list));
754 
755   http_server_properties_dict.Set(kVersionKey, kVersionNumber);
756 
757   SaveLastLocalAddressWhenQuicWorkedToPrefs(last_local_address_when_quic_worked,
758                                             http_server_properties_dict);
759 
760   SaveQuicServerInfoMapToServerPrefs(quic_server_info_map,
761                                      http_server_properties_dict);
762 
763   SaveBrokenAlternativeServicesToPrefs(
764       broken_alternative_service_list, kMaxBrokenAlternativeServicesToPersist,
765       recently_broken_alternative_services, http_server_properties_dict);
766 
767   net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_PREFS,
768                     [&] { return std::move(http_server_properties_dict); });
769 
770   pref_delegate_->SetServerProperties(std::move(http_server_properties_dict),
771                                       std::move(callback));
772 }
773 
SaveAlternativeServiceToServerPrefs(const AlternativeServiceInfoVector & alternative_service_info_vector,base::Value::Dict & server_pref_dict)774 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
775     const AlternativeServiceInfoVector& alternative_service_info_vector,
776     base::Value::Dict& server_pref_dict) {
777   if (alternative_service_info_vector.empty()) {
778     return;
779   }
780   base::Value::List alternative_service_list;
781   for (const AlternativeServiceInfo& alternative_service_info :
782        alternative_service_info_vector) {
783     const AlternativeService& alternative_service =
784         alternative_service_info.alternative_service();
785     DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
786     base::Value::Dict alternative_service_dict;
787     AddAlternativeServiceFieldsToDictionaryValue(alternative_service,
788                                                  alternative_service_dict);
789     // JSON cannot store int64_t, so expiration is converted to a string.
790     alternative_service_dict.Set(
791         kExpirationKey,
792         base::NumberToString(
793             alternative_service_info.expiration().ToInternalValue()));
794     base::Value::List advertised_versions_list;
795     for (const auto& version : alternative_service_info.advertised_versions()) {
796       advertised_versions_list.Append(quic::AlpnForVersion(version));
797     }
798     alternative_service_dict.Set(kAdvertisedAlpnsKey,
799                                  std::move(advertised_versions_list));
800     alternative_service_list.Append(std::move(alternative_service_dict));
801   }
802   if (alternative_service_list.size() == 0)
803     return;
804   server_pref_dict.Set(kAlternativeServiceKey,
805                        std::move(alternative_service_list));
806 }
807 
SaveLastLocalAddressWhenQuicWorkedToPrefs(const IPAddress & last_local_address_when_quic_worked,base::Value::Dict & http_server_properties_dict)808 void HttpServerPropertiesManager::SaveLastLocalAddressWhenQuicWorkedToPrefs(
809     const IPAddress& last_local_address_when_quic_worked,
810     base::Value::Dict& http_server_properties_dict) {
811   if (!last_local_address_when_quic_worked.IsValid())
812     return;
813 
814   base::Value::Dict supports_quic_dict;
815   supports_quic_dict.Set(kUsedQuicKey, true);
816   supports_quic_dict.Set(kAddressKey,
817                          last_local_address_when_quic_worked.ToString());
818   http_server_properties_dict.Set(kSupportsQuicKey,
819                                   std::move(supports_quic_dict));
820 }
821 
SaveNetworkStatsToServerPrefs(const ServerNetworkStats & server_network_stats,base::Value::Dict & server_pref_dict)822 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
823     const ServerNetworkStats& server_network_stats,
824     base::Value::Dict& server_pref_dict) {
825   base::Value::Dict server_network_stats_dict;
826   // Because JSON doesn't support int64_t, persist int64_t as a string.
827   server_network_stats_dict.Set(
828       kSrttKey, static_cast<int>(server_network_stats.srtt.InMicroseconds()));
829   // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
830   // bandwidth_estimate.
831   server_pref_dict.Set(kNetworkStatsKey, std::move(server_network_stats_dict));
832 }
833 
SaveQuicServerInfoMapToServerPrefs(const HttpServerProperties::QuicServerInfoMap & quic_server_info_map,base::Value::Dict & http_server_properties_dict)834 void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs(
835     const HttpServerProperties::QuicServerInfoMap& quic_server_info_map,
836     base::Value::Dict& http_server_properties_dict) {
837   if (quic_server_info_map.empty())
838     return;
839   base::Value::List quic_servers_list;
840   for (const auto& [key, server_info] : base::Reversed(quic_server_info_map)) {
841     base::Value network_anonymization_key_value;
842     // Don't save entries with ephemeral NIKs.
843     if (!key.network_anonymization_key.ToValue(
844             &network_anonymization_key_value)) {
845       continue;
846     }
847 
848     base::Value::Dict quic_server_pref_dict;
849     quic_server_pref_dict.Set(kQuicServerIdKey,
850                               QuicServerIdToString(key.server_id));
851     quic_server_pref_dict.Set(kNetworkAnonymizationKey,
852                               std::move(network_anonymization_key_value));
853     quic_server_pref_dict.Set(kServerInfoKey, server_info);
854 
855     quic_servers_list.Append(std::move(quic_server_pref_dict));
856   }
857   http_server_properties_dict.Set(kQuicServers, std::move(quic_servers_list));
858 }
859 
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)860 void HttpServerPropertiesManager::SaveBrokenAlternativeServicesToPrefs(
861     const BrokenAlternativeServiceList& broken_alternative_service_list,
862     size_t max_broken_alternative_services,
863     const RecentlyBrokenAlternativeServices&
864         recently_broken_alternative_services,
865     base::Value::Dict& http_server_properties_dict) {
866   if (broken_alternative_service_list.empty() &&
867       recently_broken_alternative_services.empty()) {
868     return;
869   }
870 
871   // JSON list will be in LRU order (least-recently-used item is in the front)
872   // according to `recently_broken_alternative_services`.
873   base::Value::List json_list;
874 
875   // Maps recently-broken alternative services to the index where it's stored
876   // in |json_list|.
877   std::map<BrokenAlternativeService, size_t> json_list_index_map;
878 
879   if (!recently_broken_alternative_services.empty()) {
880     for (const auto& [broken_alt_service, broken_count] :
881          base::Reversed(recently_broken_alternative_services)) {
882       base::Value::Dict entry_dict;
883       if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
884               broken_alt_service, entry_dict)) {
885         continue;
886       }
887       entry_dict.Set(kBrokenCountKey, broken_count);
888       json_list_index_map[broken_alt_service] = json_list.size();
889       json_list.Append(std::move(entry_dict));
890     }
891   }
892 
893   if (!broken_alternative_service_list.empty()) {
894     // Add expiration time info from |broken_alternative_service_list| to
895     // the JSON list.
896     size_t count = 0;
897     for (auto it = broken_alternative_service_list.begin();
898          it != broken_alternative_service_list.end() &&
899          count < max_broken_alternative_services;
900          ++it, ++count) {
901       const BrokenAlternativeService& broken_alt_service = it->first;
902       base::TimeTicks expiration_time_ticks = it->second;
903       // Convert expiration from TimeTicks to Time to time_t
904       time_t expiration_time_t =
905           (base::Time::Now() + (expiration_time_ticks - clock_->NowTicks()))
906               .ToTimeT();
907       int64_t expiration_int64 = static_cast<int64_t>(expiration_time_t);
908 
909       auto index_map_it = json_list_index_map.find(broken_alt_service);
910       if (index_map_it != json_list_index_map.end()) {
911         size_t json_list_index = index_map_it->second;
912         base::Value& entry_dict = json_list[json_list_index];
913         DCHECK(entry_dict.is_dict());
914         DCHECK(!entry_dict.GetDict().Find(kBrokenUntilKey));
915         entry_dict.GetDict().Set(kBrokenUntilKey,
916                                  base::NumberToString(expiration_int64));
917       } else {
918         base::Value::Dict entry_dict;
919         if (!TryAddBrokenAlternativeServiceFieldsToDictionaryValue(
920                 broken_alt_service, entry_dict)) {
921           continue;
922         }
923         entry_dict.Set(kBrokenUntilKey, base::NumberToString(expiration_int64));
924         json_list.Append(std::move(entry_dict));
925       }
926     }
927   }
928 
929   // This can happen if all the entries are for NetworkAnonymizationKeys for
930   // opaque origins, which isn't exactly common, but can theoretically happen.
931   if (json_list.empty())
932     return;
933 
934   http_server_properties_dict.Set(kBrokenAlternativeServicesKey,
935                                   std::move(json_list));
936 }
937 
OnHttpServerPropertiesLoaded()938 void HttpServerPropertiesManager::OnHttpServerPropertiesLoaded() {
939   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
940 
941   // If prefs have already been written, nothing to do.
942   if (!on_prefs_loaded_callback_)
943     return;
944 
945   std::unique_ptr<HttpServerProperties::ServerInfoMap> server_info_map;
946   IPAddress last_local_address_when_quic_worked;
947   std::unique_ptr<HttpServerProperties::QuicServerInfoMap> quic_server_info_map;
948   std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list;
949   std::unique_ptr<RecentlyBrokenAlternativeServices>
950       recently_broken_alternative_services;
951 
952   ReadPrefs(&server_info_map, &last_local_address_when_quic_worked,
953             &quic_server_info_map, &broken_alternative_service_list,
954             &recently_broken_alternative_services);
955 
956   std::move(on_prefs_loaded_callback_)
957       .Run(std::move(server_info_map), last_local_address_when_quic_worked,
958            std::move(quic_server_info_map),
959            std::move(broken_alternative_service_list),
960            std::move(recently_broken_alternative_services));
961 }
962 
963 }  // namespace net
964