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