Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / net / http / http_server_properties_manager.cc
blobb0b6019df572a90a16267fb4979621e9f896bff2
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_macros.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/ip_address_number.h"
17 #include "net/base/port_util.h"
19 namespace net {
21 namespace {
23 // Time to wait before starting an update the http_server_properties_impl_ cache
24 // from preferences. Scheduling another update during this period will reset the
25 // timer.
26 const int64 kUpdateCacheDelayMs = 1000;
28 // Time to wait before starting an update the preferences from the
29 // http_server_properties_impl_ cache. Scheduling another update during this
30 // period will reset the timer.
31 const int64 kUpdatePrefsDelayMs = 60000;
33 // "version" 0 indicates, http_server_properties doesn't have "version"
34 // property.
35 const int kMissingVersion = 0;
37 // The version number of persisted http_server_properties.
38 const int kVersionNumber = 3;
40 typedef std::vector<std::string> StringVector;
42 // Persist 200 MRU AlternateProtocolHostPortPairs.
43 const int kMaxAlternateProtocolHostsToPersist = 200;
45 // Persist 200 MRU SpdySettingsHostPortPairs.
46 const int kMaxSpdySettingsHostsToPersist = 200;
48 // Persist 300 MRU SupportsSpdyServerHostPortPairs.
49 const int kMaxSupportsSpdyServerHostsToPersist = 300;
51 // Persist 200 ServerNetworkStats.
52 const int kMaxServerNetworkStatsHostsToPersist = 200;
54 const char kVersionKey[] = "version";
55 const char kServersKey[] = "servers";
56 const char kSupportsSpdyKey[] = "supports_spdy";
57 const char kSettingsKey[] = "settings";
58 const char kSupportsQuicKey[] = "supports_quic";
59 const char kUsedQuicKey[] = "used_quic";
60 const char kAddressKey[] = "address";
61 const char kAlternateProtocolKey[] = "alternate_protocol";
62 const char kAlternativeServiceKey[] = "alternative_service";
63 const char kProtocolKey[] = "protocol_str";
64 const char kHostKey[] = "host";
65 const char kPortKey[] = "port";
66 const char kProbabilityKey[] = "probability";
67 const char kExpirationKey[] = "expiration";
68 const char kNetworkStatsKey[] = "network_stats";
69 const char kSrttKey[] = "srtt";
71 } // namespace
73 ////////////////////////////////////////////////////////////////////////////////
74 // HttpServerPropertiesManager
76 HttpServerPropertiesManager::HttpServerPropertiesManager(
77 PrefService* pref_service,
78 const char* pref_path,
79 scoped_refptr<base::SequencedTaskRunner> network_task_runner)
80 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
81 pref_service_(pref_service),
82 setting_prefs_(false),
83 path_(pref_path),
84 network_task_runner_(network_task_runner) {
85 DCHECK(pref_service);
86 pref_weak_ptr_factory_.reset(
87 new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
88 pref_weak_ptr_ = pref_weak_ptr_factory_->GetWeakPtr();
89 pref_cache_update_timer_.reset(
90 new base::OneShotTimer<HttpServerPropertiesManager>);
91 pref_change_registrar_.Init(pref_service_);
92 pref_change_registrar_.Add(
93 path_,
94 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged,
95 base::Unretained(this)));
98 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
99 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
100 network_weak_ptr_factory_.reset();
103 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
104 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
105 network_weak_ptr_factory_.reset(
106 new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
107 http_server_properties_impl_.reset(new HttpServerPropertiesImpl());
109 network_prefs_update_timer_.reset(
110 new base::OneShotTimer<HttpServerPropertiesManager>);
112 pref_task_runner_->PostTask(
113 FROM_HERE,
114 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread,
115 pref_weak_ptr_));
118 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
119 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
120 // Cancel any pending updates, and stop listening for pref change updates.
121 pref_cache_update_timer_->Stop();
122 pref_weak_ptr_factory_.reset();
123 pref_change_registrar_.RemoveAll();
126 // static
127 void HttpServerPropertiesManager::SetVersion(
128 base::DictionaryValue* http_server_properties_dict,
129 int version_number) {
130 if (version_number < 0)
131 version_number = kVersionNumber;
132 DCHECK_LE(version_number, kVersionNumber);
133 if (version_number <= kVersionNumber)
134 http_server_properties_dict->SetInteger(kVersionKey, version_number);
137 // This is required for conformance with the HttpServerProperties interface.
138 base::WeakPtr<HttpServerProperties> HttpServerPropertiesManager::GetWeakPtr() {
139 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
140 return network_weak_ptr_factory_->GetWeakPtr();
143 void HttpServerPropertiesManager::Clear() {
144 Clear(base::Closure());
147 void HttpServerPropertiesManager::Clear(const base::Closure& completion) {
148 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
150 http_server_properties_impl_->Clear();
151 UpdatePrefsFromCacheOnNetworkThread(completion);
154 bool HttpServerPropertiesManager::SupportsRequestPriority(
155 const HostPortPair& server) {
156 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
157 return http_server_properties_impl_->SupportsRequestPriority(server);
160 bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair& server) {
161 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
162 return http_server_properties_impl_->GetSupportsSpdy(server);
165 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair& server,
166 bool support_spdy) {
167 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
169 bool old_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
170 http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
171 bool new_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
172 if (old_support_spdy != new_support_spdy)
173 ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY);
176 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair& server) {
177 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
178 return http_server_properties_impl_->RequiresHTTP11(server);
181 void HttpServerPropertiesManager::SetHTTP11Required(
182 const HostPortPair& server) {
183 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
185 http_server_properties_impl_->SetHTTP11Required(server);
186 ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED);
189 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair& server,
190 SSLConfig* ssl_config) {
191 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
192 http_server_properties_impl_->MaybeForceHTTP11(server, ssl_config);
195 AlternativeServiceVector HttpServerPropertiesManager::GetAlternativeServices(
196 const HostPortPair& origin) {
197 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
198 return http_server_properties_impl_->GetAlternativeServices(origin);
201 bool HttpServerPropertiesManager::SetAlternativeService(
202 const HostPortPair& origin,
203 const AlternativeService& alternative_service,
204 double alternative_probability,
205 base::Time expiration) {
206 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
207 const bool changed = http_server_properties_impl_->SetAlternativeService(
208 origin, alternative_service, alternative_probability, expiration);
209 if (changed) {
210 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
212 return changed;
215 bool HttpServerPropertiesManager::SetAlternativeServices(
216 const HostPortPair& origin,
217 const AlternativeServiceInfoVector& alternative_service_info_vector) {
218 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
219 const bool changed = http_server_properties_impl_->SetAlternativeServices(
220 origin, alternative_service_info_vector);
221 if (changed) {
222 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
224 return changed;
227 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
228 const AlternativeService& alternative_service) {
229 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
230 http_server_properties_impl_->MarkAlternativeServiceBroken(
231 alternative_service);
232 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN);
235 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
236 const AlternativeService& alternative_service) {
237 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
238 http_server_properties_impl_->MarkAlternativeServiceRecentlyBroken(
239 alternative_service);
240 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN);
243 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
244 const AlternativeService& alternative_service) const {
245 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
246 return http_server_properties_impl_->IsAlternativeServiceBroken(
247 alternative_service);
250 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
251 const AlternativeService& alternative_service) {
252 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
253 return http_server_properties_impl_->WasAlternativeServiceRecentlyBroken(
254 alternative_service);
257 void HttpServerPropertiesManager::ConfirmAlternativeService(
258 const AlternativeService& alternative_service) {
259 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
260 bool old_value = http_server_properties_impl_->IsAlternativeServiceBroken(
261 alternative_service);
262 http_server_properties_impl_->ConfirmAlternativeService(alternative_service);
263 bool new_value = http_server_properties_impl_->IsAlternativeServiceBroken(
264 alternative_service);
265 // For persisting, we only care about the value returned by
266 // IsAlternativeServiceBroken. If that value changes, then call persist.
267 if (old_value != new_value)
268 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
271 void HttpServerPropertiesManager::ClearAlternativeServices(
272 const HostPortPair& origin) {
273 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
274 const AlternativeServiceMap& map =
275 http_server_properties_impl_->alternative_service_map();
276 size_t old_size = map.size();
277 http_server_properties_impl_->ClearAlternativeServices(origin);
278 size_t new_size = map.size();
279 // Persist only if we have deleted an entry.
280 if (old_size != new_size)
281 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
284 const AlternativeServiceMap&
285 HttpServerPropertiesManager::alternative_service_map() const {
286 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
287 return http_server_properties_impl_->alternative_service_map();
290 scoped_ptr<base::Value>
291 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
292 const {
293 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
294 return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
297 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
298 double threshold) {
299 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
300 http_server_properties_impl_->SetAlternativeServiceProbabilityThreshold(
301 threshold);
304 const SettingsMap& HttpServerPropertiesManager::GetSpdySettings(
305 const HostPortPair& host_port_pair) {
306 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
307 return http_server_properties_impl_->GetSpdySettings(host_port_pair);
310 bool HttpServerPropertiesManager::SetSpdySetting(
311 const HostPortPair& host_port_pair,
312 SpdySettingsIds id,
313 SpdySettingsFlags flags,
314 uint32 value) {
315 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
316 bool persist = http_server_properties_impl_->SetSpdySetting(
317 host_port_pair, id, flags, value);
318 if (persist)
319 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING);
320 return persist;
323 void HttpServerPropertiesManager::ClearSpdySettings(
324 const HostPortPair& host_port_pair) {
325 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
326 http_server_properties_impl_->ClearSpdySettings(host_port_pair);
327 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS);
330 void HttpServerPropertiesManager::ClearAllSpdySettings() {
331 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
332 http_server_properties_impl_->ClearAllSpdySettings();
333 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS);
336 const SpdySettingsMap& HttpServerPropertiesManager::spdy_settings_map()
337 const {
338 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
339 return http_server_properties_impl_->spdy_settings_map();
342 bool HttpServerPropertiesManager::GetSupportsQuic(
343 IPAddressNumber* last_address) const {
344 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
345 return http_server_properties_impl_->GetSupportsQuic(last_address);
348 void HttpServerPropertiesManager::SetSupportsQuic(
349 bool used_quic,
350 const IPAddressNumber& address) {
351 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
352 IPAddressNumber old_last_quic_addr;
353 http_server_properties_impl_->GetSupportsQuic(&old_last_quic_addr);
354 http_server_properties_impl_->SetSupportsQuic(used_quic, address);
355 IPAddressNumber new_last_quic_addr;
356 http_server_properties_impl_->GetSupportsQuic(&new_last_quic_addr);
357 if (old_last_quic_addr != new_last_quic_addr)
358 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
361 void HttpServerPropertiesManager::SetServerNetworkStats(
362 const HostPortPair& host_port_pair,
363 ServerNetworkStats stats) {
364 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
365 ServerNetworkStats old_stats;
366 const ServerNetworkStats* old_stats_ptr =
367 http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
368 if (http_server_properties_impl_->GetServerNetworkStats(host_port_pair))
369 old_stats = *old_stats_ptr;
370 http_server_properties_impl_->SetServerNetworkStats(host_port_pair, stats);
371 ServerNetworkStats new_stats =
372 *(http_server_properties_impl_->GetServerNetworkStats(host_port_pair));
373 if (old_stats != new_stats)
374 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
377 const ServerNetworkStats* HttpServerPropertiesManager::GetServerNetworkStats(
378 const HostPortPair& host_port_pair) {
379 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
380 return http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
383 const ServerNetworkStatsMap&
384 HttpServerPropertiesManager::server_network_stats_map() const {
385 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
386 return http_server_properties_impl_->server_network_stats_map();
390 // Update the HttpServerPropertiesImpl's cache with data from preferences.
392 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
393 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
394 // Cancel pending updates, if any.
395 pref_cache_update_timer_->Stop();
396 StartCacheUpdateTimerOnPrefThread(
397 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs));
400 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
401 base::TimeDelta delay) {
402 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
403 pref_cache_update_timer_->Start(
404 FROM_HERE,
405 delay,
406 this,
407 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread);
410 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
411 // The preferences can only be read on the pref thread.
412 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
414 if (!pref_service_->HasPrefPath(path_))
415 return;
417 bool detected_corrupted_prefs = false;
418 const base::DictionaryValue& http_server_properties_dict =
419 *pref_service_->GetDictionary(path_);
421 int version = kMissingVersion;
422 if (!http_server_properties_dict.GetIntegerWithoutPathExpansion(kVersionKey,
423 &version)) {
424 DVLOG(1) << "Missing version. Clearing all properties.";
425 return;
428 // The properties for a given server is in
429 // http_server_properties_dict["servers"][server].
430 const base::DictionaryValue* servers_dict = NULL;
431 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
432 kServersKey, &servers_dict)) {
433 DVLOG(1) << "Malformed http_server_properties for servers.";
434 return;
437 IPAddressNumber* addr = new IPAddressNumber;
438 ReadSupportsQuic(http_server_properties_dict, addr);
440 // String is host/port pair of spdy server.
441 scoped_ptr<StringVector> spdy_servers(new StringVector);
442 scoped_ptr<SpdySettingsMap> spdy_settings_map(
443 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist));
444 scoped_ptr<AlternativeServiceMap> alternative_service_map(
445 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist));
446 scoped_ptr<ServerNetworkStatsMap> server_network_stats_map(
447 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist));
449 for (base::DictionaryValue::Iterator it(*servers_dict); !it.IsAtEnd();
450 it.Advance()) {
451 // Get server's host/pair.
452 const std::string& server_str = it.key();
453 HostPortPair server = HostPortPair::FromString(server_str);
454 if (server.host().empty()) {
455 DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
456 detected_corrupted_prefs = true;
457 continue;
460 const base::DictionaryValue* server_pref_dict = NULL;
461 if (!it.value().GetAsDictionary(&server_pref_dict)) {
462 DVLOG(1) << "Malformed http_server_properties server: " << server_str;
463 detected_corrupted_prefs = true;
464 continue;
467 // Get if server supports Spdy.
468 bool supports_spdy = false;
469 if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
470 supports_spdy) {
471 spdy_servers->push_back(server_str);
474 AddToSpdySettingsMap(server, *server_pref_dict, spdy_settings_map.get());
475 if (!AddToAlternativeServiceMap(server, *server_pref_dict,
476 alternative_service_map.get()) ||
477 !AddToNetworkStatsMap(server, *server_pref_dict,
478 server_network_stats_map.get())) {
479 detected_corrupted_prefs = true;
483 network_task_runner_->PostTask(
484 FROM_HERE,
485 base::Bind(
486 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread,
487 base::Unretained(this), base::Owned(spdy_servers.release()),
488 base::Owned(spdy_settings_map.release()),
489 base::Owned(alternative_service_map.release()), base::Owned(addr),
490 base::Owned(server_network_stats_map.release()),
491 detected_corrupted_prefs));
494 void HttpServerPropertiesManager::AddToSpdySettingsMap(
495 const HostPortPair& server,
496 const base::DictionaryValue& server_pref_dict,
497 SpdySettingsMap* spdy_settings_map) {
498 // Get SpdySettings.
499 DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
500 const base::DictionaryValue* spdy_settings_dict = NULL;
501 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
502 kSettingsKey, &spdy_settings_dict)) {
503 return;
505 SettingsMap settings_map;
506 for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
507 !dict_it.IsAtEnd(); dict_it.Advance()) {
508 const std::string& id_str = dict_it.key();
509 int id = 0;
510 if (!base::StringToInt(id_str, &id)) {
511 DVLOG(1) << "Malformed id in SpdySettings for server: "
512 << server.ToString();
513 NOTREACHED();
514 continue;
516 int value = 0;
517 if (!dict_it.value().GetAsInteger(&value)) {
518 DVLOG(1) << "Malformed value in SpdySettings for server: "
519 << server.ToString();
520 NOTREACHED();
521 continue;
523 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
524 settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
526 spdy_settings_map->Put(server, settings_map);
529 bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
530 const base::DictionaryValue& alternative_service_dict,
531 const std::string& server_str,
532 AlternativeServiceInfo* alternative_service_info) {
533 // Protocol is mandatory.
534 std::string protocol_str;
535 if (!alternative_service_dict.GetStringWithoutPathExpansion(kProtocolKey,
536 &protocol_str)) {
537 DVLOG(1) << "Malformed alternative service protocol string for server: "
538 << server_str;
539 return false;
541 AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
542 if (!IsAlternateProtocolValid(protocol)) {
543 DVLOG(1) << "Invalid alternative service protocol string for server: "
544 << server_str;
545 return false;
547 alternative_service_info->alternative_service.protocol = protocol;
549 // Host is optional, defaults to "".
550 alternative_service_info->alternative_service.host.clear();
551 if (alternative_service_dict.HasKey(kHostKey) &&
552 !alternative_service_dict.GetStringWithoutPathExpansion(
553 kHostKey, &(alternative_service_info->alternative_service.host))) {
554 DVLOG(1) << "Malformed alternative service host string for server: "
555 << server_str;
556 return false;
559 // Port is mandatory.
560 int port = 0;
561 if (!alternative_service_dict.GetInteger(kPortKey, &port) ||
562 !IsPortValid(port)) {
563 DVLOG(1) << "Malformed alternative service port for server: " << server_str;
564 return false;
566 alternative_service_info->alternative_service.port =
567 static_cast<uint32>(port);
569 // Probability is optional, defaults to 1.0.
570 alternative_service_info->probability = 1.0;
571 if (alternative_service_dict.HasKey(kProbabilityKey) &&
572 !alternative_service_dict.GetDoubleWithoutPathExpansion(
573 kProbabilityKey, &(alternative_service_info->probability))) {
574 DVLOG(1) << "Malformed alternative service probability for server: "
575 << server_str;
576 return false;
579 // Expiration is optional, defaults to one day.
580 base::Time expiration;
581 if (!alternative_service_dict.HasKey(kExpirationKey)) {
582 alternative_service_info->expiration =
583 base::Time::Now() + base::TimeDelta::FromDays(1);
584 return true;
587 std::string expiration_string;
588 if (alternative_service_dict.GetStringWithoutPathExpansion(
589 kExpirationKey, &expiration_string)) {
590 int64 expiration_int64 = 0;
591 if (!base::StringToInt64(expiration_string, &expiration_int64)) {
592 DVLOG(1) << "Malformed alternative service expiration for server: "
593 << server_str;
594 return false;
596 alternative_service_info->expiration =
597 base::Time::FromInternalValue(expiration_int64);
598 return true;
601 // Early release 46 Dev and Canary versions stored expiration as double.
602 // TODO(bnc) Remove the following code parsing double around 2015-10-01.
603 double expiration_double;
604 if (alternative_service_dict.GetDoubleWithoutPathExpansion(
605 kExpirationKey, &expiration_double)) {
606 alternative_service_info->expiration =
607 base::Time::FromDoubleT(expiration_double);
608 return true;
611 DVLOG(1) << "Malformed alternative service expiration for server: "
612 << server_str;
613 return false;
616 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
617 const HostPortPair& server,
618 const base::DictionaryValue& server_pref_dict,
619 AlternativeServiceMap* alternative_service_map) {
620 DCHECK(alternative_service_map->Peek(server) ==
621 alternative_service_map->end());
622 // Get alternative_services...
623 const base::ListValue* alternative_service_list;
624 const base::DictionaryValue* alternative_service_dict;
625 AlternativeServiceInfoVector alternative_service_info_vector;
626 if (server_pref_dict.GetListWithoutPathExpansion(kAlternativeServiceKey,
627 &alternative_service_list)) {
628 for (const base::Value* alternative_service_list_item :
629 *alternative_service_list) {
630 if (!alternative_service_list_item->GetAsDictionary(
631 &alternative_service_dict))
632 return false;
633 AlternativeServiceInfo alternative_service_info;
634 if (!ParseAlternativeServiceDict(*alternative_service_dict,
635 server.ToString(),
636 &alternative_service_info)) {
637 return false;
639 alternative_service_info_vector.push_back(alternative_service_info);
641 } else {
642 // ...or alternate_protocol.
643 // TODO(bnc): Remove this in M46, we do not need preference migration for
644 // long.
645 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
646 kAlternateProtocolKey, &alternative_service_dict)) {
647 return true;
649 AlternativeServiceInfo alternative_service_info;
650 if (!ParseAlternativeServiceDict(*alternative_service_dict,
651 server.ToString(),
652 &alternative_service_info)) {
653 return false;
655 alternative_service_info_vector.push_back(alternative_service_info);
658 if (alternative_service_info_vector.empty()) {
659 return false;
662 alternative_service_map->Put(server, alternative_service_info_vector);
663 return true;
666 bool HttpServerPropertiesManager::ReadSupportsQuic(
667 const base::DictionaryValue& http_server_properties_dict,
668 IPAddressNumber* last_quic_address) {
669 const base::DictionaryValue* supports_quic_dict = NULL;
670 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
671 kSupportsQuicKey, &supports_quic_dict)) {
672 return true;
674 bool used_quic = false;
675 if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
676 &used_quic)) {
677 DVLOG(1) << "Malformed SupportsQuic";
678 return false;
680 if (!used_quic)
681 return false;
683 std::string address;
684 if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
685 &address) ||
686 !ParseIPLiteralToNumber(address, last_quic_address)) {
687 DVLOG(1) << "Malformed SupportsQuic";
688 return false;
690 return true;
693 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
694 const HostPortPair& server,
695 const base::DictionaryValue& server_pref_dict,
696 ServerNetworkStatsMap* network_stats_map) {
697 DCHECK(network_stats_map->Peek(server) == network_stats_map->end());
698 const base::DictionaryValue* server_network_stats_dict = NULL;
699 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
700 kNetworkStatsKey, &server_network_stats_dict)) {
701 return true;
703 int srtt;
704 if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
705 &srtt)) {
706 DVLOG(1) << "Malformed ServerNetworkStats for server: "
707 << server.ToString();
708 return false;
710 ServerNetworkStats server_network_stats;
711 server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
712 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
713 // bandwidth_estimate.
714 network_stats_map->Put(server, server_network_stats);
715 return true;
718 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
719 StringVector* spdy_servers,
720 SpdySettingsMap* spdy_settings_map,
721 AlternativeServiceMap* alternative_service_map,
722 IPAddressNumber* last_quic_address,
723 ServerNetworkStatsMap* server_network_stats_map,
724 bool detected_corrupted_prefs) {
725 // Preferences have the master data because admins might have pushed new
726 // preferences. Update the cached data with new data from preferences.
727 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
729 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size());
730 http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true);
732 // Update the cached data and use the new spdy_settings from preferences.
733 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size());
734 http_server_properties_impl_->InitializeSpdySettingsServers(
735 spdy_settings_map);
737 // Update the cached data and use the new alternative service list from
738 // preferences.
739 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
740 alternative_service_map->size());
741 http_server_properties_impl_->InitializeAlternativeServiceServers(
742 alternative_service_map);
744 http_server_properties_impl_->InitializeSupportsQuic(last_quic_address);
746 http_server_properties_impl_->InitializeServerNetworkStats(
747 server_network_stats_map);
749 // Update the prefs with what we have read (delete all corrupted prefs).
750 if (detected_corrupted_prefs)
751 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS);
755 // Update Preferences with data from the cached data.
757 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
758 Location location) {
759 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
760 // Cancel pending updates, if any.
761 network_prefs_update_timer_->Stop();
762 StartPrefsUpdateTimerOnNetworkThread(
763 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs));
764 // TODO(rtenneti): Delete the following histogram after collecting some data.
765 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location,
766 HttpServerPropertiesManager::NUM_LOCATIONS);
769 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
770 base::TimeDelta delay) {
771 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
772 // This is overridden in tests to post the task without the delay.
773 network_prefs_update_timer_->Start(
774 FROM_HERE,
775 delay,
776 this,
777 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread);
780 // This is required so we can set this as the callback for a timer.
781 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
782 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
785 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
786 const base::Closure& completion) {
787 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
789 base::ListValue* spdy_server_list = new base::ListValue;
790 http_server_properties_impl_->GetSpdyServerList(
791 spdy_server_list, kMaxSupportsSpdyServerHostsToPersist);
793 SpdySettingsMap* spdy_settings_map =
794 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist);
795 const SpdySettingsMap& main_map =
796 http_server_properties_impl_->spdy_settings_map();
797 int count = 0;
798 for (SpdySettingsMap::const_iterator it = main_map.begin();
799 it != main_map.end() && count < kMaxSpdySettingsHostsToPersist;
800 ++it, ++count) {
801 spdy_settings_map->Put(it->first, it->second);
804 AlternativeServiceMap* alternative_service_map =
805 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist);
806 const AlternativeServiceMap& map =
807 http_server_properties_impl_->alternative_service_map();
808 count = 0;
809 typedef std::map<std::string, bool> CanonicalHostPersistedMap;
810 CanonicalHostPersistedMap persisted_map;
811 for (AlternativeServiceMap::const_iterator it = map.begin();
812 it != map.end() && count < kMaxAlternateProtocolHostsToPersist; ++it) {
813 const HostPortPair& server = it->first;
814 AlternativeServiceInfoVector notbroken_alternative_service_info_vector;
815 for (const AlternativeServiceInfo& alternative_service_info : it->second) {
816 if (!IsAlternateProtocolValid(
817 alternative_service_info.alternative_service.protocol)) {
818 continue;
820 AlternativeService alternative_service(
821 alternative_service_info.alternative_service);
822 if (alternative_service.host.empty()) {
823 alternative_service.host = server.host();
825 if (IsAlternativeServiceBroken(alternative_service)) {
826 continue;
828 notbroken_alternative_service_info_vector.push_back(
829 alternative_service_info);
831 if (notbroken_alternative_service_info_vector.empty()) {
832 continue;
834 alternative_service_map->Put(server,
835 notbroken_alternative_service_info_vector);
836 std::string canonical_suffix =
837 http_server_properties_impl_->GetCanonicalSuffix(server.host());
838 if (!canonical_suffix.empty()) {
839 if (persisted_map.find(canonical_suffix) != persisted_map.end())
840 continue;
841 persisted_map[canonical_suffix] = true;
843 ++count;
846 ServerNetworkStatsMap* server_network_stats_map =
847 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist);
848 const ServerNetworkStatsMap& main_server_network_stats_map =
849 http_server_properties_impl_->server_network_stats_map();
850 for (ServerNetworkStatsMap::const_iterator it =
851 main_server_network_stats_map.begin();
852 it != main_server_network_stats_map.end(); ++it) {
853 server_network_stats_map->Put(it->first, it->second);
856 IPAddressNumber* last_quic_addr = new IPAddressNumber;
857 http_server_properties_impl_->GetSupportsQuic(last_quic_addr);
858 // Update the preferences on the pref thread.
859 pref_task_runner_->PostTask(
860 FROM_HERE,
861 base::Bind(
862 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread, pref_weak_ptr_,
863 base::Owned(spdy_server_list), base::Owned(spdy_settings_map),
864 base::Owned(alternative_service_map), base::Owned(last_quic_addr),
865 base::Owned(server_network_stats_map), completion));
868 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
869 // AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
870 // is used only in UpdatePrefsOnPrefThread.
871 struct ServerPref {
872 ServerPref()
873 : supports_spdy(false),
874 settings_map(NULL),
875 alternative_service_info_vector(NULL),
876 supports_quic(NULL),
877 server_network_stats(NULL) {}
878 ServerPref(
879 bool supports_spdy,
880 const SettingsMap* settings_map,
881 const AlternativeServiceInfoVector* alternative_service_info_vector,
882 const SupportsQuic* supports_quic,
883 const ServerNetworkStats* server_network_stats)
884 : supports_spdy(supports_spdy),
885 settings_map(settings_map),
886 alternative_service_info_vector(alternative_service_info_vector),
887 supports_quic(supports_quic),
888 server_network_stats(server_network_stats) {}
889 bool supports_spdy;
890 const SettingsMap* settings_map;
891 const AlternativeServiceInfoVector* alternative_service_info_vector;
892 const SupportsQuic* supports_quic;
893 const ServerNetworkStats* server_network_stats;
896 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
897 base::ListValue* spdy_server_list,
898 SpdySettingsMap* spdy_settings_map,
899 AlternativeServiceMap* alternative_service_map,
900 IPAddressNumber* last_quic_address,
901 ServerNetworkStatsMap* server_network_stats_map,
902 const base::Closure& completion) {
903 typedef std::map<HostPortPair, ServerPref> ServerPrefMap;
904 ServerPrefMap server_pref_map;
906 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
908 // Add servers that support spdy to server_pref_map.
909 std::string s;
910 for (base::ListValue::const_iterator list_it = spdy_server_list->begin();
911 list_it != spdy_server_list->end();
912 ++list_it) {
913 if ((*list_it)->GetAsString(&s)) {
914 HostPortPair server = HostPortPair::FromString(s);
915 server_pref_map[server].supports_spdy = true;
919 // Add servers that have SpdySettings to server_pref_map.
920 for (SpdySettingsMap::iterator map_it = spdy_settings_map->begin();
921 map_it != spdy_settings_map->end(); ++map_it) {
922 const HostPortPair& server = map_it->first;
923 server_pref_map[server].settings_map = &map_it->second;
926 // Add alternative services to server_pref_map.
927 for (AlternativeServiceMap::const_iterator map_it =
928 alternative_service_map->begin();
929 map_it != alternative_service_map->end(); ++map_it) {
930 server_pref_map[map_it->first].alternative_service_info_vector =
931 &map_it->second;
934 // Add ServerNetworkStats servers to server_pref_map.
935 for (ServerNetworkStatsMap::const_iterator map_it =
936 server_network_stats_map->begin();
937 map_it != server_network_stats_map->end(); ++map_it) {
938 const HostPortPair& server = map_it->first;
939 server_pref_map[server].server_network_stats = &map_it->second;
942 // Persist properties to the |path_|.
943 base::DictionaryValue http_server_properties_dict;
944 base::DictionaryValue* servers_dict = new base::DictionaryValue;
945 for (ServerPrefMap::const_iterator map_it = server_pref_map.begin();
946 map_it != server_pref_map.end();
947 ++map_it) {
948 const HostPortPair& server = map_it->first;
949 const ServerPref& server_pref = map_it->second;
951 base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
953 // Save supports_spdy.
954 if (server_pref.supports_spdy)
955 server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
956 SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
957 SaveAlternativeServiceToServerPrefs(
958 server_pref.alternative_service_info_vector, server_pref_dict);
959 SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
960 server_pref_dict);
962 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
965 http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
966 servers_dict);
967 SetVersion(&http_server_properties_dict, kVersionNumber);
969 SaveSupportsQuicToPrefs(last_quic_address, &http_server_properties_dict);
971 setting_prefs_ = true;
972 pref_service_->Set(path_, http_server_properties_dict);
973 setting_prefs_ = false;
975 // Note that |completion| will be fired after we have written everything to
976 // the Preferences, but likely before these changes are serialized to disk.
977 // This is not a problem though, as JSONPrefStore guarantees that this will
978 // happen, pretty soon, and even in the case we shut down immediately.
979 if (!completion.is_null())
980 completion.Run();
983 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
984 const SettingsMap* settings_map,
985 base::DictionaryValue* server_pref_dict) {
986 if (!settings_map) {
987 return;
989 base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
990 for (SettingsMap::const_iterator it = settings_map->begin();
991 it != settings_map->end(); ++it) {
992 SpdySettingsIds id = it->first;
993 uint32 value = it->second.second;
994 std::string key = base::StringPrintf("%u", id);
995 spdy_settings_dict->SetInteger(key, value);
997 server_pref_dict->SetWithoutPathExpansion(kSettingsKey, spdy_settings_dict);
1000 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
1001 const AlternativeServiceInfoVector* alternative_service_info_vector,
1002 base::DictionaryValue* server_pref_dict) {
1003 if (!alternative_service_info_vector ||
1004 alternative_service_info_vector->empty()) {
1005 return;
1007 scoped_ptr<base::ListValue> alternative_service_list(new base::ListValue);
1008 for (const AlternativeServiceInfo& alternative_service_info :
1009 *alternative_service_info_vector) {
1010 const AlternativeService alternative_service =
1011 alternative_service_info.alternative_service;
1012 DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
1013 base::DictionaryValue* alternative_service_dict = new base::DictionaryValue;
1014 alternative_service_dict->SetInteger(kPortKey, alternative_service.port);
1015 if (!alternative_service.host.empty()) {
1016 alternative_service_dict->SetString(kHostKey, alternative_service.host);
1018 alternative_service_dict->SetString(
1019 kProtocolKey, AlternateProtocolToString(alternative_service.protocol));
1020 alternative_service_dict->SetDouble(kProbabilityKey,
1021 alternative_service_info.probability);
1022 // JSON cannot store int64, so expiration is converted to a string.
1023 alternative_service_dict->SetString(
1024 kExpirationKey,
1025 base::Int64ToString(
1026 alternative_service_info.expiration.ToInternalValue()));
1027 alternative_service_list->Append(alternative_service_dict);
1029 if (alternative_service_list->GetSize() == 0)
1030 return;
1031 server_pref_dict->SetWithoutPathExpansion(kAlternativeServiceKey,
1032 alternative_service_list.release());
1035 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
1036 const IPAddressNumber* last_quic_address,
1037 base::DictionaryValue* http_server_properties_dict) {
1038 if (!last_quic_address || last_quic_address->empty())
1039 return;
1041 base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
1042 supports_quic_dict->SetBoolean(kUsedQuicKey, true);
1043 supports_quic_dict->SetString(kAddressKey,
1044 IPAddressToString(*last_quic_address));
1045 http_server_properties_dict->SetWithoutPathExpansion(kSupportsQuicKey,
1046 supports_quic_dict);
1049 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
1050 const ServerNetworkStats* server_network_stats,
1051 base::DictionaryValue* server_pref_dict) {
1052 if (!server_network_stats)
1053 return;
1055 base::DictionaryValue* server_network_stats_dict = new base::DictionaryValue;
1056 // Becasue JSON doesn't support int64, persist int64 as a string.
1057 server_network_stats_dict->SetInteger(
1058 kSrttKey, static_cast<int>(server_network_stats->srtt.ToInternalValue()));
1059 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
1060 // bandwidth_estimate.
1061 server_pref_dict->SetWithoutPathExpansion(kNetworkStatsKey,
1062 server_network_stats_dict);
1065 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
1066 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
1067 if (!setting_prefs_)
1068 ScheduleUpdateCacheOnPrefThread();
1071 } // namespace net