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