1 // Copyright 2014 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.
5 #include "net/http/http_server_properties_manager.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/values.h"
16 #include "net/base/net_util.h"
22 // Time to wait before starting an update the http_server_properties_impl_ cache
23 // from preferences. Scheduling another update during this period will reset the
25 const int64 kUpdateCacheDelayMs
= 1000;
27 // Time to wait before starting an update the preferences from the
28 // http_server_properties_impl_ cache. Scheduling another update during this
29 // period will reset the timer.
30 const int64 kUpdatePrefsDelayMs
= 5000;
32 // "version" 0 indicates, http_server_properties doesn't have "version"
34 const int kMissingVersion
= 0;
36 // The version number of persisted http_server_properties.
37 const int kVersionNumber
= 3;
39 typedef std::vector
<std::string
> StringVector
;
41 // Persist 200 MRU AlternateProtocolHostPortPairs.
42 const int kMaxAlternateProtocolHostsToPersist
= 200;
44 // Persist 200 MRU SpdySettingsHostPortPairs.
45 const int kMaxSpdySettingsHostsToPersist
= 200;
47 // Persist 300 MRU SupportsSpdyServerHostPortPairs.
48 const int kMaxSupportsSpdyServerHostsToPersist
= 300;
50 // Persist 200 ServerNetworkStats.
51 const int kMaxServerNetworkStatsHostsToPersist
= 200;
53 const char kVersionKey
[] = "version";
54 const char kServersKey
[] = "servers";
55 const char kSupportsSpdyKey
[] = "supports_spdy";
56 const char kSettingsKey
[] = "settings";
57 const char kSupportsQuicKey
[] = "supports_quic";
58 const char kUsedQuicKey
[] = "used_quic";
59 const char kAddressKey
[] = "address";
60 const char kAlternateProtocolKey
[] = "alternate_protocol";
61 const char kAlternativeServiceKey
[] = "alternative_service";
62 const char kProtocolKey
[] = "protocol_str";
63 const char kHostKey
[] = "host";
64 const char kPortKey
[] = "port";
65 const char kProbabilityKey
[] = "probability";
66 const char kNetworkStatsKey
[] = "network_stats";
67 const char kSrttKey
[] = "srtt";
71 ////////////////////////////////////////////////////////////////////////////////
72 // HttpServerPropertiesManager
74 HttpServerPropertiesManager::HttpServerPropertiesManager(
75 PrefService
* pref_service
,
76 const char* pref_path
,
77 scoped_refptr
<base::SequencedTaskRunner
> network_task_runner
)
78 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
79 pref_service_(pref_service
),
80 setting_prefs_(false),
82 network_task_runner_(network_task_runner
) {
84 pref_weak_ptr_factory_
.reset(
85 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
86 pref_weak_ptr_
= pref_weak_ptr_factory_
->GetWeakPtr();
87 pref_cache_update_timer_
.reset(
88 new base::OneShotTimer
<HttpServerPropertiesManager
>);
89 pref_change_registrar_
.Init(pref_service_
);
90 pref_change_registrar_
.Add(
92 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged
,
93 base::Unretained(this)));
96 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
97 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
98 network_weak_ptr_factory_
.reset();
101 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
102 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
103 network_weak_ptr_factory_
.reset(
104 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
105 http_server_properties_impl_
.reset(new HttpServerPropertiesImpl());
107 network_prefs_update_timer_
.reset(
108 new base::OneShotTimer
<HttpServerPropertiesManager
>);
110 pref_task_runner_
->PostTask(
112 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
,
116 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
117 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
118 // Cancel any pending updates, and stop listening for pref change updates.
119 pref_cache_update_timer_
->Stop();
120 pref_weak_ptr_factory_
.reset();
121 pref_change_registrar_
.RemoveAll();
125 void HttpServerPropertiesManager::SetVersion(
126 base::DictionaryValue
* http_server_properties_dict
,
127 int version_number
) {
128 if (version_number
< 0)
129 version_number
= kVersionNumber
;
130 DCHECK_LE(version_number
, kVersionNumber
);
131 if (version_number
<= kVersionNumber
)
132 http_server_properties_dict
->SetInteger(kVersionKey
, version_number
);
135 // This is required for conformance with the HttpServerProperties interface.
136 base::WeakPtr
<HttpServerProperties
> HttpServerPropertiesManager::GetWeakPtr() {
137 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
138 return network_weak_ptr_factory_
->GetWeakPtr();
141 void HttpServerPropertiesManager::Clear() {
142 Clear(base::Closure());
145 void HttpServerPropertiesManager::Clear(const base::Closure
& completion
) {
146 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
148 http_server_properties_impl_
->Clear();
149 UpdatePrefsFromCacheOnNetworkThread(completion
);
152 bool HttpServerPropertiesManager::SupportsRequestPriority(
153 const HostPortPair
& server
) {
154 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
155 return http_server_properties_impl_
->SupportsRequestPriority(server
);
158 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair
& server
,
160 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
162 http_server_properties_impl_
->SetSupportsSpdy(server
, support_spdy
);
163 ScheduleUpdatePrefsOnNetworkThread();
166 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair
& server
) {
167 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
168 return http_server_properties_impl_
->RequiresHTTP11(server
);
171 void HttpServerPropertiesManager::SetHTTP11Required(
172 const HostPortPair
& server
) {
173 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
175 http_server_properties_impl_
->SetHTTP11Required(server
);
176 ScheduleUpdatePrefsOnNetworkThread();
179 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair
& server
,
180 SSLConfig
* ssl_config
) {
181 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
182 http_server_properties_impl_
->MaybeForceHTTP11(server
, ssl_config
);
185 AlternativeService
HttpServerPropertiesManager::GetAlternativeService(
186 const HostPortPair
& origin
) {
187 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
188 return http_server_properties_impl_
->GetAlternativeService(origin
);
191 void HttpServerPropertiesManager::SetAlternativeService(
192 const HostPortPair
& origin
,
193 const AlternativeService
& alternative_service
,
194 double alternative_probability
) {
195 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
196 http_server_properties_impl_
->SetAlternativeService(
197 origin
, alternative_service
, alternative_probability
);
198 ScheduleUpdatePrefsOnNetworkThread();
201 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
202 const AlternativeService
& alternative_service
) {
203 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
204 http_server_properties_impl_
->MarkAlternativeServiceBroken(
205 alternative_service
);
206 ScheduleUpdatePrefsOnNetworkThread();
209 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
210 const AlternativeService
& alternative_service
) {
211 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
212 http_server_properties_impl_
->MarkAlternativeServiceRecentlyBroken(
213 alternative_service
);
214 ScheduleUpdatePrefsOnNetworkThread();
217 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
218 const AlternativeService
& alternative_service
) const {
219 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
220 return http_server_properties_impl_
->IsAlternativeServiceBroken(
221 alternative_service
);
224 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
225 const AlternativeService
& alternative_service
) {
226 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
227 return http_server_properties_impl_
->WasAlternativeServiceRecentlyBroken(
228 alternative_service
);
231 void HttpServerPropertiesManager::ConfirmAlternativeService(
232 const AlternativeService
& alternative_service
) {
233 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
234 http_server_properties_impl_
->ConfirmAlternativeService(alternative_service
);
235 ScheduleUpdatePrefsOnNetworkThread();
238 void HttpServerPropertiesManager::ClearAlternativeService(
239 const HostPortPair
& origin
) {
240 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
241 http_server_properties_impl_
->ClearAlternativeService(origin
);
242 ScheduleUpdatePrefsOnNetworkThread();
245 const AlternativeServiceMap
&
246 HttpServerPropertiesManager::alternative_service_map() const {
247 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
248 return http_server_properties_impl_
->alternative_service_map();
251 base::Value
* HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
253 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
254 return http_server_properties_impl_
->GetAlternativeServiceInfoAsValue();
257 void HttpServerPropertiesManager::SetAlternateProtocolProbabilityThreshold(
259 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
260 http_server_properties_impl_
->SetAlternateProtocolProbabilityThreshold(
264 const SettingsMap
& HttpServerPropertiesManager::GetSpdySettings(
265 const HostPortPair
& host_port_pair
) {
266 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
267 return http_server_properties_impl_
->GetSpdySettings(host_port_pair
);
270 bool HttpServerPropertiesManager::SetSpdySetting(
271 const HostPortPair
& host_port_pair
,
273 SpdySettingsFlags flags
,
275 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
276 bool persist
= http_server_properties_impl_
->SetSpdySetting(
277 host_port_pair
, id
, flags
, value
);
279 ScheduleUpdatePrefsOnNetworkThread();
283 void HttpServerPropertiesManager::ClearSpdySettings(
284 const HostPortPair
& host_port_pair
) {
285 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
286 http_server_properties_impl_
->ClearSpdySettings(host_port_pair
);
287 ScheduleUpdatePrefsOnNetworkThread();
290 void HttpServerPropertiesManager::ClearAllSpdySettings() {
291 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
292 http_server_properties_impl_
->ClearAllSpdySettings();
293 ScheduleUpdatePrefsOnNetworkThread();
296 const SpdySettingsMap
& HttpServerPropertiesManager::spdy_settings_map()
298 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
299 return http_server_properties_impl_
->spdy_settings_map();
302 bool HttpServerPropertiesManager::GetSupportsQuic(
303 IPAddressNumber
* last_address
) const {
304 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
305 return http_server_properties_impl_
->GetSupportsQuic(last_address
);
308 void HttpServerPropertiesManager::SetSupportsQuic(
310 const IPAddressNumber
& address
) {
311 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
312 http_server_properties_impl_
->SetSupportsQuic(used_quic
, address
);
313 ScheduleUpdatePrefsOnNetworkThread();
316 void HttpServerPropertiesManager::SetServerNetworkStats(
317 const HostPortPair
& host_port_pair
,
318 ServerNetworkStats stats
) {
319 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
320 http_server_properties_impl_
->SetServerNetworkStats(host_port_pair
, stats
);
321 ScheduleUpdatePrefsOnNetworkThread();
324 const ServerNetworkStats
* HttpServerPropertiesManager::GetServerNetworkStats(
325 const HostPortPair
& host_port_pair
) {
326 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
327 return http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
330 const ServerNetworkStatsMap
&
331 HttpServerPropertiesManager::server_network_stats_map() const {
332 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
333 return http_server_properties_impl_
->server_network_stats_map();
337 // Update the HttpServerPropertiesImpl's cache with data from preferences.
339 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
340 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
341 // Cancel pending updates, if any.
342 pref_cache_update_timer_
->Stop();
343 StartCacheUpdateTimerOnPrefThread(
344 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs
));
347 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
348 base::TimeDelta delay
) {
349 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
350 pref_cache_update_timer_
->Start(
354 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
);
357 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
358 // The preferences can only be read on the pref thread.
359 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
361 if (!pref_service_
->HasPrefPath(path_
))
364 bool detected_corrupted_prefs
= false;
365 const base::DictionaryValue
& http_server_properties_dict
=
366 *pref_service_
->GetDictionary(path_
);
368 int version
= kMissingVersion
;
369 if (!http_server_properties_dict
.GetIntegerWithoutPathExpansion(kVersionKey
,
371 DVLOG(1) << "Missing version. Clearing all properties.";
375 // The properties for a given server is in
376 // http_server_properties_dict["servers"][server].
377 const base::DictionaryValue
* servers_dict
= NULL
;
378 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
379 kServersKey
, &servers_dict
)) {
380 DVLOG(1) << "Malformed http_server_properties for servers.";
384 IPAddressNumber
* addr
= new IPAddressNumber
;
385 ReadSupportsQuic(http_server_properties_dict
, addr
);
387 // String is host/port pair of spdy server.
388 scoped_ptr
<StringVector
> spdy_servers(new StringVector
);
389 scoped_ptr
<SpdySettingsMap
> spdy_settings_map(
390 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
));
391 scoped_ptr
<AlternativeServiceMap
> alternative_service_map(
392 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
));
393 scoped_ptr
<ServerNetworkStatsMap
> server_network_stats_map(
394 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
));
396 for (base::DictionaryValue::Iterator
it(*servers_dict
); !it
.IsAtEnd();
398 // Get server's host/pair.
399 const std::string
& server_str
= it
.key();
400 HostPortPair server
= HostPortPair::FromString(server_str
);
401 if (server
.host().empty()) {
402 DVLOG(1) << "Malformed http_server_properties for server: " << server_str
;
403 detected_corrupted_prefs
= true;
407 const base::DictionaryValue
* server_pref_dict
= NULL
;
408 if (!it
.value().GetAsDictionary(&server_pref_dict
)) {
409 DVLOG(1) << "Malformed http_server_properties server: " << server_str
;
410 detected_corrupted_prefs
= true;
414 // Get if server supports Spdy.
415 bool supports_spdy
= false;
416 if ((server_pref_dict
->GetBoolean(kSupportsSpdyKey
, &supports_spdy
)) &&
418 spdy_servers
->push_back(server_str
);
421 AddToSpdySettingsMap(server
, *server_pref_dict
, spdy_settings_map
.get());
422 if (!AddToAlternativeServiceMap(server
, *server_pref_dict
,
423 alternative_service_map
.get()) ||
424 !AddToNetworkStatsMap(server
, *server_pref_dict
,
425 server_network_stats_map
.get())) {
426 detected_corrupted_prefs
= true;
430 network_task_runner_
->PostTask(
433 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread
,
434 base::Unretained(this), base::Owned(spdy_servers
.release()),
435 base::Owned(spdy_settings_map
.release()),
436 base::Owned(alternative_service_map
.release()), base::Owned(addr
),
437 base::Owned(server_network_stats_map
.release()),
438 detected_corrupted_prefs
));
441 void HttpServerPropertiesManager::AddToSpdySettingsMap(
442 const HostPortPair
& server
,
443 const base::DictionaryValue
& server_pref_dict
,
444 SpdySettingsMap
* spdy_settings_map
) {
446 DCHECK(spdy_settings_map
->Peek(server
) == spdy_settings_map
->end());
447 const base::DictionaryValue
* spdy_settings_dict
= NULL
;
448 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
449 kSettingsKey
, &spdy_settings_dict
)) {
452 SettingsMap settings_map
;
453 for (base::DictionaryValue::Iterator
dict_it(*spdy_settings_dict
);
454 !dict_it
.IsAtEnd(); dict_it
.Advance()) {
455 const std::string
& id_str
= dict_it
.key();
457 if (!base::StringToInt(id_str
, &id
)) {
458 DVLOG(1) << "Malformed id in SpdySettings for server: "
459 << server
.ToString();
464 if (!dict_it
.value().GetAsInteger(&value
)) {
465 DVLOG(1) << "Malformed value in SpdySettings for server: "
466 << server
.ToString();
470 SettingsFlagsAndValue
flags_and_value(SETTINGS_FLAG_PERSISTED
, value
);
471 settings_map
[static_cast<SpdySettingsIds
>(id
)] = flags_and_value
;
473 spdy_settings_map
->Put(server
, settings_map
);
476 AlternativeServiceInfo
HttpServerPropertiesManager::ParseAlternativeServiceDict(
477 const base::DictionaryValue
& alternative_service_dict
,
478 const std::string
& server_str
) {
479 // Protocol is mandatory.
480 std::string protocol_str
;
481 if (!alternative_service_dict
.GetStringWithoutPathExpansion(kProtocolKey
,
483 DVLOG(1) << "Malformed alternative service protocol string for server: "
485 return AlternativeServiceInfo();
487 AlternateProtocol protocol
= AlternateProtocolFromString(protocol_str
);
488 if (!IsAlternateProtocolValid(protocol
)) {
489 DVLOG(1) << "Invalid alternative service protocol string for server: "
491 return AlternativeServiceInfo();
494 // Host is optional, defaults to "".
496 if (alternative_service_dict
.HasKey(kHostKey
) &&
497 !alternative_service_dict
.GetStringWithoutPathExpansion(kHostKey
,
499 DVLOG(1) << "Malformed alternative service host string for server: "
501 return AlternativeServiceInfo();
504 // Port is mandatory.
506 if (!alternative_service_dict
.GetInteger(kPortKey
, &port
) ||
507 !IsPortValid(port
)) {
508 DVLOG(1) << "Malformed alternative service port for server: " << server_str
;
509 return AlternativeServiceInfo();
512 // Probability is optional, defaults to 1.0.
513 double probability
= 1.0;
514 if (alternative_service_dict
.HasKey(kProbabilityKey
) &&
515 !alternative_service_dict
.GetDoubleWithoutPathExpansion(kProbabilityKey
,
517 DVLOG(1) << "Malformed alternative service probability for server: "
519 return AlternativeServiceInfo();
522 return AlternativeServiceInfo(protocol
, host
, static_cast<uint16
>(port
),
526 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
527 const HostPortPair
& server
,
528 const base::DictionaryValue
& server_pref_dict
,
529 AlternativeServiceMap
* alternative_service_map
) {
530 DCHECK(alternative_service_map
->Peek(server
) ==
531 alternative_service_map
->end());
532 // Get alternative_services...
533 const base::ListValue
* alternative_service_list
;
534 const base::DictionaryValue
* alternative_service_dict
;
535 AlternativeServiceInfo alternative_service_info
;
536 if (server_pref_dict
.GetListWithoutPathExpansion(kAlternativeServiceKey
,
537 &alternative_service_list
)) {
538 if (alternative_service_list
->empty()) {
541 // Get first element of the list.
542 // TODO(bnc): Once we store multiple AlternativeServiceInfo per server, read
544 if (!alternative_service_list
->GetDictionary(0,
545 &alternative_service_dict
)) {
548 alternative_service_info
= ParseAlternativeServiceDict(
549 *alternative_service_dict
, server
.ToString());
551 // ...or alternate_protocol.
552 // TODO(bnc): Remove this in M46, we do not need preference migration for
554 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
555 kAlternateProtocolKey
, &alternative_service_dict
)) {
558 alternative_service_info
= ParseAlternativeServiceDict(
559 *alternative_service_dict
, server
.ToString());
562 if (alternative_service_info
.alternative_service
.protocol
==
563 UNINITIALIZED_ALTERNATE_PROTOCOL
) {
566 alternative_service_map
->Put(server
, alternative_service_info
);
570 bool HttpServerPropertiesManager::ReadSupportsQuic(
571 const base::DictionaryValue
& http_server_properties_dict
,
572 IPAddressNumber
* last_quic_address
) {
573 const base::DictionaryValue
* supports_quic_dict
= NULL
;
574 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
575 kSupportsQuicKey
, &supports_quic_dict
)) {
578 bool used_quic
= false;
579 if (!supports_quic_dict
->GetBooleanWithoutPathExpansion(kUsedQuicKey
,
581 DVLOG(1) << "Malformed SupportsQuic";
588 if (!supports_quic_dict
->GetStringWithoutPathExpansion(kAddressKey
,
590 !ParseIPLiteralToNumber(address
, last_quic_address
)) {
591 DVLOG(1) << "Malformed SupportsQuic";
597 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
598 const HostPortPair
& server
,
599 const base::DictionaryValue
& server_pref_dict
,
600 ServerNetworkStatsMap
* network_stats_map
) {
601 DCHECK(network_stats_map
->Peek(server
) == network_stats_map
->end());
602 const base::DictionaryValue
* server_network_stats_dict
= NULL
;
603 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
604 kNetworkStatsKey
, &server_network_stats_dict
)) {
608 if (!server_network_stats_dict
->GetIntegerWithoutPathExpansion(kSrttKey
,
610 DVLOG(1) << "Malformed ServerNetworkStats for server: "
611 << server
.ToString();
614 ServerNetworkStats server_network_stats
;
615 server_network_stats
.srtt
= base::TimeDelta::FromInternalValue(srtt
);
616 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
617 // bandwidth_estimate.
618 network_stats_map
->Put(server
, server_network_stats
);
622 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
623 StringVector
* spdy_servers
,
624 SpdySettingsMap
* spdy_settings_map
,
625 AlternativeServiceMap
* alternative_service_map
,
626 IPAddressNumber
* last_quic_address
,
627 ServerNetworkStatsMap
* server_network_stats_map
,
628 bool detected_corrupted_prefs
) {
629 // Preferences have the master data because admins might have pushed new
630 // preferences. Update the cached data with new data from preferences.
631 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
633 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers
->size());
634 http_server_properties_impl_
->InitializeSpdyServers(spdy_servers
, true);
636 // Update the cached data and use the new spdy_settings from preferences.
637 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map
->size());
638 http_server_properties_impl_
->InitializeSpdySettingsServers(
641 // Update the cached data and use the new Alternate-Protocol server list from
643 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
644 alternative_service_map
->size());
645 http_server_properties_impl_
->InitializeAlternativeServiceServers(
646 alternative_service_map
);
648 http_server_properties_impl_
->InitializeSupportsQuic(last_quic_address
);
650 http_server_properties_impl_
->InitializeServerNetworkStats(
651 server_network_stats_map
);
653 // Update the prefs with what we have read (delete all corrupted prefs).
654 if (detected_corrupted_prefs
)
655 ScheduleUpdatePrefsOnNetworkThread();
659 // Update Preferences with data from the cached data.
661 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread() {
662 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
663 // Cancel pending updates, if any.
664 network_prefs_update_timer_
->Stop();
665 StartPrefsUpdateTimerOnNetworkThread(
666 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs
));
669 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
670 base::TimeDelta delay
) {
671 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
672 // This is overridden in tests to post the task without the delay.
673 network_prefs_update_timer_
->Start(
677 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread
);
680 // This is required so we can set this as the callback for a timer.
681 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
682 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
685 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
686 const base::Closure
& completion
) {
687 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
689 base::ListValue
* spdy_server_list
= new base::ListValue
;
690 http_server_properties_impl_
->GetSpdyServerList(
691 spdy_server_list
, kMaxSupportsSpdyServerHostsToPersist
);
693 SpdySettingsMap
* spdy_settings_map
=
694 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
);
695 const SpdySettingsMap
& main_map
=
696 http_server_properties_impl_
->spdy_settings_map();
698 for (SpdySettingsMap::const_iterator it
= main_map
.begin();
699 it
!= main_map
.end() && count
< kMaxSpdySettingsHostsToPersist
;
701 spdy_settings_map
->Put(it
->first
, it
->second
);
704 AlternativeServiceMap
* alternative_service_map
=
705 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
);
706 const AlternativeServiceMap
& map
=
707 http_server_properties_impl_
->alternative_service_map();
709 typedef std::map
<std::string
, bool> CanonicalHostPersistedMap
;
710 CanonicalHostPersistedMap persisted_map
;
711 for (AlternativeServiceMap::const_iterator it
= map
.begin();
712 it
!= map
.end() && count
< kMaxAlternateProtocolHostsToPersist
; ++it
) {
713 const AlternativeServiceInfo
& alternative_service_info
= it
->second
;
714 if (!IsAlternateProtocolValid(
715 alternative_service_info
.alternative_service
.protocol
)) {
718 const HostPortPair
& server
= it
->first
;
719 AlternativeService
alternative_service(
720 alternative_service_info
.alternative_service
);
721 if (alternative_service
.host
.empty()) {
722 alternative_service
.host
= server
.host();
724 if (IsAlternativeServiceBroken(alternative_service
)) {
727 std::string canonical_suffix
=
728 http_server_properties_impl_
->GetCanonicalSuffix(server
.host());
729 if (!canonical_suffix
.empty()) {
730 if (persisted_map
.find(canonical_suffix
) != persisted_map
.end())
732 persisted_map
[canonical_suffix
] = true;
734 alternative_service_map
->Put(server
, alternative_service_info
);
738 ServerNetworkStatsMap
* server_network_stats_map
=
739 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
);
740 const ServerNetworkStatsMap
& main_server_network_stats_map
=
741 http_server_properties_impl_
->server_network_stats_map();
742 for (ServerNetworkStatsMap::const_iterator it
=
743 main_server_network_stats_map
.begin();
744 it
!= main_server_network_stats_map
.end(); ++it
) {
745 server_network_stats_map
->Put(it
->first
, it
->second
);
748 IPAddressNumber
* last_quic_addr
= new IPAddressNumber
;
749 http_server_properties_impl_
->GetSupportsQuic(last_quic_addr
);
750 // Update the preferences on the pref thread.
751 pref_task_runner_
->PostTask(
754 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread
, pref_weak_ptr_
,
755 base::Owned(spdy_server_list
), base::Owned(spdy_settings_map
),
756 base::Owned(alternative_service_map
), base::Owned(last_quic_addr
),
757 base::Owned(server_network_stats_map
), completion
));
760 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
761 // AlternativeServiceInfo and SupportsQuic preferences for a server. This is
762 // used only in UpdatePrefsOnPrefThread.
765 : supports_spdy(false),
767 alternative_service(NULL
),
769 server_network_stats(NULL
) {}
770 ServerPref(bool supports_spdy
,
771 const SettingsMap
* settings_map
,
772 const AlternativeServiceInfo
* alternative_service
,
773 const SupportsQuic
* supports_quic
,
774 const ServerNetworkStats
* server_network_stats
)
775 : supports_spdy(supports_spdy
),
776 settings_map(settings_map
),
777 alternative_service(alternative_service
),
778 supports_quic(supports_quic
),
779 server_network_stats(server_network_stats
) {}
781 const SettingsMap
* settings_map
;
782 const AlternativeServiceInfo
* alternative_service
;
783 const SupportsQuic
* supports_quic
;
784 const ServerNetworkStats
* server_network_stats
;
787 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
788 base::ListValue
* spdy_server_list
,
789 SpdySettingsMap
* spdy_settings_map
,
790 AlternativeServiceMap
* alternative_service_map
,
791 IPAddressNumber
* last_quic_address
,
792 ServerNetworkStatsMap
* server_network_stats_map
,
793 const base::Closure
& completion
) {
794 typedef std::map
<HostPortPair
, ServerPref
> ServerPrefMap
;
795 ServerPrefMap server_pref_map
;
797 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
799 // Add servers that support spdy to server_pref_map.
801 for (base::ListValue::const_iterator list_it
= spdy_server_list
->begin();
802 list_it
!= spdy_server_list
->end();
804 if ((*list_it
)->GetAsString(&s
)) {
805 HostPortPair server
= HostPortPair::FromString(s
);
806 server_pref_map
[server
].supports_spdy
= true;
810 // Add servers that have SpdySettings to server_pref_map.
811 for (SpdySettingsMap::iterator map_it
= spdy_settings_map
->begin();
812 map_it
!= spdy_settings_map
->end(); ++map_it
) {
813 const HostPortPair
& server
= map_it
->first
;
814 server_pref_map
[server
].settings_map
= &map_it
->second
;
817 // Add AlternateProtocol servers to server_pref_map.
818 for (AlternativeServiceMap::const_iterator map_it
=
819 alternative_service_map
->begin();
820 map_it
!= alternative_service_map
->end(); ++map_it
) {
821 server_pref_map
[map_it
->first
].alternative_service
= &map_it
->second
;
824 // Add ServerNetworkStats servers to server_pref_map.
825 for (ServerNetworkStatsMap::const_iterator map_it
=
826 server_network_stats_map
->begin();
827 map_it
!= server_network_stats_map
->end(); ++map_it
) {
828 const HostPortPair
& server
= map_it
->first
;
829 server_pref_map
[server
].server_network_stats
= &map_it
->second
;
832 // Persist properties to the |path_|.
833 base::DictionaryValue http_server_properties_dict
;
834 base::DictionaryValue
* servers_dict
= new base::DictionaryValue
;
835 for (ServerPrefMap::const_iterator map_it
= server_pref_map
.begin();
836 map_it
!= server_pref_map
.end();
838 const HostPortPair
& server
= map_it
->first
;
839 const ServerPref
& server_pref
= map_it
->second
;
841 base::DictionaryValue
* server_pref_dict
= new base::DictionaryValue
;
843 // Save supports_spdy.
844 if (server_pref
.supports_spdy
)
845 server_pref_dict
->SetBoolean(kSupportsSpdyKey
, server_pref
.supports_spdy
);
846 SaveSpdySettingsToServerPrefs(server_pref
.settings_map
, server_pref_dict
);
847 SaveAlternativeServiceToServerPrefs(server_pref
.alternative_service
,
849 SaveNetworkStatsToServerPrefs(server_pref
.server_network_stats
,
852 servers_dict
->SetWithoutPathExpansion(server
.ToString(), server_pref_dict
);
855 http_server_properties_dict
.SetWithoutPathExpansion(kServersKey
,
857 SetVersion(&http_server_properties_dict
, kVersionNumber
);
859 SaveSupportsQuicToPrefs(last_quic_address
, &http_server_properties_dict
);
861 setting_prefs_
= true;
862 pref_service_
->Set(path_
, http_server_properties_dict
);
863 setting_prefs_
= false;
865 // Note that |completion| will be fired after we have written everything to
866 // the Preferences, but likely before these changes are serialized to disk.
867 // This is not a problem though, as JSONPrefStore guarantees that this will
868 // happen, pretty soon, and even in the case we shut down immediately.
869 if (!completion
.is_null())
873 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
874 const SettingsMap
* settings_map
,
875 base::DictionaryValue
* server_pref_dict
) {
879 base::DictionaryValue
* spdy_settings_dict
= new base::DictionaryValue
;
880 for (SettingsMap::const_iterator it
= settings_map
->begin();
881 it
!= settings_map
->end(); ++it
) {
882 SpdySettingsIds id
= it
->first
;
883 uint32 value
= it
->second
.second
;
884 std::string key
= base::StringPrintf("%u", id
);
885 spdy_settings_dict
->SetInteger(key
, value
);
887 server_pref_dict
->SetWithoutPathExpansion(kSettingsKey
, spdy_settings_dict
);
890 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
891 const AlternativeServiceInfo
* alternative_service_info
,
892 base::DictionaryValue
* server_pref_dict
) {
893 if (!alternative_service_info
)
896 const AlternativeService
& alternative_service
=
897 alternative_service_info
->alternative_service
;
898 base::DictionaryValue
* alternative_service_info_dict
=
899 new base::DictionaryValue
;
900 alternative_service_info_dict
->SetString(
901 kProtocolKey
, AlternateProtocolToString(alternative_service
.protocol
));
902 if (!alternative_service
.host
.empty()) {
903 alternative_service_info_dict
->SetString(kHostKey
,
904 alternative_service
.host
);
906 alternative_service_info_dict
->SetInteger(kPortKey
, alternative_service
.port
);
907 alternative_service_info_dict
->SetDouble(
908 kProbabilityKey
, alternative_service_info
->probability
);
910 // Create a single element list here.
911 // TODO(bnc): Once we store multiple AlternativeServiceInfo per server, save
913 base::ListValue
* alternative_service_list
= new base::ListValue();
914 alternative_service_list
->Append(alternative_service_info_dict
);
915 server_pref_dict
->SetWithoutPathExpansion(kAlternativeServiceKey
,
916 alternative_service_list
);
919 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
920 const IPAddressNumber
* last_quic_address
,
921 base::DictionaryValue
* http_server_properties_dict
) {
922 if (!last_quic_address
|| last_quic_address
->empty())
925 base::DictionaryValue
* supports_quic_dict
= new base::DictionaryValue
;
926 supports_quic_dict
->SetBoolean(kUsedQuicKey
, true);
927 supports_quic_dict
->SetString(kAddressKey
,
928 IPAddressToString(*last_quic_address
));
929 http_server_properties_dict
->SetWithoutPathExpansion(kSupportsQuicKey
,
933 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
934 const ServerNetworkStats
* server_network_stats
,
935 base::DictionaryValue
* server_pref_dict
) {
936 if (!server_network_stats
)
939 base::DictionaryValue
* server_network_stats_dict
= new base::DictionaryValue
;
940 // Becasue JSON doesn't support int64, persist int64 as a string.
941 server_network_stats_dict
->SetInteger(
942 kSrttKey
, static_cast<int>(server_network_stats
->srtt
.ToInternalValue()));
943 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
944 // bandwidth_estimate.
945 server_pref_dict
->SetWithoutPathExpansion(kNetworkStatsKey
,
946 server_network_stats_dict
);
949 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
950 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
952 ScheduleUpdateCacheOnPrefThread();