Roll src/third_party/WebKit 6cdd902:94953d6 (svn 197985:197991)
[chromium-blink-merge.git] / net / http / http_server_properties_manager.cc
blobffbec0054536f8e89129824f7cddd33c6af3eecf
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 AlternativeService HttpServerPropertiesManager::GetAlternativeService(
194 const HostPortPair& origin) {
195 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
196 return http_server_properties_impl_->GetAlternativeService(origin);
199 void HttpServerPropertiesManager::SetAlternativeService(
200 const HostPortPair& origin,
201 const AlternativeService& alternative_service,
202 double alternative_probability) {
203 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
204 AlternativeService old_alternative_service = GetAlternativeService(origin);
205 http_server_properties_impl_->SetAlternativeService(
206 origin, alternative_service, alternative_probability);
207 AlternativeService new_alternative_service = GetAlternativeService(origin);
208 // If |alternative_probability| was above the threashold now it is below or
209 // vice versa, then a different alternative_service will be returned from the
210 // old and if so, then persist.
211 if (old_alternative_service != new_alternative_service)
212 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICE);
215 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
216 const AlternativeService& alternative_service) {
217 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
218 http_server_properties_impl_->MarkAlternativeServiceBroken(
219 alternative_service);
220 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN);
223 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
224 const AlternativeService& alternative_service) {
225 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
226 http_server_properties_impl_->MarkAlternativeServiceRecentlyBroken(
227 alternative_service);
228 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN);
231 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
232 const AlternativeService& alternative_service) const {
233 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
234 return http_server_properties_impl_->IsAlternativeServiceBroken(
235 alternative_service);
238 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
239 const AlternativeService& alternative_service) {
240 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
241 return http_server_properties_impl_->WasAlternativeServiceRecentlyBroken(
242 alternative_service);
245 void HttpServerPropertiesManager::ConfirmAlternativeService(
246 const AlternativeService& alternative_service) {
247 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
248 bool old_value = http_server_properties_impl_->IsAlternativeServiceBroken(
249 alternative_service);
250 http_server_properties_impl_->ConfirmAlternativeService(alternative_service);
251 bool new_value = http_server_properties_impl_->IsAlternativeServiceBroken(
252 alternative_service);
253 // For persisting, we only care about the value returned by
254 // IsAlternativeServiceBroken. If that value changes, then call persist.
255 if (old_value != new_value)
256 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
259 void HttpServerPropertiesManager::ClearAlternativeService(
260 const HostPortPair& origin) {
261 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
262 const AlternativeServiceMap& map =
263 http_server_properties_impl_->alternative_service_map();
264 size_t old_size = map.size();
265 http_server_properties_impl_->ClearAlternativeService(origin);
266 size_t new_size = map.size();
267 // Persist only if we have deleted an entry.
268 if (old_size != new_size)
269 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
272 const AlternativeServiceMap&
273 HttpServerPropertiesManager::alternative_service_map() const {
274 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
275 return http_server_properties_impl_->alternative_service_map();
278 scoped_ptr<base::Value>
279 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
280 const {
281 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
282 return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
285 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
286 double threshold) {
287 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
288 http_server_properties_impl_->SetAlternativeServiceProbabilityThreshold(
289 threshold);
292 const SettingsMap& HttpServerPropertiesManager::GetSpdySettings(
293 const HostPortPair& host_port_pair) {
294 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
295 return http_server_properties_impl_->GetSpdySettings(host_port_pair);
298 bool HttpServerPropertiesManager::SetSpdySetting(
299 const HostPortPair& host_port_pair,
300 SpdySettingsIds id,
301 SpdySettingsFlags flags,
302 uint32 value) {
303 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
304 bool persist = http_server_properties_impl_->SetSpdySetting(
305 host_port_pair, id, flags, value);
306 if (persist)
307 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING);
308 return persist;
311 void HttpServerPropertiesManager::ClearSpdySettings(
312 const HostPortPair& host_port_pair) {
313 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
314 http_server_properties_impl_->ClearSpdySettings(host_port_pair);
315 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS);
318 void HttpServerPropertiesManager::ClearAllSpdySettings() {
319 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
320 http_server_properties_impl_->ClearAllSpdySettings();
321 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS);
324 const SpdySettingsMap& HttpServerPropertiesManager::spdy_settings_map()
325 const {
326 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
327 return http_server_properties_impl_->spdy_settings_map();
330 bool HttpServerPropertiesManager::GetSupportsQuic(
331 IPAddressNumber* last_address) const {
332 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
333 return http_server_properties_impl_->GetSupportsQuic(last_address);
336 void HttpServerPropertiesManager::SetSupportsQuic(
337 bool used_quic,
338 const IPAddressNumber& address) {
339 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
340 IPAddressNumber old_last_quic_addr;
341 http_server_properties_impl_->GetSupportsQuic(&old_last_quic_addr);
342 http_server_properties_impl_->SetSupportsQuic(used_quic, address);
343 IPAddressNumber new_last_quic_addr;
344 http_server_properties_impl_->GetSupportsQuic(&new_last_quic_addr);
345 if (old_last_quic_addr != new_last_quic_addr)
346 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
349 void HttpServerPropertiesManager::SetServerNetworkStats(
350 const HostPortPair& host_port_pair,
351 ServerNetworkStats stats) {
352 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
353 ServerNetworkStats old_stats;
354 const ServerNetworkStats* old_stats_ptr =
355 http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
356 if (http_server_properties_impl_->GetServerNetworkStats(host_port_pair))
357 old_stats = *old_stats_ptr;
358 http_server_properties_impl_->SetServerNetworkStats(host_port_pair, stats);
359 ServerNetworkStats new_stats =
360 *(http_server_properties_impl_->GetServerNetworkStats(host_port_pair));
361 if (old_stats != new_stats)
362 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
365 const ServerNetworkStats* HttpServerPropertiesManager::GetServerNetworkStats(
366 const HostPortPair& host_port_pair) {
367 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
368 return http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
371 const ServerNetworkStatsMap&
372 HttpServerPropertiesManager::server_network_stats_map() const {
373 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
374 return http_server_properties_impl_->server_network_stats_map();
378 // Update the HttpServerPropertiesImpl's cache with data from preferences.
380 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
381 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
382 // Cancel pending updates, if any.
383 pref_cache_update_timer_->Stop();
384 StartCacheUpdateTimerOnPrefThread(
385 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs));
388 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
389 base::TimeDelta delay) {
390 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
391 pref_cache_update_timer_->Start(
392 FROM_HERE,
393 delay,
394 this,
395 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread);
398 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
399 // The preferences can only be read on the pref thread.
400 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
402 if (!pref_service_->HasPrefPath(path_))
403 return;
405 bool detected_corrupted_prefs = false;
406 const base::DictionaryValue& http_server_properties_dict =
407 *pref_service_->GetDictionary(path_);
409 int version = kMissingVersion;
410 if (!http_server_properties_dict.GetIntegerWithoutPathExpansion(kVersionKey,
411 &version)) {
412 DVLOG(1) << "Missing version. Clearing all properties.";
413 return;
416 // The properties for a given server is in
417 // http_server_properties_dict["servers"][server].
418 const base::DictionaryValue* servers_dict = NULL;
419 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
420 kServersKey, &servers_dict)) {
421 DVLOG(1) << "Malformed http_server_properties for servers.";
422 return;
425 IPAddressNumber* addr = new IPAddressNumber;
426 ReadSupportsQuic(http_server_properties_dict, addr);
428 // String is host/port pair of spdy server.
429 scoped_ptr<StringVector> spdy_servers(new StringVector);
430 scoped_ptr<SpdySettingsMap> spdy_settings_map(
431 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist));
432 scoped_ptr<AlternativeServiceMap> alternative_service_map(
433 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist));
434 scoped_ptr<ServerNetworkStatsMap> server_network_stats_map(
435 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist));
437 for (base::DictionaryValue::Iterator it(*servers_dict); !it.IsAtEnd();
438 it.Advance()) {
439 // Get server's host/pair.
440 const std::string& server_str = it.key();
441 HostPortPair server = HostPortPair::FromString(server_str);
442 if (server.host().empty()) {
443 DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
444 detected_corrupted_prefs = true;
445 continue;
448 const base::DictionaryValue* server_pref_dict = NULL;
449 if (!it.value().GetAsDictionary(&server_pref_dict)) {
450 DVLOG(1) << "Malformed http_server_properties server: " << server_str;
451 detected_corrupted_prefs = true;
452 continue;
455 // Get if server supports Spdy.
456 bool supports_spdy = false;
457 if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
458 supports_spdy) {
459 spdy_servers->push_back(server_str);
462 AddToSpdySettingsMap(server, *server_pref_dict, spdy_settings_map.get());
463 if (!AddToAlternativeServiceMap(server, *server_pref_dict,
464 alternative_service_map.get()) ||
465 !AddToNetworkStatsMap(server, *server_pref_dict,
466 server_network_stats_map.get())) {
467 detected_corrupted_prefs = true;
471 network_task_runner_->PostTask(
472 FROM_HERE,
473 base::Bind(
474 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread,
475 base::Unretained(this), base::Owned(spdy_servers.release()),
476 base::Owned(spdy_settings_map.release()),
477 base::Owned(alternative_service_map.release()), base::Owned(addr),
478 base::Owned(server_network_stats_map.release()),
479 detected_corrupted_prefs));
482 void HttpServerPropertiesManager::AddToSpdySettingsMap(
483 const HostPortPair& server,
484 const base::DictionaryValue& server_pref_dict,
485 SpdySettingsMap* spdy_settings_map) {
486 // Get SpdySettings.
487 DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
488 const base::DictionaryValue* spdy_settings_dict = NULL;
489 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
490 kSettingsKey, &spdy_settings_dict)) {
491 return;
493 SettingsMap settings_map;
494 for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
495 !dict_it.IsAtEnd(); dict_it.Advance()) {
496 const std::string& id_str = dict_it.key();
497 int id = 0;
498 if (!base::StringToInt(id_str, &id)) {
499 DVLOG(1) << "Malformed id in SpdySettings for server: "
500 << server.ToString();
501 NOTREACHED();
502 continue;
504 int value = 0;
505 if (!dict_it.value().GetAsInteger(&value)) {
506 DVLOG(1) << "Malformed value in SpdySettings for server: "
507 << server.ToString();
508 NOTREACHED();
509 continue;
511 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
512 settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
514 spdy_settings_map->Put(server, settings_map);
517 AlternativeServiceInfo HttpServerPropertiesManager::ParseAlternativeServiceDict(
518 const base::DictionaryValue& alternative_service_dict,
519 const std::string& server_str) {
520 // Protocol is mandatory.
521 std::string protocol_str;
522 if (!alternative_service_dict.GetStringWithoutPathExpansion(kProtocolKey,
523 &protocol_str)) {
524 DVLOG(1) << "Malformed alternative service protocol string for server: "
525 << server_str;
526 return AlternativeServiceInfo();
528 AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
529 if (!IsAlternateProtocolValid(protocol)) {
530 DVLOG(1) << "Invalid alternative service protocol string for server: "
531 << server_str;
532 return AlternativeServiceInfo();
535 // Host is optional, defaults to "".
536 std::string host;
537 if (alternative_service_dict.HasKey(kHostKey) &&
538 !alternative_service_dict.GetStringWithoutPathExpansion(kHostKey,
539 &host)) {
540 DVLOG(1) << "Malformed alternative service host string for server: "
541 << server_str;
542 return AlternativeServiceInfo();
545 // Port is mandatory.
546 int port = 0;
547 if (!alternative_service_dict.GetInteger(kPortKey, &port) ||
548 !IsPortValid(port)) {
549 DVLOG(1) << "Malformed alternative service port for server: " << server_str;
550 return AlternativeServiceInfo();
553 // Probability is optional, defaults to 1.0.
554 double probability = 1.0;
555 if (alternative_service_dict.HasKey(kProbabilityKey) &&
556 !alternative_service_dict.GetDoubleWithoutPathExpansion(kProbabilityKey,
557 &probability)) {
558 DVLOG(1) << "Malformed alternative service probability for server: "
559 << server_str;
560 return AlternativeServiceInfo();
563 return AlternativeServiceInfo(protocol, host, static_cast<uint16>(port),
564 probability);
567 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
568 const HostPortPair& server,
569 const base::DictionaryValue& server_pref_dict,
570 AlternativeServiceMap* alternative_service_map) {
571 DCHECK(alternative_service_map->Peek(server) ==
572 alternative_service_map->end());
573 // Get alternative_services...
574 const base::ListValue* alternative_service_list;
575 const base::DictionaryValue* alternative_service_dict;
576 AlternativeServiceInfo alternative_service_info;
577 if (server_pref_dict.GetListWithoutPathExpansion(kAlternativeServiceKey,
578 &alternative_service_list)) {
579 if (alternative_service_list->empty()) {
580 return false;
582 // Get first element of the list.
583 // TODO(bnc): Once we store multiple AlternativeServiceInfo per server, read
584 // all of them.
585 if (!alternative_service_list->GetDictionary(0,
586 &alternative_service_dict)) {
587 return false;
589 alternative_service_info = ParseAlternativeServiceDict(
590 *alternative_service_dict, server.ToString());
591 } else {
592 // ...or alternate_protocol.
593 // TODO(bnc): Remove this in M46, we do not need preference migration for
594 // long.
595 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
596 kAlternateProtocolKey, &alternative_service_dict)) {
597 return true;
599 alternative_service_info = ParseAlternativeServiceDict(
600 *alternative_service_dict, server.ToString());
603 if (alternative_service_info.alternative_service.protocol ==
604 UNINITIALIZED_ALTERNATE_PROTOCOL) {
605 return false;
607 alternative_service_map->Put(server, alternative_service_info);
608 return true;
611 bool HttpServerPropertiesManager::ReadSupportsQuic(
612 const base::DictionaryValue& http_server_properties_dict,
613 IPAddressNumber* last_quic_address) {
614 const base::DictionaryValue* supports_quic_dict = NULL;
615 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
616 kSupportsQuicKey, &supports_quic_dict)) {
617 return true;
619 bool used_quic = false;
620 if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
621 &used_quic)) {
622 DVLOG(1) << "Malformed SupportsQuic";
623 return false;
625 if (!used_quic)
626 return false;
628 std::string address;
629 if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
630 &address) ||
631 !ParseIPLiteralToNumber(address, last_quic_address)) {
632 DVLOG(1) << "Malformed SupportsQuic";
633 return false;
635 return true;
638 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
639 const HostPortPair& server,
640 const base::DictionaryValue& server_pref_dict,
641 ServerNetworkStatsMap* network_stats_map) {
642 DCHECK(network_stats_map->Peek(server) == network_stats_map->end());
643 const base::DictionaryValue* server_network_stats_dict = NULL;
644 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
645 kNetworkStatsKey, &server_network_stats_dict)) {
646 return true;
648 int srtt;
649 if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
650 &srtt)) {
651 DVLOG(1) << "Malformed ServerNetworkStats for server: "
652 << server.ToString();
653 return false;
655 ServerNetworkStats server_network_stats;
656 server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
657 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
658 // bandwidth_estimate.
659 network_stats_map->Put(server, server_network_stats);
660 return true;
663 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
664 StringVector* spdy_servers,
665 SpdySettingsMap* spdy_settings_map,
666 AlternativeServiceMap* alternative_service_map,
667 IPAddressNumber* last_quic_address,
668 ServerNetworkStatsMap* server_network_stats_map,
669 bool detected_corrupted_prefs) {
670 // Preferences have the master data because admins might have pushed new
671 // preferences. Update the cached data with new data from preferences.
672 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
674 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size());
675 http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true);
677 // Update the cached data and use the new spdy_settings from preferences.
678 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size());
679 http_server_properties_impl_->InitializeSpdySettingsServers(
680 spdy_settings_map);
682 // Update the cached data and use the new Alternate-Protocol server list from
683 // preferences.
684 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
685 alternative_service_map->size());
686 http_server_properties_impl_->InitializeAlternativeServiceServers(
687 alternative_service_map);
689 http_server_properties_impl_->InitializeSupportsQuic(last_quic_address);
691 http_server_properties_impl_->InitializeServerNetworkStats(
692 server_network_stats_map);
694 // Update the prefs with what we have read (delete all corrupted prefs).
695 if (detected_corrupted_prefs)
696 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS);
700 // Update Preferences with data from the cached data.
702 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
703 Location location) {
704 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
705 // Cancel pending updates, if any.
706 network_prefs_update_timer_->Stop();
707 StartPrefsUpdateTimerOnNetworkThread(
708 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs));
709 // TODO(rtenneti): Delete the following histogram after collecting some data.
710 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location,
711 HttpServerPropertiesManager::NUM_LOCATIONS);
714 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
715 base::TimeDelta delay) {
716 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
717 // This is overridden in tests to post the task without the delay.
718 network_prefs_update_timer_->Start(
719 FROM_HERE,
720 delay,
721 this,
722 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread);
725 // This is required so we can set this as the callback for a timer.
726 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
727 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
730 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
731 const base::Closure& completion) {
732 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
734 base::ListValue* spdy_server_list = new base::ListValue;
735 http_server_properties_impl_->GetSpdyServerList(
736 spdy_server_list, kMaxSupportsSpdyServerHostsToPersist);
738 SpdySettingsMap* spdy_settings_map =
739 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist);
740 const SpdySettingsMap& main_map =
741 http_server_properties_impl_->spdy_settings_map();
742 int count = 0;
743 for (SpdySettingsMap::const_iterator it = main_map.begin();
744 it != main_map.end() && count < kMaxSpdySettingsHostsToPersist;
745 ++it, ++count) {
746 spdy_settings_map->Put(it->first, it->second);
749 AlternativeServiceMap* alternative_service_map =
750 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist);
751 const AlternativeServiceMap& map =
752 http_server_properties_impl_->alternative_service_map();
753 count = 0;
754 typedef std::map<std::string, bool> CanonicalHostPersistedMap;
755 CanonicalHostPersistedMap persisted_map;
756 for (AlternativeServiceMap::const_iterator it = map.begin();
757 it != map.end() && count < kMaxAlternateProtocolHostsToPersist; ++it) {
758 const AlternativeServiceInfo& alternative_service_info = it->second;
759 if (!IsAlternateProtocolValid(
760 alternative_service_info.alternative_service.protocol)) {
761 continue;
763 const HostPortPair& server = it->first;
764 AlternativeService alternative_service(
765 alternative_service_info.alternative_service);
766 if (alternative_service.host.empty()) {
767 alternative_service.host = server.host();
769 if (IsAlternativeServiceBroken(alternative_service)) {
770 continue;
772 std::string canonical_suffix =
773 http_server_properties_impl_->GetCanonicalSuffix(server.host());
774 if (!canonical_suffix.empty()) {
775 if (persisted_map.find(canonical_suffix) != persisted_map.end())
776 continue;
777 persisted_map[canonical_suffix] = true;
779 alternative_service_map->Put(server, alternative_service_info);
780 ++count;
783 ServerNetworkStatsMap* server_network_stats_map =
784 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist);
785 const ServerNetworkStatsMap& main_server_network_stats_map =
786 http_server_properties_impl_->server_network_stats_map();
787 for (ServerNetworkStatsMap::const_iterator it =
788 main_server_network_stats_map.begin();
789 it != main_server_network_stats_map.end(); ++it) {
790 server_network_stats_map->Put(it->first, it->second);
793 IPAddressNumber* last_quic_addr = new IPAddressNumber;
794 http_server_properties_impl_->GetSupportsQuic(last_quic_addr);
795 // Update the preferences on the pref thread.
796 pref_task_runner_->PostTask(
797 FROM_HERE,
798 base::Bind(
799 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread, pref_weak_ptr_,
800 base::Owned(spdy_server_list), base::Owned(spdy_settings_map),
801 base::Owned(alternative_service_map), base::Owned(last_quic_addr),
802 base::Owned(server_network_stats_map), completion));
805 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
806 // AlternativeServiceInfo and SupportsQuic preferences for a server. This is
807 // used only in UpdatePrefsOnPrefThread.
808 struct ServerPref {
809 ServerPref()
810 : supports_spdy(false),
811 settings_map(NULL),
812 alternative_service(NULL),
813 supports_quic(NULL),
814 server_network_stats(NULL) {}
815 ServerPref(bool supports_spdy,
816 const SettingsMap* settings_map,
817 const AlternativeServiceInfo* alternative_service,
818 const SupportsQuic* supports_quic,
819 const ServerNetworkStats* server_network_stats)
820 : supports_spdy(supports_spdy),
821 settings_map(settings_map),
822 alternative_service(alternative_service),
823 supports_quic(supports_quic),
824 server_network_stats(server_network_stats) {}
825 bool supports_spdy;
826 const SettingsMap* settings_map;
827 const AlternativeServiceInfo* alternative_service;
828 const SupportsQuic* supports_quic;
829 const ServerNetworkStats* server_network_stats;
832 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
833 base::ListValue* spdy_server_list,
834 SpdySettingsMap* spdy_settings_map,
835 AlternativeServiceMap* alternative_service_map,
836 IPAddressNumber* last_quic_address,
837 ServerNetworkStatsMap* server_network_stats_map,
838 const base::Closure& completion) {
839 typedef std::map<HostPortPair, ServerPref> ServerPrefMap;
840 ServerPrefMap server_pref_map;
842 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
844 // Add servers that support spdy to server_pref_map.
845 std::string s;
846 for (base::ListValue::const_iterator list_it = spdy_server_list->begin();
847 list_it != spdy_server_list->end();
848 ++list_it) {
849 if ((*list_it)->GetAsString(&s)) {
850 HostPortPair server = HostPortPair::FromString(s);
851 server_pref_map[server].supports_spdy = true;
855 // Add servers that have SpdySettings to server_pref_map.
856 for (SpdySettingsMap::iterator map_it = spdy_settings_map->begin();
857 map_it != spdy_settings_map->end(); ++map_it) {
858 const HostPortPair& server = map_it->first;
859 server_pref_map[server].settings_map = &map_it->second;
862 // Add AlternateProtocol servers to server_pref_map.
863 for (AlternativeServiceMap::const_iterator map_it =
864 alternative_service_map->begin();
865 map_it != alternative_service_map->end(); ++map_it) {
866 server_pref_map[map_it->first].alternative_service = &map_it->second;
869 // Add ServerNetworkStats servers to server_pref_map.
870 for (ServerNetworkStatsMap::const_iterator map_it =
871 server_network_stats_map->begin();
872 map_it != server_network_stats_map->end(); ++map_it) {
873 const HostPortPair& server = map_it->first;
874 server_pref_map[server].server_network_stats = &map_it->second;
877 // Persist properties to the |path_|.
878 base::DictionaryValue http_server_properties_dict;
879 base::DictionaryValue* servers_dict = new base::DictionaryValue;
880 for (ServerPrefMap::const_iterator map_it = server_pref_map.begin();
881 map_it != server_pref_map.end();
882 ++map_it) {
883 const HostPortPair& server = map_it->first;
884 const ServerPref& server_pref = map_it->second;
886 base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
888 // Save supports_spdy.
889 if (server_pref.supports_spdy)
890 server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
891 SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
892 SaveAlternativeServiceToServerPrefs(server_pref.alternative_service,
893 server_pref_dict);
894 SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
895 server_pref_dict);
897 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
900 http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
901 servers_dict);
902 SetVersion(&http_server_properties_dict, kVersionNumber);
904 SaveSupportsQuicToPrefs(last_quic_address, &http_server_properties_dict);
906 setting_prefs_ = true;
907 pref_service_->Set(path_, http_server_properties_dict);
908 setting_prefs_ = false;
910 // Note that |completion| will be fired after we have written everything to
911 // the Preferences, but likely before these changes are serialized to disk.
912 // This is not a problem though, as JSONPrefStore guarantees that this will
913 // happen, pretty soon, and even in the case we shut down immediately.
914 if (!completion.is_null())
915 completion.Run();
918 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
919 const SettingsMap* settings_map,
920 base::DictionaryValue* server_pref_dict) {
921 if (!settings_map) {
922 return;
924 base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
925 for (SettingsMap::const_iterator it = settings_map->begin();
926 it != settings_map->end(); ++it) {
927 SpdySettingsIds id = it->first;
928 uint32 value = it->second.second;
929 std::string key = base::StringPrintf("%u", id);
930 spdy_settings_dict->SetInteger(key, value);
932 server_pref_dict->SetWithoutPathExpansion(kSettingsKey, spdy_settings_dict);
935 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
936 const AlternativeServiceInfo* alternative_service_info,
937 base::DictionaryValue* server_pref_dict) {
938 if (!alternative_service_info)
939 return;
941 const AlternativeService& alternative_service =
942 alternative_service_info->alternative_service;
943 base::DictionaryValue* alternative_service_info_dict =
944 new base::DictionaryValue;
945 alternative_service_info_dict->SetString(
946 kProtocolKey, AlternateProtocolToString(alternative_service.protocol));
947 if (!alternative_service.host.empty()) {
948 alternative_service_info_dict->SetString(kHostKey,
949 alternative_service.host);
951 alternative_service_info_dict->SetInteger(kPortKey, alternative_service.port);
952 alternative_service_info_dict->SetDouble(
953 kProbabilityKey, alternative_service_info->probability);
955 // Create a single element list here.
956 // TODO(bnc): Once we store multiple AlternativeServiceInfo per server, save
957 // all of them.
958 base::ListValue* alternative_service_list = new base::ListValue();
959 alternative_service_list->Append(alternative_service_info_dict);
960 server_pref_dict->SetWithoutPathExpansion(kAlternativeServiceKey,
961 alternative_service_list);
964 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
965 const IPAddressNumber* last_quic_address,
966 base::DictionaryValue* http_server_properties_dict) {
967 if (!last_quic_address || last_quic_address->empty())
968 return;
970 base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
971 supports_quic_dict->SetBoolean(kUsedQuicKey, true);
972 supports_quic_dict->SetString(kAddressKey,
973 IPAddressToString(*last_quic_address));
974 http_server_properties_dict->SetWithoutPathExpansion(kSupportsQuicKey,
975 supports_quic_dict);
978 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
979 const ServerNetworkStats* server_network_stats,
980 base::DictionaryValue* server_pref_dict) {
981 if (!server_network_stats)
982 return;
984 base::DictionaryValue* server_network_stats_dict = new base::DictionaryValue;
985 // Becasue JSON doesn't support int64, persist int64 as a string.
986 server_network_stats_dict->SetInteger(
987 kSrttKey, static_cast<int>(server_network_stats->srtt.ToInternalValue()));
988 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
989 // bandwidth_estimate.
990 server_pref_dict->SetWithoutPathExpansion(kNetworkStatsKey,
991 server_network_stats_dict);
994 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
995 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
996 if (!setting_prefs_)
997 ScheduleUpdateCacheOnPrefThread();
1000 } // namespace net