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