Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / net / http / http_server_properties_manager.cc
blobeb80a53e5fde201f1693a1d3fbadeb828107d803
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"
7 #include "base/bind.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"
18 namespace net {
20 namespace {
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
24 // timer.
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"
33 // property.
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";
69 } // namespace
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),
81 path_(pref_path),
82 network_task_runner_(network_task_runner) {
83 DCHECK(pref_service);
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(
91 path_,
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(
111 FROM_HERE,
112 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread,
113 pref_weak_ptr_));
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();
124 // static
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,
159 bool support_spdy) {
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()
252 const {
253 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
254 return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
257 void HttpServerPropertiesManager::SetAlternateProtocolProbabilityThreshold(
258 double threshold) {
259 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
260 http_server_properties_impl_->SetAlternateProtocolProbabilityThreshold(
261 threshold);
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,
272 SpdySettingsIds id,
273 SpdySettingsFlags flags,
274 uint32 value) {
275 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
276 bool persist = http_server_properties_impl_->SetSpdySetting(
277 host_port_pair, id, flags, value);
278 if (persist)
279 ScheduleUpdatePrefsOnNetworkThread();
280 return persist;
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()
297 const {
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(
309 bool used_quic,
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(
351 FROM_HERE,
352 delay,
353 this,
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_))
362 return;
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,
370 &version)) {
371 DVLOG(1) << "Missing version. Clearing all properties.";
372 return;
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.";
381 return;
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();
397 it.Advance()) {
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;
404 continue;
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;
411 continue;
414 // Get if server supports Spdy.
415 bool supports_spdy = false;
416 if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
417 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(
431 FROM_HERE,
432 base::Bind(
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) {
445 // Get SpdySettings.
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)) {
450 return;
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();
456 int id = 0;
457 if (!base::StringToInt(id_str, &id)) {
458 DVLOG(1) << "Malformed id in SpdySettings for server: "
459 << server.ToString();
460 NOTREACHED();
461 continue;
463 int value = 0;
464 if (!dict_it.value().GetAsInteger(&value)) {
465 DVLOG(1) << "Malformed value in SpdySettings for server: "
466 << server.ToString();
467 NOTREACHED();
468 continue;
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,
482 &protocol_str)) {
483 DVLOG(1) << "Malformed alternative service protocol string for server: "
484 << server_str;
485 return AlternativeServiceInfo();
487 AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
488 if (!IsAlternateProtocolValid(protocol)) {
489 DVLOG(1) << "Invalid alternative service protocol string for server: "
490 << server_str;
491 return AlternativeServiceInfo();
494 // Host is optional, defaults to "".
495 std::string host;
496 if (alternative_service_dict.HasKey(kHostKey) &&
497 !alternative_service_dict.GetStringWithoutPathExpansion(kHostKey,
498 &host)) {
499 DVLOG(1) << "Malformed alternative service host string for server: "
500 << server_str;
501 return AlternativeServiceInfo();
504 // Port is mandatory.
505 int port = 0;
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,
516 &probability)) {
517 DVLOG(1) << "Malformed alternative service probability for server: "
518 << server_str;
519 return AlternativeServiceInfo();
522 return AlternativeServiceInfo(protocol, host, static_cast<uint16>(port),
523 probability);
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()) {
539 return false;
541 // Get first element of the list.
542 // TODO(bnc): Once we store multiple AlternativeServiceInfo per server, read
543 // all of them.
544 if (!alternative_service_list->GetDictionary(0,
545 &alternative_service_dict)) {
546 return false;
548 alternative_service_info = ParseAlternativeServiceDict(
549 *alternative_service_dict, server.ToString());
550 } else {
551 // ...or alternate_protocol.
552 // TODO(bnc): Remove this in M46, we do not need preference migration for
553 // long.
554 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
555 kAlternateProtocolKey, &alternative_service_dict)) {
556 return true;
558 alternative_service_info = ParseAlternativeServiceDict(
559 *alternative_service_dict, server.ToString());
562 if (alternative_service_info.alternative_service.protocol ==
563 UNINITIALIZED_ALTERNATE_PROTOCOL) {
564 return false;
566 alternative_service_map->Put(server, alternative_service_info);
567 return true;
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)) {
576 return true;
578 bool used_quic = false;
579 if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
580 &used_quic)) {
581 DVLOG(1) << "Malformed SupportsQuic";
582 return false;
584 if (!used_quic)
585 return false;
587 std::string address;
588 if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
589 &address) ||
590 !ParseIPLiteralToNumber(address, last_quic_address)) {
591 DVLOG(1) << "Malformed SupportsQuic";
592 return false;
594 return true;
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)) {
605 return true;
607 int srtt;
608 if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
609 &srtt)) {
610 DVLOG(1) << "Malformed ServerNetworkStats for server: "
611 << server.ToString();
612 return false;
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);
619 return true;
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(
639 spdy_settings_map);
641 // Update the cached data and use the new Alternate-Protocol server list from
642 // preferences.
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(
674 FROM_HERE,
675 delay,
676 this,
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();
697 int count = 0;
698 for (SpdySettingsMap::const_iterator it = main_map.begin();
699 it != main_map.end() && count < kMaxSpdySettingsHostsToPersist;
700 ++it, ++count) {
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();
708 count = 0;
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)) {
716 continue;
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)) {
725 continue;
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())
731 continue;
732 persisted_map[canonical_suffix] = true;
734 alternative_service_map->Put(server, alternative_service_info);
735 ++count;
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(
752 FROM_HERE,
753 base::Bind(
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.
763 struct ServerPref {
764 ServerPref()
765 : supports_spdy(false),
766 settings_map(NULL),
767 alternative_service(NULL),
768 supports_quic(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) {}
780 bool supports_spdy;
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.
800 std::string s;
801 for (base::ListValue::const_iterator list_it = spdy_server_list->begin();
802 list_it != spdy_server_list->end();
803 ++list_it) {
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();
837 ++map_it) {
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,
848 server_pref_dict);
849 SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
850 server_pref_dict);
852 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
855 http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
856 servers_dict);
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())
870 completion.Run();
873 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
874 const SettingsMap* settings_map,
875 base::DictionaryValue* server_pref_dict) {
876 if (!settings_map) {
877 return;
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)
894 return;
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
912 // all of them.
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())
923 return;
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,
930 supports_quic_dict);
933 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
934 const ServerNetworkStats* server_network_stats,
935 base::DictionaryValue* server_pref_dict) {
936 if (!server_network_stats)
937 return;
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());
951 if (!setting_prefs_)
952 ScheduleUpdateCacheOnPrefThread();
955 } // namespace net