xref: /aosp_15_r20/external/cronet/net/http/http_server_properties.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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.h"
6 
7 #include "base/check_op.h"
8 #include "base/containers/adapters.h"
9 #include "base/containers/contains.h"
10 #include "base/feature_list.h"
11 #include "base/functional/bind.h"
12 #include "base/location.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "base/time/default_clock.h"
18 #include "base/time/default_tick_clock.h"
19 #include "base/values.h"
20 #include "net/base/features.h"
21 #include "net/base/network_anonymization_key.h"
22 #include "net/base/url_util.h"
23 #include "net/http/http_network_session.h"
24 #include "net/http/http_server_properties_manager.h"
25 #include "net/socket/ssl_client_socket.h"
26 #include "net/ssl/ssl_config.h"
27 
28 namespace net {
29 
30 namespace {
31 
32 // Time to wait before starting an update the preferences from the
33 // http_server_properties_impl_ cache. Scheduling another update during this
34 // period will be a no-op.
35 constexpr base::TimeDelta kUpdatePrefsDelay = base::Seconds(60);
36 
NormalizeSchemeHostPort(const url::SchemeHostPort & scheme_host_port)37 url::SchemeHostPort NormalizeSchemeHostPort(
38     const url::SchemeHostPort& scheme_host_port) {
39   if (scheme_host_port.scheme() == url::kWssScheme) {
40     return url::SchemeHostPort(url::kHttpsScheme, scheme_host_port.host(),
41                                scheme_host_port.port());
42   }
43   if (scheme_host_port.scheme() == url::kWsScheme) {
44     return url::SchemeHostPort(url::kHttpScheme, scheme_host_port.host(),
45                                scheme_host_port.port());
46   }
47   return scheme_host_port;
48 }
49 
50 }  // namespace
51 
52 HttpServerProperties::PrefDelegate::~PrefDelegate() = default;
53 
54 HttpServerProperties::ServerInfo::ServerInfo() = default;
55 HttpServerProperties::ServerInfo::ServerInfo(const ServerInfo& server_info) =
56     default;
57 HttpServerProperties::ServerInfo::ServerInfo(ServerInfo&& server_info) =
58     default;
59 HttpServerProperties::ServerInfo::~ServerInfo() = default;
60 
empty() const61 bool HttpServerProperties::ServerInfo::empty() const {
62   return !supports_spdy.has_value() && !alternative_services.has_value() &&
63          !server_network_stats.has_value();
64 }
65 
operator ==(const ServerInfo & other) const66 bool HttpServerProperties::ServerInfo::operator==(
67     const ServerInfo& other) const {
68   return supports_spdy == other.supports_spdy &&
69          alternative_services == other.alternative_services &&
70          server_network_stats == other.server_network_stats;
71 }
72 
ServerInfoMapKey(url::SchemeHostPort server,const NetworkAnonymizationKey & network_anonymization_key,bool use_network_anonymization_key)73 HttpServerProperties::ServerInfoMapKey::ServerInfoMapKey(
74     url::SchemeHostPort server,
75     const NetworkAnonymizationKey& network_anonymization_key,
76     bool use_network_anonymization_key)
77     : server(std::move(server)),
78       network_anonymization_key(use_network_anonymization_key
79                                     ? network_anonymization_key
80                                     : NetworkAnonymizationKey()) {
81   // Scheme should have been normalized before this method was called.
82   DCHECK_NE(this->server.scheme(), url::kWsScheme);
83   DCHECK_NE(this->server.scheme(), url::kWssScheme);
84 }
85 
86 HttpServerProperties::ServerInfoMapKey::~ServerInfoMapKey() = default;
87 
operator <(const ServerInfoMapKey & other) const88 bool HttpServerProperties::ServerInfoMapKey::operator<(
89     const ServerInfoMapKey& other) const {
90   return std::tie(server, network_anonymization_key) <
91          std::tie(other.server, other.network_anonymization_key);
92 }
93 
QuicServerInfoMapKey(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key,bool use_network_anonymization_key)94 HttpServerProperties::QuicServerInfoMapKey::QuicServerInfoMapKey(
95     const quic::QuicServerId& server_id,
96     const NetworkAnonymizationKey& network_anonymization_key,
97     bool use_network_anonymization_key)
98     : server_id(server_id),
99       network_anonymization_key(use_network_anonymization_key
100                                     ? network_anonymization_key
101                                     : NetworkAnonymizationKey()) {}
102 
103 HttpServerProperties::QuicServerInfoMapKey::~QuicServerInfoMapKey() = default;
104 
operator <(const QuicServerInfoMapKey & other) const105 bool HttpServerProperties::QuicServerInfoMapKey::operator<(
106     const QuicServerInfoMapKey& other) const {
107   return std::tie(server_id, network_anonymization_key) <
108          std::tie(other.server_id, other.network_anonymization_key);
109 }
110 
111 // Used in tests.
operator ==(const QuicServerInfoMapKey & other) const112 bool HttpServerProperties::QuicServerInfoMapKey::operator==(
113     const QuicServerInfoMapKey& other) const {
114   return std::tie(server_id, network_anonymization_key) ==
115          std::tie(other.server_id, other.network_anonymization_key);
116 }
117 
ServerInfoMap()118 HttpServerProperties::ServerInfoMap::ServerInfoMap()
119     : base::LRUCache<ServerInfoMapKey, ServerInfo>(kMaxServerInfoEntries) {}
120 
121 HttpServerProperties::ServerInfoMap::iterator
GetOrPut(const ServerInfoMapKey & key)122 HttpServerProperties::ServerInfoMap::GetOrPut(const ServerInfoMapKey& key) {
123   auto it = Get(key);
124   if (it != end())
125     return it;
126   return Put(key, ServerInfo());
127 }
128 
129 HttpServerProperties::ServerInfoMap::iterator
EraseIfEmpty(iterator server_info_it)130 HttpServerProperties::ServerInfoMap::EraseIfEmpty(iterator server_info_it) {
131   if (server_info_it->second.empty())
132     return Erase(server_info_it);
133   return ++server_info_it;
134 }
135 
HttpServerProperties(std::unique_ptr<PrefDelegate> pref_delegate,NetLog * net_log,const base::TickClock * tick_clock,base::Clock * clock)136 HttpServerProperties::HttpServerProperties(
137     std::unique_ptr<PrefDelegate> pref_delegate,
138     NetLog* net_log,
139     const base::TickClock* tick_clock,
140     base::Clock* clock)
141     : tick_clock_(tick_clock ? tick_clock
142                              : base::DefaultTickClock::GetInstance()),
143       clock_(clock ? clock : base::DefaultClock::GetInstance()),
144       use_network_anonymization_key_(
145           NetworkAnonymizationKey::IsPartitioningEnabled()),
146       is_initialized_(pref_delegate.get() == nullptr),
147       properties_manager_(
148           pref_delegate
149               ? std::make_unique<HttpServerPropertiesManager>(
150                     std::move(pref_delegate),
151                     base::BindOnce(&HttpServerProperties::OnPrefsLoaded,
152                                    base::Unretained(this)),
153                     kDefaultMaxQuicServerEntries,
154                     net_log,
155                     tick_clock_)
156               : nullptr),
157       broken_alternative_services_(kMaxRecentlyBrokenAlternativeServiceEntries,
158                                    this,
159                                    tick_clock_),
160       canonical_suffixes_({".ggpht.com", ".c.youtube.com", ".googlevideo.com",
161                            ".googleusercontent.com", ".gvt1.com"}),
162       quic_server_info_map_(kDefaultMaxQuicServerEntries),
163       max_server_configs_stored_in_properties_(kDefaultMaxQuicServerEntries) {}
164 
~HttpServerProperties()165 HttpServerProperties::~HttpServerProperties() {
166   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
167 
168   if (properties_manager_) {
169     // Stop waiting for initial settings.
170     is_initialized_ = true;
171 
172     // Stop the timer if it's running, since this will write to the properties
173     // file immediately.
174     prefs_update_timer_.Stop();
175 
176     WriteProperties(base::OnceClosure());
177   }
178 }
179 
Clear(base::OnceClosure callback)180 void HttpServerProperties::Clear(base::OnceClosure callback) {
181   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
182   server_info_map_.Clear();
183   broken_alternative_services_.Clear();
184   canonical_alt_svc_map_.clear();
185   last_local_address_when_quic_worked_ = IPAddress();
186   quic_server_info_map_.Clear();
187   canonical_server_info_map_.clear();
188 
189   if (properties_manager_) {
190     // Stop waiting for initial settings.
191     is_initialized_ = true;
192     // Leaving this as-is doesn't actually have any effect, if it's true, but
193     // seems best to be safe.
194     queue_write_on_load_ = false;
195 
196     // Stop the timer if it's running, since this will write to the properties
197     // file immediately.
198     prefs_update_timer_.Stop();
199     WriteProperties(std::move(callback));
200   } else if (callback) {
201     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
202         FROM_HERE, std::move(callback));
203   }
204 }
205 
SupportsRequestPriority(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key)206 bool HttpServerProperties::SupportsRequestPriority(
207     const url::SchemeHostPort& server,
208     const net::NetworkAnonymizationKey& network_anonymization_key) {
209   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
210   if (server.host().empty())
211     return false;
212 
213   if (GetSupportsSpdy(server, network_anonymization_key))
214     return true;
215   const AlternativeServiceInfoVector alternative_service_info_vector =
216       GetAlternativeServiceInfos(server, network_anonymization_key);
217   for (const AlternativeServiceInfo& alternative_service_info :
218        alternative_service_info_vector) {
219     if (alternative_service_info.alternative_service().protocol == kProtoQUIC) {
220       return true;
221     }
222   }
223   return false;
224 }
225 
GetSupportsSpdy(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key)226 bool HttpServerProperties::GetSupportsSpdy(
227     const url::SchemeHostPort& server,
228     const net::NetworkAnonymizationKey& network_anonymization_key) {
229   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
230   return GetSupportsSpdyInternal(NormalizeSchemeHostPort(server),
231                                  network_anonymization_key);
232 }
233 
SetSupportsSpdy(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key,bool supports_spdy)234 void HttpServerProperties::SetSupportsSpdy(
235     const url::SchemeHostPort& server,
236     const net::NetworkAnonymizationKey& network_anonymization_key,
237     bool supports_spdy) {
238   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
239   SetSupportsSpdyInternal(NormalizeSchemeHostPort(server),
240                           network_anonymization_key, supports_spdy);
241 }
242 
RequiresHTTP11(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key)243 bool HttpServerProperties::RequiresHTTP11(
244     const url::SchemeHostPort& server,
245     const net::NetworkAnonymizationKey& network_anonymization_key) {
246   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
247   return RequiresHTTP11Internal(NormalizeSchemeHostPort(server),
248                                 network_anonymization_key);
249 }
250 
SetHTTP11Required(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key)251 void HttpServerProperties::SetHTTP11Required(
252     const url::SchemeHostPort& server,
253     const net::NetworkAnonymizationKey& network_anonymization_key) {
254   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
255   SetHTTP11RequiredInternal(NormalizeSchemeHostPort(server),
256                             network_anonymization_key);
257 }
258 
MaybeForceHTTP11(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key,SSLConfig * ssl_config)259 void HttpServerProperties::MaybeForceHTTP11(
260     const url::SchemeHostPort& server,
261     const net::NetworkAnonymizationKey& network_anonymization_key,
262     SSLConfig* ssl_config) {
263   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
264   MaybeForceHTTP11Internal(NormalizeSchemeHostPort(server),
265                            network_anonymization_key, ssl_config);
266 }
267 
GetAlternativeServiceInfos(const url::SchemeHostPort & origin,const net::NetworkAnonymizationKey & network_anonymization_key)268 AlternativeServiceInfoVector HttpServerProperties::GetAlternativeServiceInfos(
269     const url::SchemeHostPort& origin,
270     const net::NetworkAnonymizationKey& network_anonymization_key) {
271   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
272   return GetAlternativeServiceInfosInternal(NormalizeSchemeHostPort(origin),
273                                             network_anonymization_key);
274 }
275 
SetHttp2AlternativeService(const url::SchemeHostPort & origin,const NetworkAnonymizationKey & network_anonymization_key,const AlternativeService & alternative_service,base::Time expiration)276 void HttpServerProperties::SetHttp2AlternativeService(
277     const url::SchemeHostPort& origin,
278     const NetworkAnonymizationKey& network_anonymization_key,
279     const AlternativeService& alternative_service,
280     base::Time expiration) {
281   DCHECK_EQ(alternative_service.protocol, kProtoHTTP2);
282 
283   SetAlternativeServices(
284       origin, network_anonymization_key,
285       AlternativeServiceInfoVector(
286           /*size=*/1, AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
287                           alternative_service, expiration)));
288 }
289 
SetQuicAlternativeService(const url::SchemeHostPort & origin,const NetworkAnonymizationKey & network_anonymization_key,const AlternativeService & alternative_service,base::Time expiration,const quic::ParsedQuicVersionVector & advertised_versions)290 void HttpServerProperties::SetQuicAlternativeService(
291     const url::SchemeHostPort& origin,
292     const NetworkAnonymizationKey& network_anonymization_key,
293     const AlternativeService& alternative_service,
294     base::Time expiration,
295     const quic::ParsedQuicVersionVector& advertised_versions) {
296   DCHECK(alternative_service.protocol == kProtoQUIC);
297 
298   SetAlternativeServices(
299       origin, network_anonymization_key,
300       AlternativeServiceInfoVector(
301           /*size=*/1,
302           AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
303               alternative_service, expiration, advertised_versions)));
304 }
305 
SetAlternativeServices(const url::SchemeHostPort & origin,const net::NetworkAnonymizationKey & network_anonymization_key,const AlternativeServiceInfoVector & alternative_service_info_vector)306 void HttpServerProperties::SetAlternativeServices(
307     const url::SchemeHostPort& origin,
308     const net::NetworkAnonymizationKey& network_anonymization_key,
309     const AlternativeServiceInfoVector& alternative_service_info_vector) {
310   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
311   SetAlternativeServicesInternal(NormalizeSchemeHostPort(origin),
312                                  network_anonymization_key,
313                                  alternative_service_info_vector);
314 }
315 
MarkAlternativeServiceBroken(const AlternativeService & alternative_service,const net::NetworkAnonymizationKey & network_anonymization_key)316 void HttpServerProperties::MarkAlternativeServiceBroken(
317     const AlternativeService& alternative_service,
318     const net::NetworkAnonymizationKey& network_anonymization_key) {
319   broken_alternative_services_.MarkBroken(
320       BrokenAlternativeService(alternative_service, network_anonymization_key,
321                                use_network_anonymization_key_));
322   MaybeQueueWriteProperties();
323 }
324 
325 void HttpServerProperties::
MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(const AlternativeService & alternative_service,const net::NetworkAnonymizationKey & network_anonymization_key)326     MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(
327         const AlternativeService& alternative_service,
328         const net::NetworkAnonymizationKey& network_anonymization_key) {
329   broken_alternative_services_.MarkBrokenUntilDefaultNetworkChanges(
330       BrokenAlternativeService(alternative_service, network_anonymization_key,
331                                use_network_anonymization_key_));
332   MaybeQueueWriteProperties();
333 }
334 
MarkAlternativeServiceRecentlyBroken(const AlternativeService & alternative_service,const net::NetworkAnonymizationKey & network_anonymization_key)335 void HttpServerProperties::MarkAlternativeServiceRecentlyBroken(
336     const AlternativeService& alternative_service,
337     const net::NetworkAnonymizationKey& network_anonymization_key) {
338   broken_alternative_services_.MarkRecentlyBroken(
339       BrokenAlternativeService(alternative_service, network_anonymization_key,
340                                use_network_anonymization_key_));
341   MaybeQueueWriteProperties();
342 }
343 
IsAlternativeServiceBroken(const AlternativeService & alternative_service,const net::NetworkAnonymizationKey & network_anonymization_key) const344 bool HttpServerProperties::IsAlternativeServiceBroken(
345     const AlternativeService& alternative_service,
346     const net::NetworkAnonymizationKey& network_anonymization_key) const {
347   return broken_alternative_services_.IsBroken(
348       BrokenAlternativeService(alternative_service, network_anonymization_key,
349                                use_network_anonymization_key_));
350 }
351 
WasAlternativeServiceRecentlyBroken(const AlternativeService & alternative_service,const net::NetworkAnonymizationKey & network_anonymization_key)352 bool HttpServerProperties::WasAlternativeServiceRecentlyBroken(
353     const AlternativeService& alternative_service,
354     const net::NetworkAnonymizationKey& network_anonymization_key) {
355   return broken_alternative_services_.WasRecentlyBroken(
356       BrokenAlternativeService(alternative_service, network_anonymization_key,
357                                use_network_anonymization_key_));
358 }
359 
ConfirmAlternativeService(const AlternativeService & alternative_service,const net::NetworkAnonymizationKey & network_anonymization_key)360 void HttpServerProperties::ConfirmAlternativeService(
361     const AlternativeService& alternative_service,
362     const net::NetworkAnonymizationKey& network_anonymization_key) {
363   bool old_value = IsAlternativeServiceBroken(alternative_service,
364                                               network_anonymization_key);
365   broken_alternative_services_.Confirm(
366       BrokenAlternativeService(alternative_service, network_anonymization_key,
367                                use_network_anonymization_key_));
368   bool new_value = IsAlternativeServiceBroken(alternative_service,
369                                               network_anonymization_key);
370 
371   // For persisting, we only care about the value returned by
372   // IsAlternativeServiceBroken. If that value changes, then call persist.
373   if (old_value != new_value)
374     MaybeQueueWriteProperties();
375 }
376 
OnDefaultNetworkChanged()377 void HttpServerProperties::OnDefaultNetworkChanged() {
378   bool changed = broken_alternative_services_.OnDefaultNetworkChanged();
379   if (changed)
380     MaybeQueueWriteProperties();
381 }
382 
GetAlternativeServiceInfoAsValue() const383 base::Value HttpServerProperties::GetAlternativeServiceInfoAsValue() const {
384   const base::Time now = clock_->Now();
385   const base::TimeTicks now_ticks = tick_clock_->NowTicks();
386   base::Value::List dict_list;
387   for (const auto& server_info : server_info_map_) {
388     if (!server_info.second.alternative_services.has_value())
389       continue;
390     base::Value::List alternative_service_list;
391     const ServerInfoMapKey& key = server_info.first;
392     for (const AlternativeServiceInfo& alternative_service_info :
393          server_info.second.alternative_services.value()) {
394       std::string alternative_service_string(
395           alternative_service_info.ToString());
396       AlternativeService alternative_service(
397           alternative_service_info.alternative_service());
398       if (alternative_service.host.empty()) {
399         alternative_service.host = key.server.host();
400       }
401       base::TimeTicks brokenness_expiration_ticks;
402       if (broken_alternative_services_.IsBroken(
403               BrokenAlternativeService(
404                   alternative_service,
405                   server_info.first.network_anonymization_key,
406                   use_network_anonymization_key_),
407               &brokenness_expiration_ticks)) {
408         // Convert |brokenness_expiration| from TimeTicks to Time.
409         //
410         // Note: Cannot use `base::UnlocalizedTimeFormatWithPattern()` since
411         // `net/DEPS` disallows `base/i18n`.
412         base::Time brokenness_expiration =
413             now + (brokenness_expiration_ticks - now_ticks);
414         base::Time::Exploded exploded;
415         brokenness_expiration.LocalExplode(&exploded);
416         std::string broken_info_string =
417             " (broken until " +
418             base::StringPrintf("%04d-%02d-%02d %0d:%0d:%0d", exploded.year,
419                                exploded.month, exploded.day_of_month,
420                                exploded.hour, exploded.minute,
421                                exploded.second) +
422             ")";
423         alternative_service_string.append(broken_info_string);
424       }
425       alternative_service_list.Append(std::move(alternative_service_string));
426     }
427     if (alternative_service_list.empty())
428       continue;
429     base::Value::Dict dict;
430     dict.Set("server", key.server.Serialize());
431     dict.Set("network_anonymization_key",
432              key.network_anonymization_key.ToDebugString());
433     dict.Set("alternative_service", std::move(alternative_service_list));
434     dict_list.Append(std::move(dict));
435   }
436   return base::Value(std::move(dict_list));
437 }
438 
WasLastLocalAddressWhenQuicWorked(const IPAddress & local_address) const439 bool HttpServerProperties::WasLastLocalAddressWhenQuicWorked(
440     const IPAddress& local_address) const {
441   return !last_local_address_when_quic_worked_.empty() &&
442          last_local_address_when_quic_worked_ == local_address;
443 }
444 
HasLastLocalAddressWhenQuicWorked() const445 bool HttpServerProperties::HasLastLocalAddressWhenQuicWorked() const {
446   return !last_local_address_when_quic_worked_.empty();
447 }
448 
SetLastLocalAddressWhenQuicWorked(IPAddress last_local_address_when_quic_worked)449 void HttpServerProperties::SetLastLocalAddressWhenQuicWorked(
450     IPAddress last_local_address_when_quic_worked) {
451   DCHECK(!last_local_address_when_quic_worked.empty());
452   if (last_local_address_when_quic_worked_ ==
453       last_local_address_when_quic_worked) {
454     return;
455   }
456 
457   last_local_address_when_quic_worked_ = last_local_address_when_quic_worked;
458   MaybeQueueWriteProperties();
459 }
460 
ClearLastLocalAddressWhenQuicWorked()461 void HttpServerProperties::ClearLastLocalAddressWhenQuicWorked() {
462   if (last_local_address_when_quic_worked_.empty())
463     return;
464 
465   last_local_address_when_quic_worked_ = IPAddress();
466   MaybeQueueWriteProperties();
467 }
468 
SetServerNetworkStats(const url::SchemeHostPort & server,const NetworkAnonymizationKey & network_anonymization_key,ServerNetworkStats stats)469 void HttpServerProperties::SetServerNetworkStats(
470     const url::SchemeHostPort& server,
471     const NetworkAnonymizationKey& network_anonymization_key,
472     ServerNetworkStats stats) {
473   SetServerNetworkStatsInternal(NormalizeSchemeHostPort(server),
474                                 network_anonymization_key, std::move(stats));
475 }
476 
ClearServerNetworkStats(const url::SchemeHostPort & server,const NetworkAnonymizationKey & network_anonymization_key)477 void HttpServerProperties::ClearServerNetworkStats(
478     const url::SchemeHostPort& server,
479     const NetworkAnonymizationKey& network_anonymization_key) {
480   ClearServerNetworkStatsInternal(NormalizeSchemeHostPort(server),
481                                   network_anonymization_key);
482 }
483 
GetServerNetworkStats(const url::SchemeHostPort & server,const NetworkAnonymizationKey & network_anonymization_key)484 const ServerNetworkStats* HttpServerProperties::GetServerNetworkStats(
485     const url::SchemeHostPort& server,
486     const NetworkAnonymizationKey& network_anonymization_key) {
487   return GetServerNetworkStatsInternal(NormalizeSchemeHostPort(server),
488                                        network_anonymization_key);
489 }
490 
SetQuicServerInfo(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key,const std::string & server_info)491 void HttpServerProperties::SetQuicServerInfo(
492     const quic::QuicServerId& server_id,
493     const NetworkAnonymizationKey& network_anonymization_key,
494     const std::string& server_info) {
495   QuicServerInfoMapKey key =
496       CreateQuicServerInfoKey(server_id, network_anonymization_key);
497   auto it = quic_server_info_map_.Peek(key);
498   bool changed =
499       (it == quic_server_info_map_.end() || it->second != server_info);
500   quic_server_info_map_.Put(key, server_info);
501   UpdateCanonicalServerInfoMap(key);
502   if (changed)
503     MaybeQueueWriteProperties();
504 }
505 
GetQuicServerInfo(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key)506 const std::string* HttpServerProperties::GetQuicServerInfo(
507     const quic::QuicServerId& server_id,
508     const NetworkAnonymizationKey& network_anonymization_key) {
509   QuicServerInfoMapKey key =
510       CreateQuicServerInfoKey(server_id, network_anonymization_key);
511   auto it = quic_server_info_map_.Get(key);
512   if (it != quic_server_info_map_.end()) {
513     // Since |canonical_server_info_map_| should always map to the most
514     // recent host, update it with the one that became MRU in
515     // |quic_server_info_map_|.
516     UpdateCanonicalServerInfoMap(key);
517     return &it->second;
518   }
519 
520   // If the exact match for |server_id| wasn't found, check
521   // |canonical_server_info_map_| whether there is server info for a host with
522   // the same canonical host suffix.
523   auto canonical_itr = GetCanonicalServerInfoHost(key);
524   if (canonical_itr == canonical_server_info_map_.end())
525     return nullptr;
526 
527   // When search in |quic_server_info_map_|, do not change the MRU order.
528   it = quic_server_info_map_.Peek(CreateQuicServerInfoKey(
529       canonical_itr->second, network_anonymization_key));
530   if (it != quic_server_info_map_.end())
531     return &it->second;
532 
533   return nullptr;
534 }
535 
536 const HttpServerProperties::QuicServerInfoMap&
quic_server_info_map() const537 HttpServerProperties::quic_server_info_map() const {
538   return quic_server_info_map_;
539 }
540 
max_server_configs_stored_in_properties() const541 size_t HttpServerProperties::max_server_configs_stored_in_properties() const {
542   return max_server_configs_stored_in_properties_;
543 }
544 
SetMaxServerConfigsStoredInProperties(size_t max_server_configs_stored_in_properties)545 void HttpServerProperties::SetMaxServerConfigsStoredInProperties(
546     size_t max_server_configs_stored_in_properties) {
547   // Do nothing if the new size is the same as the old one.
548   if (max_server_configs_stored_in_properties_ ==
549       max_server_configs_stored_in_properties) {
550     return;
551   }
552 
553   max_server_configs_stored_in_properties_ =
554       max_server_configs_stored_in_properties;
555 
556   // LRUCache doesn't allow the capacity of the cache to be changed. Thus create
557   // a new map with the new size and add current elements and swap the new map.
558   quic_server_info_map_.ShrinkToSize(max_server_configs_stored_in_properties_);
559   QuicServerInfoMap temp_map(max_server_configs_stored_in_properties_);
560   // Update the |canonical_server_info_map_| as well, so it stays in sync with
561   // |quic_server_info_map_|.
562   canonical_server_info_map_ = QuicCanonicalMap();
563   for (const auto& [key, server_info] : base::Reversed(quic_server_info_map_)) {
564     temp_map.Put(key, server_info);
565     UpdateCanonicalServerInfoMap(key);
566   }
567 
568   quic_server_info_map_.Swap(temp_map);
569   if (properties_manager_) {
570     properties_manager_->set_max_server_configs_stored_in_properties(
571         max_server_configs_stored_in_properties);
572   }
573 }
574 
SetBrokenAlternativeServicesDelayParams(std::optional<base::TimeDelta> initial_delay,std::optional<bool> exponential_backoff_on_initial_delay)575 void HttpServerProperties::SetBrokenAlternativeServicesDelayParams(
576     std::optional<base::TimeDelta> initial_delay,
577     std::optional<bool> exponential_backoff_on_initial_delay) {
578   broken_alternative_services_.SetDelayParams(
579       initial_delay, exponential_backoff_on_initial_delay);
580 }
581 
IsInitialized() const582 bool HttpServerProperties::IsInitialized() const {
583   return is_initialized_;
584 }
585 
OnExpireBrokenAlternativeService(const AlternativeService & expired_alternative_service,const NetworkAnonymizationKey & network_anonymization_key)586 void HttpServerProperties::OnExpireBrokenAlternativeService(
587     const AlternativeService& expired_alternative_service,
588     const NetworkAnonymizationKey& network_anonymization_key) {
589   // Remove every occurrence of |expired_alternative_service| from
590   // |alternative_service_map_|.
591   for (auto map_it = server_info_map_.begin();
592        map_it != server_info_map_.end();) {
593     if (!map_it->second.alternative_services.has_value() ||
594         map_it->first.network_anonymization_key != network_anonymization_key) {
595       ++map_it;
596       continue;
597     }
598     AlternativeServiceInfoVector* service_info =
599         &map_it->second.alternative_services.value();
600     for (auto it = service_info->begin(); it != service_info->end();) {
601       AlternativeService alternative_service(it->alternative_service());
602       // Empty hostname in map means hostname of key: substitute before
603       // comparing to |expired_alternative_service|.
604       if (alternative_service.host.empty()) {
605         alternative_service.host = map_it->first.server.host();
606       }
607       if (alternative_service == expired_alternative_service) {
608         it = service_info->erase(it);
609         continue;
610       }
611       ++it;
612     }
613     // If an origin has an empty list of alternative services, then remove it
614     // from both |canonical_alt_svc_map_| and
615     // |alternative_service_map_|.
616     if (service_info->empty()) {
617       RemoveAltSvcCanonicalHost(map_it->first.server,
618                                 network_anonymization_key);
619       map_it->second.alternative_services.reset();
620       map_it = server_info_map_.EraseIfEmpty(map_it);
621       continue;
622     }
623     ++map_it;
624   }
625 }
626 
GetUpdatePrefsDelayForTesting()627 base::TimeDelta HttpServerProperties::GetUpdatePrefsDelayForTesting() {
628   return kUpdatePrefsDelay;
629 }
630 
GetSupportsSpdyInternal(url::SchemeHostPort server,const net::NetworkAnonymizationKey & network_anonymization_key)631 bool HttpServerProperties::GetSupportsSpdyInternal(
632     url::SchemeHostPort server,
633     const net::NetworkAnonymizationKey& network_anonymization_key) {
634   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
635   DCHECK_NE(server.scheme(), url::kWsScheme);
636   DCHECK_NE(server.scheme(), url::kWssScheme);
637   if (server.host().empty())
638     return false;
639 
640   auto server_info = server_info_map_.Get(
641       CreateServerInfoKey(std::move(server), network_anonymization_key));
642   return server_info != server_info_map_.end() &&
643          server_info->second.supports_spdy.value_or(false);
644 }
645 
SetSupportsSpdyInternal(url::SchemeHostPort server,const net::NetworkAnonymizationKey & network_anonymization_key,bool supports_spdy)646 void HttpServerProperties::SetSupportsSpdyInternal(
647     url::SchemeHostPort server,
648     const net::NetworkAnonymizationKey& network_anonymization_key,
649     bool supports_spdy) {
650   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
651   DCHECK_NE(server.scheme(), url::kWsScheme);
652   DCHECK_NE(server.scheme(), url::kWssScheme);
653   if (server.host().empty())
654     return;
655 
656   auto server_info = server_info_map_.GetOrPut(
657       CreateServerInfoKey(std::move(server), network_anonymization_key));
658   // If value is already the same as |supports_spdy|, or value is unset and
659   // |supports_spdy| is false, don't queue a write.
660   bool queue_write =
661       server_info->second.supports_spdy.value_or(false) != supports_spdy;
662   server_info->second.supports_spdy = supports_spdy;
663 
664   if (queue_write)
665     MaybeQueueWriteProperties();
666 }
667 
RequiresHTTP11Internal(url::SchemeHostPort server,const net::NetworkAnonymizationKey & network_anonymization_key)668 bool HttpServerProperties::RequiresHTTP11Internal(
669     url::SchemeHostPort server,
670     const net::NetworkAnonymizationKey& network_anonymization_key) {
671   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
672   DCHECK_NE(server.scheme(), url::kWsScheme);
673   DCHECK_NE(server.scheme(), url::kWssScheme);
674   if (server.host().empty())
675     return false;
676 
677   auto spdy_info = server_info_map_.Get(
678       CreateServerInfoKey(std::move(server), network_anonymization_key));
679   return spdy_info != server_info_map_.end() &&
680          spdy_info->second.requires_http11.value_or(false);
681 }
682 
SetHTTP11RequiredInternal(url::SchemeHostPort server,const net::NetworkAnonymizationKey & network_anonymization_key)683 void HttpServerProperties::SetHTTP11RequiredInternal(
684     url::SchemeHostPort server,
685     const net::NetworkAnonymizationKey& network_anonymization_key) {
686   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
687   DCHECK_NE(server.scheme(), url::kWsScheme);
688   DCHECK_NE(server.scheme(), url::kWssScheme);
689   if (server.host().empty())
690     return;
691 
692   server_info_map_
693       .GetOrPut(
694           CreateServerInfoKey(std::move(server), network_anonymization_key))
695       ->second.requires_http11 = true;
696   // No need to call MaybeQueueWriteProperties(), as this information is not
697   // persisted to preferences.
698 }
699 
MaybeForceHTTP11Internal(url::SchemeHostPort server,const net::NetworkAnonymizationKey & network_anonymization_key,SSLConfig * ssl_config)700 void HttpServerProperties::MaybeForceHTTP11Internal(
701     url::SchemeHostPort server,
702     const net::NetworkAnonymizationKey& network_anonymization_key,
703     SSLConfig* ssl_config) {
704   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
705   DCHECK_NE(server.scheme(), url::kWsScheme);
706   DCHECK_NE(server.scheme(), url::kWssScheme);
707   if (RequiresHTTP11(std::move(server), network_anonymization_key)) {
708     ssl_config->alpn_protos.clear();
709     ssl_config->alpn_protos.push_back(kProtoHTTP11);
710   }
711 }
712 
713 AlternativeServiceInfoVector
GetAlternativeServiceInfosInternal(const url::SchemeHostPort & origin,const net::NetworkAnonymizationKey & network_anonymization_key)714 HttpServerProperties::GetAlternativeServiceInfosInternal(
715     const url::SchemeHostPort& origin,
716     const net::NetworkAnonymizationKey& network_anonymization_key) {
717   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
718   DCHECK_NE(origin.scheme(), url::kWsScheme);
719   DCHECK_NE(origin.scheme(), url::kWssScheme);
720 
721   // Copy valid alternative service infos into
722   // |valid_alternative_service_infos|.
723   AlternativeServiceInfoVector valid_alternative_service_infos;
724   const base::Time now = clock_->Now();
725   auto map_it = server_info_map_.Get(
726       CreateServerInfoKey(origin, network_anonymization_key));
727   if (map_it != server_info_map_.end() &&
728       map_it->second.alternative_services.has_value()) {
729     AlternativeServiceInfoVector* service_info =
730         &map_it->second.alternative_services.value();
731     HostPortPair host_port_pair(origin.host(), origin.port());
732     for (auto it = service_info->begin(); it != service_info->end();) {
733       if (it->expiration() < now) {
734         it = service_info->erase(it);
735         continue;
736       }
737       AlternativeService alternative_service(it->alternative_service());
738       if (alternative_service.host.empty()) {
739         alternative_service.host = origin.host();
740       }
741       // If the alternative service is equivalent to the origin (same host, same
742       // port, and both TCP), skip it.
743       if (host_port_pair.Equals(alternative_service.host_port_pair()) &&
744           alternative_service.protocol == kProtoHTTP2) {
745         ++it;
746         continue;
747       }
748       if (alternative_service.protocol == kProtoQUIC) {
749         valid_alternative_service_infos.push_back(
750             AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
751                 alternative_service, it->expiration(),
752                 it->advertised_versions()));
753       } else {
754         valid_alternative_service_infos.push_back(
755             AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
756                 alternative_service, it->expiration()));
757       }
758       ++it;
759     }
760     if (service_info->empty()) {
761       map_it->second.alternative_services.reset();
762       server_info_map_.EraseIfEmpty(map_it);
763     }
764     return valid_alternative_service_infos;
765   }
766 
767   auto canonical = GetCanonicalAltSvcHost(origin, network_anonymization_key);
768   if (canonical == canonical_alt_svc_map_.end()) {
769     return AlternativeServiceInfoVector();
770   }
771   map_it = server_info_map_.Get(
772       CreateServerInfoKey(canonical->second, network_anonymization_key));
773   if (map_it == server_info_map_.end() ||
774       !map_it->second.alternative_services.has_value()) {
775     return AlternativeServiceInfoVector();
776   }
777   AlternativeServiceInfoVector* service_info =
778       &map_it->second.alternative_services.value();
779   for (auto it = service_info->begin(); it != service_info->end();) {
780     if (it->expiration() < now) {
781       it = service_info->erase(it);
782       continue;
783     }
784     AlternativeService alternative_service(it->alternative_service());
785     if (alternative_service.host.empty()) {
786       alternative_service.host = canonical->second.host();
787       if (IsAlternativeServiceBroken(alternative_service,
788                                      network_anonymization_key)) {
789         ++it;
790         continue;
791       }
792       alternative_service.host = origin.host();
793     } else if (IsAlternativeServiceBroken(alternative_service,
794                                           network_anonymization_key)) {
795       ++it;
796       continue;
797     }
798     if (alternative_service.protocol == kProtoQUIC) {
799       valid_alternative_service_infos.push_back(
800           AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
801               alternative_service, it->expiration(),
802               it->advertised_versions()));
803     } else {
804       valid_alternative_service_infos.push_back(
805           AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
806               alternative_service, it->expiration()));
807     }
808     ++it;
809   }
810   if (service_info->empty())
811     server_info_map_.EraseIfEmpty(map_it);
812   return valid_alternative_service_infos;
813 }
814 
SetAlternativeServicesInternal(const url::SchemeHostPort & origin,const net::NetworkAnonymizationKey & network_anonymization_key,const AlternativeServiceInfoVector & alternative_service_info_vector)815 void HttpServerProperties::SetAlternativeServicesInternal(
816     const url::SchemeHostPort& origin,
817     const net::NetworkAnonymizationKey& network_anonymization_key,
818     const AlternativeServiceInfoVector& alternative_service_info_vector) {
819   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
820   DCHECK_NE(origin.scheme(), url::kWsScheme);
821   DCHECK_NE(origin.scheme(), url::kWssScheme);
822 
823   if (alternative_service_info_vector.empty()) {
824     RemoveAltSvcCanonicalHost(origin, network_anonymization_key);
825     // Don't bother moving to front when erasing information.
826     auto it = server_info_map_.Peek(
827         CreateServerInfoKey(origin, network_anonymization_key));
828 
829     if (it == server_info_map_.end() ||
830         !it->second.alternative_services.has_value()) {
831       return;
832     }
833 
834     it->second.alternative_services.reset();
835     server_info_map_.EraseIfEmpty(it);
836     MaybeQueueWriteProperties();
837     return;
838   }
839 
840   auto it = server_info_map_.GetOrPut(
841       CreateServerInfoKey(origin, network_anonymization_key));
842   bool need_update_pref = true;
843   if (it->second.alternative_services.has_value()) {
844     DCHECK(!it->second.empty());
845     if (it->second.alternative_services->size() ==
846         alternative_service_info_vector.size()) {
847       const base::Time now = clock_->Now();
848       need_update_pref = false;
849       auto new_it = alternative_service_info_vector.begin();
850       for (const auto& old : *it->second.alternative_services) {
851         // Persist to disk immediately if new entry has different scheme, host,
852         // or port.
853         if (old.alternative_service() != new_it->alternative_service()) {
854           need_update_pref = true;
855           break;
856         }
857         // Also persist to disk if new expiration it more that twice as far or
858         // less than half as far in the future.
859         base::Time old_time = old.expiration();
860         base::Time new_time = new_it->expiration();
861         if (new_time - now > 2 * (old_time - now) ||
862             2 * (new_time - now) < (old_time - now)) {
863           need_update_pref = true;
864           break;
865         }
866         // Also persist to disk if new entry has a different list of advertised
867         // versions.
868         if (old.advertised_versions() != new_it->advertised_versions()) {
869           need_update_pref = true;
870           break;
871         }
872         ++new_it;
873       }
874     }
875   }
876 
877   const bool previously_no_alternative_services =
878       (GetIteratorWithAlternativeServiceInfo(
879            origin, network_anonymization_key) == server_info_map_.end());
880 
881   it->second.alternative_services = alternative_service_info_vector;
882 
883   if (previously_no_alternative_services &&
884       !GetAlternativeServiceInfos(origin, network_anonymization_key).empty()) {
885     // TODO(rch): Consider the case where multiple requests are started
886     // before the first completes. In this case, only one of the jobs
887     // would reach this code, whereas all of them should should have.
888     HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING,
889                                     IsGoogleHost(origin.host()));
890   }
891 
892   // If this host ends with a canonical suffix, then set it as the
893   // canonical host.
894   const char* kCanonicalScheme = "https";
895   if (origin.scheme() == kCanonicalScheme) {
896     const std::string* canonical_suffix = GetCanonicalSuffix(origin.host());
897     if (canonical_suffix != nullptr) {
898       url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix,
899                                            origin.port());
900       canonical_alt_svc_map_[CreateServerInfoKey(
901           canonical_server, network_anonymization_key)] = origin;
902     }
903   }
904 
905   if (need_update_pref)
906     MaybeQueueWriteProperties();
907 }
908 
SetServerNetworkStatsInternal(url::SchemeHostPort server,const NetworkAnonymizationKey & network_anonymization_key,ServerNetworkStats stats)909 void HttpServerProperties::SetServerNetworkStatsInternal(
910     url::SchemeHostPort server,
911     const NetworkAnonymizationKey& network_anonymization_key,
912     ServerNetworkStats stats) {
913   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
914   DCHECK_NE(server.scheme(), url::kWsScheme);
915   DCHECK_NE(server.scheme(), url::kWssScheme);
916 
917   auto server_info = server_info_map_.GetOrPut(
918       CreateServerInfoKey(std::move(server), network_anonymization_key));
919   bool changed = !server_info->second.server_network_stats.has_value() ||
920                  server_info->second.server_network_stats.value() != stats;
921 
922   if (changed) {
923     server_info->second.server_network_stats = stats;
924     MaybeQueueWriteProperties();
925   }
926 }
927 
ClearServerNetworkStatsInternal(url::SchemeHostPort server,const NetworkAnonymizationKey & network_anonymization_key)928 void HttpServerProperties::ClearServerNetworkStatsInternal(
929     url::SchemeHostPort server,
930     const NetworkAnonymizationKey& network_anonymization_key) {
931   auto server_info = server_info_map_.Peek(
932       CreateServerInfoKey(std::move(server), network_anonymization_key));
933   // If stats are empty, nothing to do.
934   if (server_info == server_info_map_.end() ||
935       !server_info->second.server_network_stats.has_value()) {
936     return;
937   }
938 
939   // Otherwise, clear and delete if needed. No need to bring to front of MRU
940   // cache when clearing data.
941   server_info->second.server_network_stats.reset();
942   if (server_info->second.empty())
943     server_info_map_.EraseIfEmpty(server_info);
944   MaybeQueueWriteProperties();
945 }
946 
GetServerNetworkStatsInternal(url::SchemeHostPort server,const NetworkAnonymizationKey & network_anonymization_key)947 const ServerNetworkStats* HttpServerProperties::GetServerNetworkStatsInternal(
948     url::SchemeHostPort server,
949     const NetworkAnonymizationKey& network_anonymization_key) {
950   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
951   DCHECK_NE(server.scheme(), url::kWsScheme);
952   DCHECK_NE(server.scheme(), url::kWssScheme);
953 
954   auto server_info = server_info_map_.Get(
955       CreateServerInfoKey(std::move(server), network_anonymization_key));
956   if (server_info == server_info_map_.end() ||
957       !server_info->second.server_network_stats.has_value()) {
958     return nullptr;
959   }
960   return &server_info->second.server_network_stats.value();
961 }
962 
963 HttpServerProperties::QuicServerInfoMapKey
CreateQuicServerInfoKey(const quic::QuicServerId & server_id,const NetworkAnonymizationKey & network_anonymization_key) const964 HttpServerProperties::CreateQuicServerInfoKey(
965     const quic::QuicServerId& server_id,
966     const NetworkAnonymizationKey& network_anonymization_key) const {
967   return QuicServerInfoMapKey(server_id, network_anonymization_key,
968                               use_network_anonymization_key_);
969 }
970 
971 HttpServerProperties::ServerInfoMapKey
CreateServerInfoKey(const url::SchemeHostPort & server,const NetworkAnonymizationKey & network_anonymization_key) const972 HttpServerProperties::CreateServerInfoKey(
973     const url::SchemeHostPort& server,
974     const NetworkAnonymizationKey& network_anonymization_key) const {
975   return ServerInfoMapKey(server, network_anonymization_key,
976                           use_network_anonymization_key_);
977 }
978 
979 HttpServerProperties::ServerInfoMap::const_iterator
GetIteratorWithAlternativeServiceInfo(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key)980 HttpServerProperties::GetIteratorWithAlternativeServiceInfo(
981     const url::SchemeHostPort& server,
982     const net::NetworkAnonymizationKey& network_anonymization_key) {
983   ServerInfoMap::const_iterator it = server_info_map_.Get(
984       CreateServerInfoKey(server, network_anonymization_key));
985   if (it != server_info_map_.end() && it->second.alternative_services)
986     return it;
987 
988   auto canonical = GetCanonicalAltSvcHost(server, network_anonymization_key);
989   if (canonical == canonical_alt_svc_map_.end()) {
990     return server_info_map_.end();
991   }
992 
993   const url::SchemeHostPort canonical_server = canonical->second;
994   it = server_info_map_.Get(
995       CreateServerInfoKey(canonical_server, network_anonymization_key));
996   if (it == server_info_map_.end() || !it->second.alternative_services)
997     return server_info_map_.end();
998 
999   for (const AlternativeServiceInfo& alternative_service_info :
1000        it->second.alternative_services.value()) {
1001     AlternativeService alternative_service(
1002         alternative_service_info.alternative_service());
1003     if (alternative_service.host.empty()) {
1004       alternative_service.host = canonical_server.host();
1005     }
1006     if (!IsAlternativeServiceBroken(alternative_service,
1007                                     network_anonymization_key)) {
1008       return it;
1009     }
1010   }
1011 
1012   RemoveAltSvcCanonicalHost(canonical_server, network_anonymization_key);
1013   return server_info_map_.end();
1014 }
1015 
1016 HttpServerProperties::CanonicalMap::const_iterator
GetCanonicalAltSvcHost(const url::SchemeHostPort & server,const net::NetworkAnonymizationKey & network_anonymization_key) const1017 HttpServerProperties::GetCanonicalAltSvcHost(
1018     const url::SchemeHostPort& server,
1019     const net::NetworkAnonymizationKey& network_anonymization_key) const {
1020   const char* kCanonicalScheme = "https";
1021   if (server.scheme() != kCanonicalScheme)
1022     return canonical_alt_svc_map_.end();
1023 
1024   const std::string* canonical_suffix = GetCanonicalSuffix(server.host());
1025   if (canonical_suffix == nullptr)
1026     return canonical_alt_svc_map_.end();
1027 
1028   url::SchemeHostPort canonical_server(kCanonicalScheme, *canonical_suffix,
1029                                        server.port());
1030   return canonical_alt_svc_map_.find(
1031       CreateServerInfoKey(canonical_server, network_anonymization_key));
1032 }
1033 
1034 HttpServerProperties::QuicCanonicalMap::const_iterator
GetCanonicalServerInfoHost(const QuicServerInfoMapKey & key) const1035 HttpServerProperties::GetCanonicalServerInfoHost(
1036     const QuicServerInfoMapKey& key) const {
1037   const std::string* canonical_suffix =
1038       GetCanonicalSuffix(key.server_id.host());
1039   if (canonical_suffix == nullptr)
1040     return canonical_server_info_map_.end();
1041 
1042   quic::QuicServerId canonical_server_id(*canonical_suffix,
1043                                          key.server_id.privacy_mode_enabled(),
1044                                          key.server_id.port());
1045   return canonical_server_info_map_.find(CreateQuicServerInfoKey(
1046       canonical_server_id, key.network_anonymization_key));
1047 }
1048 
RemoveAltSvcCanonicalHost(const url::SchemeHostPort & server,const NetworkAnonymizationKey & network_anonymization_key)1049 void HttpServerProperties::RemoveAltSvcCanonicalHost(
1050     const url::SchemeHostPort& server,
1051     const NetworkAnonymizationKey& network_anonymization_key) {
1052   auto canonical = GetCanonicalAltSvcHost(server, network_anonymization_key);
1053   if (canonical == canonical_alt_svc_map_.end())
1054     return;
1055 
1056   canonical_alt_svc_map_.erase(canonical->first);
1057 }
1058 
UpdateCanonicalServerInfoMap(const QuicServerInfoMapKey & key)1059 void HttpServerProperties::UpdateCanonicalServerInfoMap(
1060     const QuicServerInfoMapKey& key) {
1061   const std::string* suffix = GetCanonicalSuffix(key.server_id.host());
1062   if (!suffix)
1063     return;
1064   quic::QuicServerId canonical_server(
1065       *suffix, key.server_id.privacy_mode_enabled(), key.server_id.port());
1066 
1067   canonical_server_info_map_[CreateQuicServerInfoKey(
1068       canonical_server, key.network_anonymization_key)] = key.server_id;
1069 }
1070 
GetCanonicalSuffix(const std::string & host) const1071 const std::string* HttpServerProperties::GetCanonicalSuffix(
1072     const std::string& host) const {
1073   // If this host ends with a canonical suffix, then return the canonical
1074   // suffix.
1075   for (const std::string& canonical_suffix : canonical_suffixes_) {
1076     if (base::EndsWith(host, canonical_suffix,
1077                        base::CompareCase::INSENSITIVE_ASCII)) {
1078       return &canonical_suffix;
1079     }
1080   }
1081   return nullptr;
1082 }
1083 
OnPrefsLoaded(std::unique_ptr<ServerInfoMap> server_info_map,const IPAddress & last_local_address_when_quic_worked,std::unique_ptr<QuicServerInfoMap> quic_server_info_map,std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list,std::unique_ptr<RecentlyBrokenAlternativeServices> recently_broken_alternative_services)1084 void HttpServerProperties::OnPrefsLoaded(
1085     std::unique_ptr<ServerInfoMap> server_info_map,
1086     const IPAddress& last_local_address_when_quic_worked,
1087     std::unique_ptr<QuicServerInfoMap> quic_server_info_map,
1088     std::unique_ptr<BrokenAlternativeServiceList>
1089         broken_alternative_service_list,
1090     std::unique_ptr<RecentlyBrokenAlternativeServices>
1091         recently_broken_alternative_services) {
1092   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1093 
1094   DCHECK(!is_initialized_);
1095 
1096   // Either all of these are nullptr, or none of them are (except the broken alt
1097   // service fields).
1098   if (server_info_map) {
1099     OnServerInfoLoaded(std::move(server_info_map));
1100     OnLastLocalAddressWhenQuicWorkedLoaded(last_local_address_when_quic_worked);
1101     OnQuicServerInfoMapLoaded(std::move(quic_server_info_map));
1102     if (recently_broken_alternative_services) {
1103       DCHECK(broken_alternative_service_list);
1104       OnBrokenAndRecentlyBrokenAlternativeServicesLoaded(
1105           std::move(broken_alternative_service_list),
1106           std::move(recently_broken_alternative_services));
1107     }
1108   }
1109 
1110   is_initialized_ = true;
1111 
1112   if (queue_write_on_load_) {
1113     // Leaving this as true doesn't actually have any effect, but seems best to
1114     // be safe.
1115     queue_write_on_load_ = false;
1116     MaybeQueueWriteProperties();
1117   }
1118 }
1119 
OnServerInfoLoaded(std::unique_ptr<ServerInfoMap> server_info_map)1120 void HttpServerProperties::OnServerInfoLoaded(
1121     std::unique_ptr<ServerInfoMap> server_info_map) {
1122   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1123 
1124   // Perform a simple sanity check on loaded data, when DCHECKs are enabled.
1125 #if DCHECK_IS_ON()
1126   if (!use_network_anonymization_key_) {
1127     for (auto server_info = server_info_map->begin();
1128          server_info != server_info_map->end(); ++server_info) {
1129       DCHECK(server_info->first.network_anonymization_key.IsEmpty());
1130     }
1131   }
1132 #endif  // DCHECK_IS_ON()
1133 
1134   // Swap in the entries from persisted data. This allows the MRU cache to be
1135   // sorted based on the order of the entries in the newer in-memory cache.
1136   server_info_map_.Swap(*server_info_map);
1137 
1138   // Add the entries from the memory cache.
1139   for (auto& [key, server_info] : base::Reversed(*server_info_map)) {
1140     // If there's no corresponding old entry, add the new entry directly.
1141     auto old_entry = server_info_map_.Get(key);
1142     if (old_entry == server_info_map_.end()) {
1143       server_info_map_.Put(key, std::move(server_info));
1144       continue;
1145     }
1146 
1147     // Otherwise, merge the old and new entries. Prefer values from older
1148     // entries.
1149     if (!old_entry->second.supports_spdy.has_value())
1150       old_entry->second.supports_spdy = server_info.supports_spdy;
1151     if (!old_entry->second.alternative_services.has_value())
1152       old_entry->second.alternative_services = server_info.alternative_services;
1153     if (!old_entry->second.server_network_stats.has_value())
1154       old_entry->second.server_network_stats = server_info.server_network_stats;
1155 
1156     // |requires_http11| isn't saved to prefs, so the loaded entry should not
1157     // have it set. Unconditionally copy it from the new entry.
1158     DCHECK(!old_entry->second.requires_http11.has_value());
1159     old_entry->second.requires_http11 = server_info.requires_http11;
1160   }
1161 
1162   // Attempt to find canonical servers. Canonical suffix only apply to HTTPS.
1163   const uint16_t kCanonicalPort = 443;
1164   const char* kCanonicalScheme = "https";
1165   for (const auto& it : server_info_map_) {
1166     if (!it.second.alternative_services ||
1167         it.first.server.scheme() != kCanonicalScheme) {
1168       continue;
1169     }
1170     const std::string* canonical_suffix =
1171         GetCanonicalSuffix(it.first.server.host());
1172     if (!canonical_suffix)
1173       continue;
1174     ServerInfoMapKey key = CreateServerInfoKey(
1175         url::SchemeHostPort(kCanonicalScheme, *canonical_suffix,
1176                             kCanonicalPort),
1177         it.first.network_anonymization_key);
1178     // If we already have a valid canonical server, we're done.
1179     if (base::Contains(canonical_alt_svc_map_, key)) {
1180       auto key_it = server_info_map_.Peek(key);
1181       if (key_it != server_info_map_.end() &&
1182           key_it->second.alternative_services.has_value()) {
1183         continue;
1184       }
1185     }
1186     canonical_alt_svc_map_[key] = it.first.server;
1187   }
1188 }
1189 
OnLastLocalAddressWhenQuicWorkedLoaded(const IPAddress & last_local_address_when_quic_worked)1190 void HttpServerProperties::OnLastLocalAddressWhenQuicWorkedLoaded(
1191     const IPAddress& last_local_address_when_quic_worked) {
1192   last_local_address_when_quic_worked_ = last_local_address_when_quic_worked;
1193 }
1194 
OnQuicServerInfoMapLoaded(std::unique_ptr<QuicServerInfoMap> quic_server_info_map)1195 void HttpServerProperties::OnQuicServerInfoMapLoaded(
1196     std::unique_ptr<QuicServerInfoMap> quic_server_info_map) {
1197   DCHECK_EQ(quic_server_info_map->max_size(), quic_server_info_map_.max_size());
1198 
1199   // Add the entries from persisted data.
1200   quic_server_info_map_.Swap(*quic_server_info_map);
1201 
1202   // Add the entries from the memory cache.
1203   for (const auto& [key, server_info] : base::Reversed(*quic_server_info_map)) {
1204     if (quic_server_info_map_.Get(key) == quic_server_info_map_.end()) {
1205       quic_server_info_map_.Put(key, server_info);
1206     }
1207   }
1208 
1209   // Repopulate |canonical_server_info_map_| to stay in sync with
1210   // |quic_server_info_map_|.
1211   canonical_server_info_map_.clear();
1212   for (const auto& [key, server_info] : base::Reversed(quic_server_info_map_)) {
1213     UpdateCanonicalServerInfoMap(key);
1214   }
1215 }
1216 
OnBrokenAndRecentlyBrokenAlternativeServicesLoaded(std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list,std::unique_ptr<RecentlyBrokenAlternativeServices> recently_broken_alternative_services)1217 void HttpServerProperties::OnBrokenAndRecentlyBrokenAlternativeServicesLoaded(
1218     std::unique_ptr<BrokenAlternativeServiceList>
1219         broken_alternative_service_list,
1220     std::unique_ptr<RecentlyBrokenAlternativeServices>
1221         recently_broken_alternative_services) {
1222   broken_alternative_services_.SetBrokenAndRecentlyBrokenAlternativeServices(
1223       std::move(broken_alternative_service_list),
1224       std::move(recently_broken_alternative_services));
1225 }
1226 
MaybeQueueWriteProperties()1227 void HttpServerProperties::MaybeQueueWriteProperties() {
1228   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1229   if (prefs_update_timer_.IsRunning() || !properties_manager_)
1230     return;
1231 
1232   if (!is_initialized_) {
1233     queue_write_on_load_ = true;
1234     return;
1235   }
1236 
1237   prefs_update_timer_.Start(
1238       FROM_HERE, kUpdatePrefsDelay,
1239       base::BindOnce(&HttpServerProperties::WriteProperties,
1240                      base::Unretained(this), base::OnceClosure()));
1241 }
1242 
FlushWritePropertiesForTesting(base::OnceClosure callback)1243 void HttpServerProperties::FlushWritePropertiesForTesting(
1244     base::OnceClosure callback) {
1245   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1246   if (!properties_manager_) {
1247     return;
1248   }
1249 
1250   // initialising the |properties_manager_| is not a concern here. So skip
1251   // it and set |is_initalized_| to true.
1252   is_initialized_ = true;
1253   // Stop the timer if it's running, since this will write to the properties
1254   // file immediately.
1255   prefs_update_timer_.Stop();
1256   WriteProperties(std::move(callback));
1257 }
1258 
WriteProperties(base::OnceClosure callback) const1259 void HttpServerProperties::WriteProperties(base::OnceClosure callback) const {
1260   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1261   DCHECK(properties_manager_);
1262 
1263   // |this| shouldn't be waiting to load properties cached to disk when this
1264   // method is invoked, since this method will overwrite any cached properties.
1265   DCHECK(is_initialized_);
1266 
1267   // There shouldn't be a queued update when this is run, since this method
1268   // removes the need for any update to be queued.
1269   DCHECK(!prefs_update_timer_.IsRunning());
1270 
1271   properties_manager_->WriteToPrefs(
1272       server_info_map_,
1273       base::BindRepeating(&HttpServerProperties::GetCanonicalSuffix,
1274                           base::Unretained(this)),
1275       last_local_address_when_quic_worked_, quic_server_info_map_,
1276       broken_alternative_services_.broken_alternative_service_list(),
1277       broken_alternative_services_.recently_broken_alternative_services(),
1278       std::move(callback));
1279 }
1280 
1281 }  // namespace net
1282