[Sync] Add tests for bookmark folders on Android.
[chromium-blink-merge.git] / net / http / http_server_properties_manager.cc
blobd89efab5a412aee9ae15de293f17d895750c9616
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"
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 = 60000;
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 bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair& server) {
159 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
160 return http_server_properties_impl_->GetSupportsSpdy(server);
163 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair& server,
164 bool support_spdy) {
165 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
167 bool old_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
168 http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
169 bool new_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
170 if (old_support_spdy != new_support_spdy)
171 ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY);
174 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair& server) {
175 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
176 return http_server_properties_impl_->RequiresHTTP11(server);
179 void HttpServerPropertiesManager::SetHTTP11Required(
180 const HostPortPair& server) {
181 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
183 http_server_properties_impl_->SetHTTP11Required(server);
184 ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED);
187 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair& server,
188 SSLConfig* ssl_config) {
189 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
190 http_server_properties_impl_->MaybeForceHTTP11(server, ssl_config);
193 AlternativeServiceVector HttpServerPropertiesManager::GetAlternativeServices(
194 const HostPortPair& origin) {
195 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
196 return http_server_properties_impl_->GetAlternativeServices(origin);
199 bool HttpServerPropertiesManager::SetAlternativeService(
200 const HostPortPair& origin,
201 const AlternativeService& alternative_service,
202 double alternative_probability) {
203 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
204 const bool changed = http_server_properties_impl_->SetAlternativeService(
205 origin, alternative_service, alternative_probability);
206 if (changed) {
207 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
209 return changed;
212 bool HttpServerPropertiesManager::SetAlternativeServices(
213 const HostPortPair& origin,
214 const AlternativeServiceInfoVector& alternative_service_info_vector) {
215 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
216 const bool changed = http_server_properties_impl_->SetAlternativeServices(
217 origin, alternative_service_info_vector);
218 if (changed) {
219 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
221 return changed;
224 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
225 const AlternativeService& alternative_service) {
226 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
227 http_server_properties_impl_->MarkAlternativeServiceBroken(
228 alternative_service);
229 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN);
232 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
233 const AlternativeService& alternative_service) {
234 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
235 http_server_properties_impl_->MarkAlternativeServiceRecentlyBroken(
236 alternative_service);
237 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN);
240 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
241 const AlternativeService& alternative_service) const {
242 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
243 return http_server_properties_impl_->IsAlternativeServiceBroken(
244 alternative_service);
247 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
248 const AlternativeService& alternative_service) {
249 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
250 return http_server_properties_impl_->WasAlternativeServiceRecentlyBroken(
251 alternative_service);
254 void HttpServerPropertiesManager::ConfirmAlternativeService(
255 const AlternativeService& alternative_service) {
256 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
257 bool old_value = http_server_properties_impl_->IsAlternativeServiceBroken(
258 alternative_service);
259 http_server_properties_impl_->ConfirmAlternativeService(alternative_service);
260 bool new_value = http_server_properties_impl_->IsAlternativeServiceBroken(
261 alternative_service);
262 // For persisting, we only care about the value returned by
263 // IsAlternativeServiceBroken. If that value changes, then call persist.
264 if (old_value != new_value)
265 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
268 void HttpServerPropertiesManager::ClearAlternativeServices(
269 const HostPortPair& origin) {
270 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
271 const AlternativeServiceMap& map =
272 http_server_properties_impl_->alternative_service_map();
273 size_t old_size = map.size();
274 http_server_properties_impl_->ClearAlternativeServices(origin);
275 size_t new_size = map.size();
276 // Persist only if we have deleted an entry.
277 if (old_size != new_size)
278 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
281 const AlternativeServiceMap&
282 HttpServerPropertiesManager::alternative_service_map() const {
283 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
284 return http_server_properties_impl_->alternative_service_map();
287 scoped_ptr<base::Value>
288 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
289 const {
290 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
291 return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
294 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
295 double threshold) {
296 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
297 http_server_properties_impl_->SetAlternativeServiceProbabilityThreshold(
298 threshold);
301 const SettingsMap& HttpServerPropertiesManager::GetSpdySettings(
302 const HostPortPair& host_port_pair) {
303 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
304 return http_server_properties_impl_->GetSpdySettings(host_port_pair);
307 bool HttpServerPropertiesManager::SetSpdySetting(
308 const HostPortPair& host_port_pair,
309 SpdySettingsIds id,
310 SpdySettingsFlags flags,
311 uint32 value) {
312 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
313 bool persist = http_server_properties_impl_->SetSpdySetting(
314 host_port_pair, id, flags, value);
315 if (persist)
316 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING);
317 return persist;
320 void HttpServerPropertiesManager::ClearSpdySettings(
321 const HostPortPair& host_port_pair) {
322 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
323 http_server_properties_impl_->ClearSpdySettings(host_port_pair);
324 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS);
327 void HttpServerPropertiesManager::ClearAllSpdySettings() {
328 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
329 http_server_properties_impl_->ClearAllSpdySettings();
330 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS);
333 const SpdySettingsMap& HttpServerPropertiesManager::spdy_settings_map()
334 const {
335 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
336 return http_server_properties_impl_->spdy_settings_map();
339 bool HttpServerPropertiesManager::GetSupportsQuic(
340 IPAddressNumber* last_address) const {
341 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
342 return http_server_properties_impl_->GetSupportsQuic(last_address);
345 void HttpServerPropertiesManager::SetSupportsQuic(
346 bool used_quic,
347 const IPAddressNumber& address) {
348 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
349 IPAddressNumber old_last_quic_addr;
350 http_server_properties_impl_->GetSupportsQuic(&old_last_quic_addr);
351 http_server_properties_impl_->SetSupportsQuic(used_quic, address);
352 IPAddressNumber new_last_quic_addr;
353 http_server_properties_impl_->GetSupportsQuic(&new_last_quic_addr);
354 if (old_last_quic_addr != new_last_quic_addr)
355 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
358 void HttpServerPropertiesManager::SetServerNetworkStats(
359 const HostPortPair& host_port_pair,
360 ServerNetworkStats stats) {
361 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
362 ServerNetworkStats old_stats;
363 const ServerNetworkStats* old_stats_ptr =
364 http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
365 if (http_server_properties_impl_->GetServerNetworkStats(host_port_pair))
366 old_stats = *old_stats_ptr;
367 http_server_properties_impl_->SetServerNetworkStats(host_port_pair, stats);
368 ServerNetworkStats new_stats =
369 *(http_server_properties_impl_->GetServerNetworkStats(host_port_pair));
370 if (old_stats != new_stats)
371 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
374 const ServerNetworkStats* HttpServerPropertiesManager::GetServerNetworkStats(
375 const HostPortPair& host_port_pair) {
376 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
377 return http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
380 const ServerNetworkStatsMap&
381 HttpServerPropertiesManager::server_network_stats_map() const {
382 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
383 return http_server_properties_impl_->server_network_stats_map();
387 // Update the HttpServerPropertiesImpl's cache with data from preferences.
389 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
390 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
391 // Cancel pending updates, if any.
392 pref_cache_update_timer_->Stop();
393 StartCacheUpdateTimerOnPrefThread(
394 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs));
397 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
398 base::TimeDelta delay) {
399 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
400 pref_cache_update_timer_->Start(
401 FROM_HERE,
402 delay,
403 this,
404 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread);
407 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
408 // The preferences can only be read on the pref thread.
409 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
411 if (!pref_service_->HasPrefPath(path_))
412 return;
414 bool detected_corrupted_prefs = false;
415 const base::DictionaryValue& http_server_properties_dict =
416 *pref_service_->GetDictionary(path_);
418 int version = kMissingVersion;
419 if (!http_server_properties_dict.GetIntegerWithoutPathExpansion(kVersionKey,
420 &version)) {
421 DVLOG(1) << "Missing version. Clearing all properties.";
422 return;
425 // The properties for a given server is in
426 // http_server_properties_dict["servers"][server].
427 const base::DictionaryValue* servers_dict = NULL;
428 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
429 kServersKey, &servers_dict)) {
430 DVLOG(1) << "Malformed http_server_properties for servers.";
431 return;
434 IPAddressNumber* addr = new IPAddressNumber;
435 ReadSupportsQuic(http_server_properties_dict, addr);
437 // String is host/port pair of spdy server.
438 scoped_ptr<StringVector> spdy_servers(new StringVector);
439 scoped_ptr<SpdySettingsMap> spdy_settings_map(
440 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist));
441 scoped_ptr<AlternativeServiceMap> alternative_service_map(
442 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist));
443 scoped_ptr<ServerNetworkStatsMap> server_network_stats_map(
444 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist));
446 for (base::DictionaryValue::Iterator it(*servers_dict); !it.IsAtEnd();
447 it.Advance()) {
448 // Get server's host/pair.
449 const std::string& server_str = it.key();
450 HostPortPair server = HostPortPair::FromString(server_str);
451 if (server.host().empty()) {
452 DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
453 detected_corrupted_prefs = true;
454 continue;
457 const base::DictionaryValue* server_pref_dict = NULL;
458 if (!it.value().GetAsDictionary(&server_pref_dict)) {
459 DVLOG(1) << "Malformed http_server_properties server: " << server_str;
460 detected_corrupted_prefs = true;
461 continue;
464 // Get if server supports Spdy.
465 bool supports_spdy = false;
466 if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
467 supports_spdy) {
468 spdy_servers->push_back(server_str);
471 AddToSpdySettingsMap(server, *server_pref_dict, spdy_settings_map.get());
472 if (!AddToAlternativeServiceMap(server, *server_pref_dict,
473 alternative_service_map.get()) ||
474 !AddToNetworkStatsMap(server, *server_pref_dict,
475 server_network_stats_map.get())) {
476 detected_corrupted_prefs = true;
480 network_task_runner_->PostTask(
481 FROM_HERE,
482 base::Bind(
483 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread,
484 base::Unretained(this), base::Owned(spdy_servers.release()),
485 base::Owned(spdy_settings_map.release()),
486 base::Owned(alternative_service_map.release()), base::Owned(addr),
487 base::Owned(server_network_stats_map.release()),
488 detected_corrupted_prefs));
491 void HttpServerPropertiesManager::AddToSpdySettingsMap(
492 const HostPortPair& server,
493 const base::DictionaryValue& server_pref_dict,
494 SpdySettingsMap* spdy_settings_map) {
495 // Get SpdySettings.
496 DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
497 const base::DictionaryValue* spdy_settings_dict = NULL;
498 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
499 kSettingsKey, &spdy_settings_dict)) {
500 return;
502 SettingsMap settings_map;
503 for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
504 !dict_it.IsAtEnd(); dict_it.Advance()) {
505 const std::string& id_str = dict_it.key();
506 int id = 0;
507 if (!base::StringToInt(id_str, &id)) {
508 DVLOG(1) << "Malformed id in SpdySettings for server: "
509 << server.ToString();
510 NOTREACHED();
511 continue;
513 int value = 0;
514 if (!dict_it.value().GetAsInteger(&value)) {
515 DVLOG(1) << "Malformed value in SpdySettings for server: "
516 << server.ToString();
517 NOTREACHED();
518 continue;
520 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
521 settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
523 spdy_settings_map->Put(server, settings_map);
526 AlternativeServiceInfo HttpServerPropertiesManager::ParseAlternativeServiceDict(
527 const base::DictionaryValue& alternative_service_dict,
528 const std::string& server_str) {
529 // Protocol is mandatory.
530 std::string protocol_str;
531 if (!alternative_service_dict.GetStringWithoutPathExpansion(kProtocolKey,
532 &protocol_str)) {
533 DVLOG(1) << "Malformed alternative service protocol string for server: "
534 << server_str;
535 return AlternativeServiceInfo();
537 AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
538 if (!IsAlternateProtocolValid(protocol)) {
539 DVLOG(1) << "Invalid alternative service protocol string for server: "
540 << server_str;
541 return AlternativeServiceInfo();
544 // Host is optional, defaults to "".
545 std::string host;
546 if (alternative_service_dict.HasKey(kHostKey) &&
547 !alternative_service_dict.GetStringWithoutPathExpansion(kHostKey,
548 &host)) {
549 DVLOG(1) << "Malformed alternative service host string for server: "
550 << server_str;
551 return AlternativeServiceInfo();
554 // Port is mandatory.
555 int port = 0;
556 if (!alternative_service_dict.GetInteger(kPortKey, &port) ||
557 !IsPortValid(port)) {
558 DVLOG(1) << "Malformed alternative service port for server: " << server_str;
559 return AlternativeServiceInfo();
562 // Probability is optional, defaults to 1.0.
563 double probability = 1.0;
564 if (alternative_service_dict.HasKey(kProbabilityKey) &&
565 !alternative_service_dict.GetDoubleWithoutPathExpansion(kProbabilityKey,
566 &probability)) {
567 DVLOG(1) << "Malformed alternative service probability for server: "
568 << server_str;
569 return AlternativeServiceInfo();
572 return AlternativeServiceInfo(protocol, host, static_cast<uint16>(port),
573 probability);
576 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
577 const HostPortPair& server,
578 const base::DictionaryValue& server_pref_dict,
579 AlternativeServiceMap* alternative_service_map) {
580 DCHECK(alternative_service_map->Peek(server) ==
581 alternative_service_map->end());
582 // Get alternative_services...
583 const base::ListValue* alternative_service_list;
584 const base::DictionaryValue* alternative_service_dict;
585 AlternativeServiceInfoVector alternative_service_info_vector;
586 if (server_pref_dict.GetListWithoutPathExpansion(kAlternativeServiceKey,
587 &alternative_service_list)) {
588 for (const base::Value* alternative_service_list_item :
589 *alternative_service_list) {
590 if (!alternative_service_list_item->GetAsDictionary(
591 &alternative_service_dict))
592 return false;
593 AlternativeServiceInfo alternative_service_info =
594 ParseAlternativeServiceDict(*alternative_service_dict,
595 server.ToString());
596 if (alternative_service_info.alternative_service.protocol ==
597 UNINITIALIZED_ALTERNATE_PROTOCOL) {
598 return false;
600 alternative_service_info_vector.push_back(alternative_service_info);
602 } else {
603 // ...or alternate_protocol.
604 // TODO(bnc): Remove this in M46, we do not need preference migration for
605 // long.
606 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
607 kAlternateProtocolKey, &alternative_service_dict)) {
608 return true;
610 AlternativeServiceInfo alternative_service_info =
611 ParseAlternativeServiceDict(*alternative_service_dict,
612 server.ToString());
613 if (alternative_service_info.alternative_service.protocol ==
614 UNINITIALIZED_ALTERNATE_PROTOCOL) {
615 return false;
617 alternative_service_info_vector.push_back(alternative_service_info);
620 if (alternative_service_info_vector.empty()) {
621 return false;
624 alternative_service_map->Put(server, alternative_service_info_vector);
625 return true;
628 bool HttpServerPropertiesManager::ReadSupportsQuic(
629 const base::DictionaryValue& http_server_properties_dict,
630 IPAddressNumber* last_quic_address) {
631 const base::DictionaryValue* supports_quic_dict = NULL;
632 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
633 kSupportsQuicKey, &supports_quic_dict)) {
634 return true;
636 bool used_quic = false;
637 if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
638 &used_quic)) {
639 DVLOG(1) << "Malformed SupportsQuic";
640 return false;
642 if (!used_quic)
643 return false;
645 std::string address;
646 if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
647 &address) ||
648 !ParseIPLiteralToNumber(address, last_quic_address)) {
649 DVLOG(1) << "Malformed SupportsQuic";
650 return false;
652 return true;
655 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
656 const HostPortPair& server,
657 const base::DictionaryValue& server_pref_dict,
658 ServerNetworkStatsMap* network_stats_map) {
659 DCHECK(network_stats_map->Peek(server) == network_stats_map->end());
660 const base::DictionaryValue* server_network_stats_dict = NULL;
661 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
662 kNetworkStatsKey, &server_network_stats_dict)) {
663 return true;
665 int srtt;
666 if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
667 &srtt)) {
668 DVLOG(1) << "Malformed ServerNetworkStats for server: "
669 << server.ToString();
670 return false;
672 ServerNetworkStats server_network_stats;
673 server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
674 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
675 // bandwidth_estimate.
676 network_stats_map->Put(server, server_network_stats);
677 return true;
680 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
681 StringVector* spdy_servers,
682 SpdySettingsMap* spdy_settings_map,
683 AlternativeServiceMap* alternative_service_map,
684 IPAddressNumber* last_quic_address,
685 ServerNetworkStatsMap* server_network_stats_map,
686 bool detected_corrupted_prefs) {
687 // Preferences have the master data because admins might have pushed new
688 // preferences. Update the cached data with new data from preferences.
689 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
691 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size());
692 http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true);
694 // Update the cached data and use the new spdy_settings from preferences.
695 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size());
696 http_server_properties_impl_->InitializeSpdySettingsServers(
697 spdy_settings_map);
699 // Update the cached data and use the new alternative service list from
700 // preferences.
701 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
702 alternative_service_map->size());
703 http_server_properties_impl_->InitializeAlternativeServiceServers(
704 alternative_service_map);
706 http_server_properties_impl_->InitializeSupportsQuic(last_quic_address);
708 http_server_properties_impl_->InitializeServerNetworkStats(
709 server_network_stats_map);
711 // Update the prefs with what we have read (delete all corrupted prefs).
712 if (detected_corrupted_prefs)
713 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS);
717 // Update Preferences with data from the cached data.
719 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
720 Location location) {
721 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
722 // Cancel pending updates, if any.
723 network_prefs_update_timer_->Stop();
724 StartPrefsUpdateTimerOnNetworkThread(
725 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs));
726 // TODO(rtenneti): Delete the following histogram after collecting some data.
727 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location,
728 HttpServerPropertiesManager::NUM_LOCATIONS);
731 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
732 base::TimeDelta delay) {
733 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
734 // This is overridden in tests to post the task without the delay.
735 network_prefs_update_timer_->Start(
736 FROM_HERE,
737 delay,
738 this,
739 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread);
742 // This is required so we can set this as the callback for a timer.
743 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
744 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
747 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
748 const base::Closure& completion) {
749 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
751 base::ListValue* spdy_server_list = new base::ListValue;
752 http_server_properties_impl_->GetSpdyServerList(
753 spdy_server_list, kMaxSupportsSpdyServerHostsToPersist);
755 SpdySettingsMap* spdy_settings_map =
756 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist);
757 const SpdySettingsMap& main_map =
758 http_server_properties_impl_->spdy_settings_map();
759 int count = 0;
760 for (SpdySettingsMap::const_iterator it = main_map.begin();
761 it != main_map.end() && count < kMaxSpdySettingsHostsToPersist;
762 ++it, ++count) {
763 spdy_settings_map->Put(it->first, it->second);
766 AlternativeServiceMap* alternative_service_map =
767 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist);
768 const AlternativeServiceMap& map =
769 http_server_properties_impl_->alternative_service_map();
770 count = 0;
771 typedef std::map<std::string, bool> CanonicalHostPersistedMap;
772 CanonicalHostPersistedMap persisted_map;
773 for (AlternativeServiceMap::const_iterator it = map.begin();
774 it != map.end() && count < kMaxAlternateProtocolHostsToPersist; ++it) {
775 const HostPortPair& server = it->first;
776 AlternativeServiceInfoVector notbroken_alternative_service_info_vector;
777 for (const AlternativeServiceInfo& alternative_service_info : it->second) {
778 if (!IsAlternateProtocolValid(
779 alternative_service_info.alternative_service.protocol)) {
780 continue;
782 AlternativeService alternative_service(
783 alternative_service_info.alternative_service);
784 if (alternative_service.host.empty()) {
785 alternative_service.host = server.host();
787 if (IsAlternativeServiceBroken(alternative_service)) {
788 continue;
790 notbroken_alternative_service_info_vector.push_back(
791 alternative_service_info);
793 if (notbroken_alternative_service_info_vector.empty()) {
794 continue;
796 alternative_service_map->Put(server,
797 notbroken_alternative_service_info_vector);
798 std::string canonical_suffix =
799 http_server_properties_impl_->GetCanonicalSuffix(server.host());
800 if (!canonical_suffix.empty()) {
801 if (persisted_map.find(canonical_suffix) != persisted_map.end())
802 continue;
803 persisted_map[canonical_suffix] = true;
805 ++count;
808 ServerNetworkStatsMap* server_network_stats_map =
809 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist);
810 const ServerNetworkStatsMap& main_server_network_stats_map =
811 http_server_properties_impl_->server_network_stats_map();
812 for (ServerNetworkStatsMap::const_iterator it =
813 main_server_network_stats_map.begin();
814 it != main_server_network_stats_map.end(); ++it) {
815 server_network_stats_map->Put(it->first, it->second);
818 IPAddressNumber* last_quic_addr = new IPAddressNumber;
819 http_server_properties_impl_->GetSupportsQuic(last_quic_addr);
820 // Update the preferences on the pref thread.
821 pref_task_runner_->PostTask(
822 FROM_HERE,
823 base::Bind(
824 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread, pref_weak_ptr_,
825 base::Owned(spdy_server_list), base::Owned(spdy_settings_map),
826 base::Owned(alternative_service_map), base::Owned(last_quic_addr),
827 base::Owned(server_network_stats_map), completion));
830 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
831 // AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
832 // is used only in UpdatePrefsOnPrefThread.
833 struct ServerPref {
834 ServerPref()
835 : supports_spdy(false),
836 settings_map(NULL),
837 alternative_service_info_vector(NULL),
838 supports_quic(NULL),
839 server_network_stats(NULL) {}
840 ServerPref(
841 bool supports_spdy,
842 const SettingsMap* settings_map,
843 const AlternativeServiceInfoVector* alternative_service_info_vector,
844 const SupportsQuic* supports_quic,
845 const ServerNetworkStats* server_network_stats)
846 : supports_spdy(supports_spdy),
847 settings_map(settings_map),
848 alternative_service_info_vector(alternative_service_info_vector),
849 supports_quic(supports_quic),
850 server_network_stats(server_network_stats) {}
851 bool supports_spdy;
852 const SettingsMap* settings_map;
853 const AlternativeServiceInfoVector* alternative_service_info_vector;
854 const SupportsQuic* supports_quic;
855 const ServerNetworkStats* server_network_stats;
858 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
859 base::ListValue* spdy_server_list,
860 SpdySettingsMap* spdy_settings_map,
861 AlternativeServiceMap* alternative_service_map,
862 IPAddressNumber* last_quic_address,
863 ServerNetworkStatsMap* server_network_stats_map,
864 const base::Closure& completion) {
865 typedef std::map<HostPortPair, ServerPref> ServerPrefMap;
866 ServerPrefMap server_pref_map;
868 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
870 // Add servers that support spdy to server_pref_map.
871 std::string s;
872 for (base::ListValue::const_iterator list_it = spdy_server_list->begin();
873 list_it != spdy_server_list->end();
874 ++list_it) {
875 if ((*list_it)->GetAsString(&s)) {
876 HostPortPair server = HostPortPair::FromString(s);
877 server_pref_map[server].supports_spdy = true;
881 // Add servers that have SpdySettings to server_pref_map.
882 for (SpdySettingsMap::iterator map_it = spdy_settings_map->begin();
883 map_it != spdy_settings_map->end(); ++map_it) {
884 const HostPortPair& server = map_it->first;
885 server_pref_map[server].settings_map = &map_it->second;
888 // Add alternative services to server_pref_map.
889 for (AlternativeServiceMap::const_iterator map_it =
890 alternative_service_map->begin();
891 map_it != alternative_service_map->end(); ++map_it) {
892 server_pref_map[map_it->first].alternative_service_info_vector =
893 &map_it->second;
896 // Add ServerNetworkStats servers to server_pref_map.
897 for (ServerNetworkStatsMap::const_iterator map_it =
898 server_network_stats_map->begin();
899 map_it != server_network_stats_map->end(); ++map_it) {
900 const HostPortPair& server = map_it->first;
901 server_pref_map[server].server_network_stats = &map_it->second;
904 // Persist properties to the |path_|.
905 base::DictionaryValue http_server_properties_dict;
906 base::DictionaryValue* servers_dict = new base::DictionaryValue;
907 for (ServerPrefMap::const_iterator map_it = server_pref_map.begin();
908 map_it != server_pref_map.end();
909 ++map_it) {
910 const HostPortPair& server = map_it->first;
911 const ServerPref& server_pref = map_it->second;
913 base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
915 // Save supports_spdy.
916 if (server_pref.supports_spdy)
917 server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
918 SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
919 SaveAlternativeServiceToServerPrefs(
920 server_pref.alternative_service_info_vector, server_pref_dict);
921 SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
922 server_pref_dict);
924 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
927 http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
928 servers_dict);
929 SetVersion(&http_server_properties_dict, kVersionNumber);
931 SaveSupportsQuicToPrefs(last_quic_address, &http_server_properties_dict);
933 setting_prefs_ = true;
934 pref_service_->Set(path_, http_server_properties_dict);
935 setting_prefs_ = false;
937 // Note that |completion| will be fired after we have written everything to
938 // the Preferences, but likely before these changes are serialized to disk.
939 // This is not a problem though, as JSONPrefStore guarantees that this will
940 // happen, pretty soon, and even in the case we shut down immediately.
941 if (!completion.is_null())
942 completion.Run();
945 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
946 const SettingsMap* settings_map,
947 base::DictionaryValue* server_pref_dict) {
948 if (!settings_map) {
949 return;
951 base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
952 for (SettingsMap::const_iterator it = settings_map->begin();
953 it != settings_map->end(); ++it) {
954 SpdySettingsIds id = it->first;
955 uint32 value = it->second.second;
956 std::string key = base::StringPrintf("%u", id);
957 spdy_settings_dict->SetInteger(key, value);
959 server_pref_dict->SetWithoutPathExpansion(kSettingsKey, spdy_settings_dict);
962 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
963 const AlternativeServiceInfoVector* alternative_service_info_vector,
964 base::DictionaryValue* server_pref_dict) {
965 if (!alternative_service_info_vector ||
966 alternative_service_info_vector->empty()) {
967 return;
969 scoped_ptr<base::ListValue> alternative_service_list(new base::ListValue);
970 for (const AlternativeServiceInfo& alternative_service_info :
971 *alternative_service_info_vector) {
972 const AlternativeService alternative_service =
973 alternative_service_info.alternative_service;
974 DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
975 base::DictionaryValue* alternative_service_dict = new base::DictionaryValue;
976 alternative_service_dict->SetInteger(kPortKey, alternative_service.port);
977 if (!alternative_service.host.empty()) {
978 alternative_service_dict->SetString(kHostKey, alternative_service.host);
980 alternative_service_dict->SetString(
981 kProtocolKey, AlternateProtocolToString(alternative_service.protocol));
982 alternative_service_dict->SetDouble(kProbabilityKey,
983 alternative_service_info.probability);
984 alternative_service_list->Append(alternative_service_dict);
986 if (alternative_service_list->GetSize() == 0)
987 return;
988 server_pref_dict->SetWithoutPathExpansion(kAlternativeServiceKey,
989 alternative_service_list.release());
992 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
993 const IPAddressNumber* last_quic_address,
994 base::DictionaryValue* http_server_properties_dict) {
995 if (!last_quic_address || last_quic_address->empty())
996 return;
998 base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
999 supports_quic_dict->SetBoolean(kUsedQuicKey, true);
1000 supports_quic_dict->SetString(kAddressKey,
1001 IPAddressToString(*last_quic_address));
1002 http_server_properties_dict->SetWithoutPathExpansion(kSupportsQuicKey,
1003 supports_quic_dict);
1006 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
1007 const ServerNetworkStats* server_network_stats,
1008 base::DictionaryValue* server_pref_dict) {
1009 if (!server_network_stats)
1010 return;
1012 base::DictionaryValue* server_network_stats_dict = new base::DictionaryValue;
1013 // Becasue JSON doesn't support int64, persist int64 as a string.
1014 server_network_stats_dict->SetInteger(
1015 kSrttKey, static_cast<int>(server_network_stats->srtt.ToInternalValue()));
1016 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
1017 // bandwidth_estimate.
1018 server_pref_dict->SetWithoutPathExpansion(kNetworkStatsKey,
1019 server_network_stats_dict);
1022 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
1023 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
1024 if (!setting_prefs_)
1025 ScheduleUpdateCacheOnPrefThread();
1028 } // namespace net