Update V8 to version 4.6.29.
[chromium-blink-merge.git] / net / http / http_server_properties_manager.cc
blobefd87156d0488971cae71792feabf3d23ef8277a
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 kNetworkStatsKey[] = "network_stats";
68 const char kSrttKey[] = "srtt";
70 } // namespace
72 ////////////////////////////////////////////////////////////////////////////////
73 // HttpServerPropertiesManager
75 HttpServerPropertiesManager::HttpServerPropertiesManager(
76 PrefService* pref_service,
77 const char* pref_path,
78 scoped_refptr<base::SequencedTaskRunner> network_task_runner)
79 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
80 pref_service_(pref_service),
81 setting_prefs_(false),
82 path_(pref_path),
83 network_task_runner_(network_task_runner) {
84 DCHECK(pref_service);
85 pref_weak_ptr_factory_.reset(
86 new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
87 pref_weak_ptr_ = pref_weak_ptr_factory_->GetWeakPtr();
88 pref_cache_update_timer_.reset(
89 new base::OneShotTimer<HttpServerPropertiesManager>);
90 pref_change_registrar_.Init(pref_service_);
91 pref_change_registrar_.Add(
92 path_,
93 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged,
94 base::Unretained(this)));
97 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
98 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
99 network_weak_ptr_factory_.reset();
102 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
103 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
104 network_weak_ptr_factory_.reset(
105 new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
106 http_server_properties_impl_.reset(new HttpServerPropertiesImpl());
108 network_prefs_update_timer_.reset(
109 new base::OneShotTimer<HttpServerPropertiesManager>);
111 pref_task_runner_->PostTask(
112 FROM_HERE,
113 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread,
114 pref_weak_ptr_));
117 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
118 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
119 // Cancel any pending updates, and stop listening for pref change updates.
120 pref_cache_update_timer_->Stop();
121 pref_weak_ptr_factory_.reset();
122 pref_change_registrar_.RemoveAll();
125 // static
126 void HttpServerPropertiesManager::SetVersion(
127 base::DictionaryValue* http_server_properties_dict,
128 int version_number) {
129 if (version_number < 0)
130 version_number = kVersionNumber;
131 DCHECK_LE(version_number, kVersionNumber);
132 if (version_number <= kVersionNumber)
133 http_server_properties_dict->SetInteger(kVersionKey, version_number);
136 // This is required for conformance with the HttpServerProperties interface.
137 base::WeakPtr<HttpServerProperties> HttpServerPropertiesManager::GetWeakPtr() {
138 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
139 return network_weak_ptr_factory_->GetWeakPtr();
142 void HttpServerPropertiesManager::Clear() {
143 Clear(base::Closure());
146 void HttpServerPropertiesManager::Clear(const base::Closure& completion) {
147 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
149 http_server_properties_impl_->Clear();
150 UpdatePrefsFromCacheOnNetworkThread(completion);
153 bool HttpServerPropertiesManager::SupportsRequestPriority(
154 const HostPortPair& server) {
155 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
156 return http_server_properties_impl_->SupportsRequestPriority(server);
159 bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair& server) {
160 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
161 return http_server_properties_impl_->GetSupportsSpdy(server);
164 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair& server,
165 bool support_spdy) {
166 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
168 bool old_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
169 http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
170 bool new_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
171 if (old_support_spdy != new_support_spdy)
172 ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY);
175 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair& server) {
176 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
177 return http_server_properties_impl_->RequiresHTTP11(server);
180 void HttpServerPropertiesManager::SetHTTP11Required(
181 const HostPortPair& server) {
182 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
184 http_server_properties_impl_->SetHTTP11Required(server);
185 ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED);
188 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair& server,
189 SSLConfig* ssl_config) {
190 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
191 http_server_properties_impl_->MaybeForceHTTP11(server, ssl_config);
194 AlternativeServiceVector HttpServerPropertiesManager::GetAlternativeServices(
195 const HostPortPair& origin) {
196 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
197 return http_server_properties_impl_->GetAlternativeServices(origin);
200 bool HttpServerPropertiesManager::SetAlternativeService(
201 const HostPortPair& origin,
202 const AlternativeService& alternative_service,
203 double alternative_probability) {
204 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
205 const bool changed = http_server_properties_impl_->SetAlternativeService(
206 origin, alternative_service, alternative_probability);
207 if (changed) {
208 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
210 return changed;
213 bool HttpServerPropertiesManager::SetAlternativeServices(
214 const HostPortPair& origin,
215 const AlternativeServiceInfoVector& alternative_service_info_vector) {
216 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
217 const bool changed = http_server_properties_impl_->SetAlternativeServices(
218 origin, alternative_service_info_vector);
219 if (changed) {
220 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES);
222 return changed;
225 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
226 const AlternativeService& alternative_service) {
227 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
228 http_server_properties_impl_->MarkAlternativeServiceBroken(
229 alternative_service);
230 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN);
233 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
234 const AlternativeService& alternative_service) {
235 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
236 http_server_properties_impl_->MarkAlternativeServiceRecentlyBroken(
237 alternative_service);
238 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN);
241 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
242 const AlternativeService& alternative_service) const {
243 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
244 return http_server_properties_impl_->IsAlternativeServiceBroken(
245 alternative_service);
248 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
249 const AlternativeService& alternative_service) {
250 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
251 return http_server_properties_impl_->WasAlternativeServiceRecentlyBroken(
252 alternative_service);
255 void HttpServerPropertiesManager::ConfirmAlternativeService(
256 const AlternativeService& alternative_service) {
257 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
258 bool old_value = http_server_properties_impl_->IsAlternativeServiceBroken(
259 alternative_service);
260 http_server_properties_impl_->ConfirmAlternativeService(alternative_service);
261 bool new_value = http_server_properties_impl_->IsAlternativeServiceBroken(
262 alternative_service);
263 // For persisting, we only care about the value returned by
264 // IsAlternativeServiceBroken. If that value changes, then call persist.
265 if (old_value != new_value)
266 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
269 void HttpServerPropertiesManager::ClearAlternativeServices(
270 const HostPortPair& origin) {
271 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
272 const AlternativeServiceMap& map =
273 http_server_properties_impl_->alternative_service_map();
274 size_t old_size = map.size();
275 http_server_properties_impl_->ClearAlternativeServices(origin);
276 size_t new_size = map.size();
277 // Persist only if we have deleted an entry.
278 if (old_size != new_size)
279 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
282 const AlternativeServiceMap&
283 HttpServerPropertiesManager::alternative_service_map() const {
284 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
285 return http_server_properties_impl_->alternative_service_map();
288 scoped_ptr<base::Value>
289 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
290 const {
291 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
292 return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
295 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
296 double threshold) {
297 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
298 http_server_properties_impl_->SetAlternativeServiceProbabilityThreshold(
299 threshold);
302 const SettingsMap& HttpServerPropertiesManager::GetSpdySettings(
303 const HostPortPair& host_port_pair) {
304 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
305 return http_server_properties_impl_->GetSpdySettings(host_port_pair);
308 bool HttpServerPropertiesManager::SetSpdySetting(
309 const HostPortPair& host_port_pair,
310 SpdySettingsIds id,
311 SpdySettingsFlags flags,
312 uint32 value) {
313 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
314 bool persist = http_server_properties_impl_->SetSpdySetting(
315 host_port_pair, id, flags, value);
316 if (persist)
317 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING);
318 return persist;
321 void HttpServerPropertiesManager::ClearSpdySettings(
322 const HostPortPair& host_port_pair) {
323 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
324 http_server_properties_impl_->ClearSpdySettings(host_port_pair);
325 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS);
328 void HttpServerPropertiesManager::ClearAllSpdySettings() {
329 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
330 http_server_properties_impl_->ClearAllSpdySettings();
331 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS);
334 const SpdySettingsMap& HttpServerPropertiesManager::spdy_settings_map()
335 const {
336 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
337 return http_server_properties_impl_->spdy_settings_map();
340 bool HttpServerPropertiesManager::GetSupportsQuic(
341 IPAddressNumber* last_address) const {
342 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
343 return http_server_properties_impl_->GetSupportsQuic(last_address);
346 void HttpServerPropertiesManager::SetSupportsQuic(
347 bool used_quic,
348 const IPAddressNumber& address) {
349 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
350 IPAddressNumber old_last_quic_addr;
351 http_server_properties_impl_->GetSupportsQuic(&old_last_quic_addr);
352 http_server_properties_impl_->SetSupportsQuic(used_quic, address);
353 IPAddressNumber new_last_quic_addr;
354 http_server_properties_impl_->GetSupportsQuic(&new_last_quic_addr);
355 if (old_last_quic_addr != new_last_quic_addr)
356 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC);
359 void HttpServerPropertiesManager::SetServerNetworkStats(
360 const HostPortPair& host_port_pair,
361 ServerNetworkStats stats) {
362 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
363 ServerNetworkStats old_stats;
364 const ServerNetworkStats* old_stats_ptr =
365 http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
366 if (http_server_properties_impl_->GetServerNetworkStats(host_port_pair))
367 old_stats = *old_stats_ptr;
368 http_server_properties_impl_->SetServerNetworkStats(host_port_pair, stats);
369 ServerNetworkStats new_stats =
370 *(http_server_properties_impl_->GetServerNetworkStats(host_port_pair));
371 if (old_stats != new_stats)
372 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
375 const ServerNetworkStats* HttpServerPropertiesManager::GetServerNetworkStats(
376 const HostPortPair& host_port_pair) {
377 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
378 return http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
381 const ServerNetworkStatsMap&
382 HttpServerPropertiesManager::server_network_stats_map() const {
383 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
384 return http_server_properties_impl_->server_network_stats_map();
388 // Update the HttpServerPropertiesImpl's cache with data from preferences.
390 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
391 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
392 // Cancel pending updates, if any.
393 pref_cache_update_timer_->Stop();
394 StartCacheUpdateTimerOnPrefThread(
395 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs));
398 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
399 base::TimeDelta delay) {
400 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
401 pref_cache_update_timer_->Start(
402 FROM_HERE,
403 delay,
404 this,
405 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread);
408 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
409 // The preferences can only be read on the pref thread.
410 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
412 if (!pref_service_->HasPrefPath(path_))
413 return;
415 bool detected_corrupted_prefs = false;
416 const base::DictionaryValue& http_server_properties_dict =
417 *pref_service_->GetDictionary(path_);
419 int version = kMissingVersion;
420 if (!http_server_properties_dict.GetIntegerWithoutPathExpansion(kVersionKey,
421 &version)) {
422 DVLOG(1) << "Missing version. Clearing all properties.";
423 return;
426 // The properties for a given server is in
427 // http_server_properties_dict["servers"][server].
428 const base::DictionaryValue* servers_dict = NULL;
429 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
430 kServersKey, &servers_dict)) {
431 DVLOG(1) << "Malformed http_server_properties for servers.";
432 return;
435 IPAddressNumber* addr = new IPAddressNumber;
436 ReadSupportsQuic(http_server_properties_dict, addr);
438 // String is host/port pair of spdy server.
439 scoped_ptr<StringVector> spdy_servers(new StringVector);
440 scoped_ptr<SpdySettingsMap> spdy_settings_map(
441 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist));
442 scoped_ptr<AlternativeServiceMap> alternative_service_map(
443 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist));
444 scoped_ptr<ServerNetworkStatsMap> server_network_stats_map(
445 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist));
447 for (base::DictionaryValue::Iterator it(*servers_dict); !it.IsAtEnd();
448 it.Advance()) {
449 // Get server's host/pair.
450 const std::string& server_str = it.key();
451 HostPortPair server = HostPortPair::FromString(server_str);
452 if (server.host().empty()) {
453 DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
454 detected_corrupted_prefs = true;
455 continue;
458 const base::DictionaryValue* server_pref_dict = NULL;
459 if (!it.value().GetAsDictionary(&server_pref_dict)) {
460 DVLOG(1) << "Malformed http_server_properties server: " << server_str;
461 detected_corrupted_prefs = true;
462 continue;
465 // Get if server supports Spdy.
466 bool supports_spdy = false;
467 if ((server_pref_dict->GetBoolean(kSupportsSpdyKey, &supports_spdy)) &&
468 supports_spdy) {
469 spdy_servers->push_back(server_str);
472 AddToSpdySettingsMap(server, *server_pref_dict, spdy_settings_map.get());
473 if (!AddToAlternativeServiceMap(server, *server_pref_dict,
474 alternative_service_map.get()) ||
475 !AddToNetworkStatsMap(server, *server_pref_dict,
476 server_network_stats_map.get())) {
477 detected_corrupted_prefs = true;
481 network_task_runner_->PostTask(
482 FROM_HERE,
483 base::Bind(
484 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread,
485 base::Unretained(this), base::Owned(spdy_servers.release()),
486 base::Owned(spdy_settings_map.release()),
487 base::Owned(alternative_service_map.release()), base::Owned(addr),
488 base::Owned(server_network_stats_map.release()),
489 detected_corrupted_prefs));
492 void HttpServerPropertiesManager::AddToSpdySettingsMap(
493 const HostPortPair& server,
494 const base::DictionaryValue& server_pref_dict,
495 SpdySettingsMap* spdy_settings_map) {
496 // Get SpdySettings.
497 DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
498 const base::DictionaryValue* spdy_settings_dict = NULL;
499 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
500 kSettingsKey, &spdy_settings_dict)) {
501 return;
503 SettingsMap settings_map;
504 for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
505 !dict_it.IsAtEnd(); dict_it.Advance()) {
506 const std::string& id_str = dict_it.key();
507 int id = 0;
508 if (!base::StringToInt(id_str, &id)) {
509 DVLOG(1) << "Malformed id in SpdySettings for server: "
510 << server.ToString();
511 NOTREACHED();
512 continue;
514 int value = 0;
515 if (!dict_it.value().GetAsInteger(&value)) {
516 DVLOG(1) << "Malformed value in SpdySettings for server: "
517 << server.ToString();
518 NOTREACHED();
519 continue;
521 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
522 settings_map[static_cast<SpdySettingsIds>(id)] = flags_and_value;
524 spdy_settings_map->Put(server, settings_map);
527 bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
528 const base::DictionaryValue& alternative_service_dict,
529 const std::string& server_str,
530 AlternativeServiceInfo* alternative_service_info) {
531 // Protocol is mandatory.
532 std::string protocol_str;
533 if (!alternative_service_dict.GetStringWithoutPathExpansion(kProtocolKey,
534 &protocol_str)) {
535 DVLOG(1) << "Malformed alternative service protocol string for server: "
536 << server_str;
537 return false;
539 AlternateProtocol protocol = AlternateProtocolFromString(protocol_str);
540 if (!IsAlternateProtocolValid(protocol)) {
541 DVLOG(1) << "Invalid alternative service protocol string for server: "
542 << server_str;
543 return false;
545 alternative_service_info->alternative_service.protocol = protocol;
547 // Host is optional, defaults to "".
548 alternative_service_info->alternative_service.host.clear();
549 if (alternative_service_dict.HasKey(kHostKey) &&
550 !alternative_service_dict.GetStringWithoutPathExpansion(
551 kHostKey, &(alternative_service_info->alternative_service.host))) {
552 DVLOG(1) << "Malformed alternative service host string for server: "
553 << server_str;
554 return false;
557 // Port is mandatory.
558 int port = 0;
559 if (!alternative_service_dict.GetInteger(kPortKey, &port) ||
560 !IsPortValid(port)) {
561 DVLOG(1) << "Malformed alternative service port for server: " << server_str;
562 return false;
564 alternative_service_info->alternative_service.port =
565 static_cast<uint32>(port);
567 // Probability is optional, defaults to 1.0.
568 alternative_service_info->probability = 1.0;
569 if (alternative_service_dict.HasKey(kProbabilityKey) &&
570 !alternative_service_dict.GetDoubleWithoutPathExpansion(
571 kProbabilityKey, &(alternative_service_info->probability))) {
572 DVLOG(1) << "Malformed alternative service probability for server: "
573 << server_str;
574 return false;
577 return true;
580 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
581 const HostPortPair& server,
582 const base::DictionaryValue& server_pref_dict,
583 AlternativeServiceMap* alternative_service_map) {
584 DCHECK(alternative_service_map->Peek(server) ==
585 alternative_service_map->end());
586 // Get alternative_services...
587 const base::ListValue* alternative_service_list;
588 const base::DictionaryValue* alternative_service_dict;
589 AlternativeServiceInfoVector alternative_service_info_vector;
590 if (server_pref_dict.GetListWithoutPathExpansion(kAlternativeServiceKey,
591 &alternative_service_list)) {
592 for (const base::Value* alternative_service_list_item :
593 *alternative_service_list) {
594 if (!alternative_service_list_item->GetAsDictionary(
595 &alternative_service_dict))
596 return false;
597 AlternativeServiceInfo alternative_service_info;
598 if (!ParseAlternativeServiceDict(*alternative_service_dict,
599 server.ToString(),
600 &alternative_service_info)) {
601 return false;
603 alternative_service_info_vector.push_back(alternative_service_info);
605 } else {
606 // ...or alternate_protocol.
607 // TODO(bnc): Remove this in M46, we do not need preference migration for
608 // long.
609 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
610 kAlternateProtocolKey, &alternative_service_dict)) {
611 return true;
613 AlternativeServiceInfo alternative_service_info;
614 if (!ParseAlternativeServiceDict(*alternative_service_dict,
615 server.ToString(),
616 &alternative_service_info)) {
617 return false;
619 alternative_service_info_vector.push_back(alternative_service_info);
622 if (alternative_service_info_vector.empty()) {
623 return false;
626 alternative_service_map->Put(server, alternative_service_info_vector);
627 return true;
630 bool HttpServerPropertiesManager::ReadSupportsQuic(
631 const base::DictionaryValue& http_server_properties_dict,
632 IPAddressNumber* last_quic_address) {
633 const base::DictionaryValue* supports_quic_dict = NULL;
634 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
635 kSupportsQuicKey, &supports_quic_dict)) {
636 return true;
638 bool used_quic = false;
639 if (!supports_quic_dict->GetBooleanWithoutPathExpansion(kUsedQuicKey,
640 &used_quic)) {
641 DVLOG(1) << "Malformed SupportsQuic";
642 return false;
644 if (!used_quic)
645 return false;
647 std::string address;
648 if (!supports_quic_dict->GetStringWithoutPathExpansion(kAddressKey,
649 &address) ||
650 !ParseIPLiteralToNumber(address, last_quic_address)) {
651 DVLOG(1) << "Malformed SupportsQuic";
652 return false;
654 return true;
657 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
658 const HostPortPair& server,
659 const base::DictionaryValue& server_pref_dict,
660 ServerNetworkStatsMap* network_stats_map) {
661 DCHECK(network_stats_map->Peek(server) == network_stats_map->end());
662 const base::DictionaryValue* server_network_stats_dict = NULL;
663 if (!server_pref_dict.GetDictionaryWithoutPathExpansion(
664 kNetworkStatsKey, &server_network_stats_dict)) {
665 return true;
667 int srtt;
668 if (!server_network_stats_dict->GetIntegerWithoutPathExpansion(kSrttKey,
669 &srtt)) {
670 DVLOG(1) << "Malformed ServerNetworkStats for server: "
671 << server.ToString();
672 return false;
674 ServerNetworkStats server_network_stats;
675 server_network_stats.srtt = base::TimeDelta::FromInternalValue(srtt);
676 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
677 // bandwidth_estimate.
678 network_stats_map->Put(server, server_network_stats);
679 return true;
682 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
683 StringVector* spdy_servers,
684 SpdySettingsMap* spdy_settings_map,
685 AlternativeServiceMap* alternative_service_map,
686 IPAddressNumber* last_quic_address,
687 ServerNetworkStatsMap* server_network_stats_map,
688 bool detected_corrupted_prefs) {
689 // Preferences have the master data because admins might have pushed new
690 // preferences. Update the cached data with new data from preferences.
691 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
693 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size());
694 http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true);
696 // Update the cached data and use the new spdy_settings from preferences.
697 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size());
698 http_server_properties_impl_->InitializeSpdySettingsServers(
699 spdy_settings_map);
701 // Update the cached data and use the new alternative service list from
702 // preferences.
703 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
704 alternative_service_map->size());
705 http_server_properties_impl_->InitializeAlternativeServiceServers(
706 alternative_service_map);
708 http_server_properties_impl_->InitializeSupportsQuic(last_quic_address);
710 http_server_properties_impl_->InitializeServerNetworkStats(
711 server_network_stats_map);
713 // Update the prefs with what we have read (delete all corrupted prefs).
714 if (detected_corrupted_prefs)
715 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS);
719 // Update Preferences with data from the cached data.
721 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
722 Location location) {
723 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
724 // Cancel pending updates, if any.
725 network_prefs_update_timer_->Stop();
726 StartPrefsUpdateTimerOnNetworkThread(
727 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs));
728 // TODO(rtenneti): Delete the following histogram after collecting some data.
729 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location,
730 HttpServerPropertiesManager::NUM_LOCATIONS);
733 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
734 base::TimeDelta delay) {
735 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
736 // This is overridden in tests to post the task without the delay.
737 network_prefs_update_timer_->Start(
738 FROM_HERE,
739 delay,
740 this,
741 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread);
744 // This is required so we can set this as the callback for a timer.
745 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
746 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
749 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
750 const base::Closure& completion) {
751 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
753 base::ListValue* spdy_server_list = new base::ListValue;
754 http_server_properties_impl_->GetSpdyServerList(
755 spdy_server_list, kMaxSupportsSpdyServerHostsToPersist);
757 SpdySettingsMap* spdy_settings_map =
758 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist);
759 const SpdySettingsMap& main_map =
760 http_server_properties_impl_->spdy_settings_map();
761 int count = 0;
762 for (SpdySettingsMap::const_iterator it = main_map.begin();
763 it != main_map.end() && count < kMaxSpdySettingsHostsToPersist;
764 ++it, ++count) {
765 spdy_settings_map->Put(it->first, it->second);
768 AlternativeServiceMap* alternative_service_map =
769 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist);
770 const AlternativeServiceMap& map =
771 http_server_properties_impl_->alternative_service_map();
772 count = 0;
773 typedef std::map<std::string, bool> CanonicalHostPersistedMap;
774 CanonicalHostPersistedMap persisted_map;
775 for (AlternativeServiceMap::const_iterator it = map.begin();
776 it != map.end() && count < kMaxAlternateProtocolHostsToPersist; ++it) {
777 const HostPortPair& server = it->first;
778 AlternativeServiceInfoVector notbroken_alternative_service_info_vector;
779 for (const AlternativeServiceInfo& alternative_service_info : it->second) {
780 if (!IsAlternateProtocolValid(
781 alternative_service_info.alternative_service.protocol)) {
782 continue;
784 AlternativeService alternative_service(
785 alternative_service_info.alternative_service);
786 if (alternative_service.host.empty()) {
787 alternative_service.host = server.host();
789 if (IsAlternativeServiceBroken(alternative_service)) {
790 continue;
792 notbroken_alternative_service_info_vector.push_back(
793 alternative_service_info);
795 if (notbroken_alternative_service_info_vector.empty()) {
796 continue;
798 alternative_service_map->Put(server,
799 notbroken_alternative_service_info_vector);
800 std::string canonical_suffix =
801 http_server_properties_impl_->GetCanonicalSuffix(server.host());
802 if (!canonical_suffix.empty()) {
803 if (persisted_map.find(canonical_suffix) != persisted_map.end())
804 continue;
805 persisted_map[canonical_suffix] = true;
807 ++count;
810 ServerNetworkStatsMap* server_network_stats_map =
811 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist);
812 const ServerNetworkStatsMap& main_server_network_stats_map =
813 http_server_properties_impl_->server_network_stats_map();
814 for (ServerNetworkStatsMap::const_iterator it =
815 main_server_network_stats_map.begin();
816 it != main_server_network_stats_map.end(); ++it) {
817 server_network_stats_map->Put(it->first, it->second);
820 IPAddressNumber* last_quic_addr = new IPAddressNumber;
821 http_server_properties_impl_->GetSupportsQuic(last_quic_addr);
822 // Update the preferences on the pref thread.
823 pref_task_runner_->PostTask(
824 FROM_HERE,
825 base::Bind(
826 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread, pref_weak_ptr_,
827 base::Owned(spdy_server_list), base::Owned(spdy_settings_map),
828 base::Owned(alternative_service_map), base::Owned(last_quic_addr),
829 base::Owned(server_network_stats_map), completion));
832 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
833 // AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
834 // is used only in UpdatePrefsOnPrefThread.
835 struct ServerPref {
836 ServerPref()
837 : supports_spdy(false),
838 settings_map(NULL),
839 alternative_service_info_vector(NULL),
840 supports_quic(NULL),
841 server_network_stats(NULL) {}
842 ServerPref(
843 bool supports_spdy,
844 const SettingsMap* settings_map,
845 const AlternativeServiceInfoVector* alternative_service_info_vector,
846 const SupportsQuic* supports_quic,
847 const ServerNetworkStats* server_network_stats)
848 : supports_spdy(supports_spdy),
849 settings_map(settings_map),
850 alternative_service_info_vector(alternative_service_info_vector),
851 supports_quic(supports_quic),
852 server_network_stats(server_network_stats) {}
853 bool supports_spdy;
854 const SettingsMap* settings_map;
855 const AlternativeServiceInfoVector* alternative_service_info_vector;
856 const SupportsQuic* supports_quic;
857 const ServerNetworkStats* server_network_stats;
860 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
861 base::ListValue* spdy_server_list,
862 SpdySettingsMap* spdy_settings_map,
863 AlternativeServiceMap* alternative_service_map,
864 IPAddressNumber* last_quic_address,
865 ServerNetworkStatsMap* server_network_stats_map,
866 const base::Closure& completion) {
867 typedef std::map<HostPortPair, ServerPref> ServerPrefMap;
868 ServerPrefMap server_pref_map;
870 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
872 // Add servers that support spdy to server_pref_map.
873 std::string s;
874 for (base::ListValue::const_iterator list_it = spdy_server_list->begin();
875 list_it != spdy_server_list->end();
876 ++list_it) {
877 if ((*list_it)->GetAsString(&s)) {
878 HostPortPair server = HostPortPair::FromString(s);
879 server_pref_map[server].supports_spdy = true;
883 // Add servers that have SpdySettings to server_pref_map.
884 for (SpdySettingsMap::iterator map_it = spdy_settings_map->begin();
885 map_it != spdy_settings_map->end(); ++map_it) {
886 const HostPortPair& server = map_it->first;
887 server_pref_map[server].settings_map = &map_it->second;
890 // Add alternative services to server_pref_map.
891 for (AlternativeServiceMap::const_iterator map_it =
892 alternative_service_map->begin();
893 map_it != alternative_service_map->end(); ++map_it) {
894 server_pref_map[map_it->first].alternative_service_info_vector =
895 &map_it->second;
898 // Add ServerNetworkStats servers to server_pref_map.
899 for (ServerNetworkStatsMap::const_iterator map_it =
900 server_network_stats_map->begin();
901 map_it != server_network_stats_map->end(); ++map_it) {
902 const HostPortPair& server = map_it->first;
903 server_pref_map[server].server_network_stats = &map_it->second;
906 // Persist properties to the |path_|.
907 base::DictionaryValue http_server_properties_dict;
908 base::DictionaryValue* servers_dict = new base::DictionaryValue;
909 for (ServerPrefMap::const_iterator map_it = server_pref_map.begin();
910 map_it != server_pref_map.end();
911 ++map_it) {
912 const HostPortPair& server = map_it->first;
913 const ServerPref& server_pref = map_it->second;
915 base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
917 // Save supports_spdy.
918 if (server_pref.supports_spdy)
919 server_pref_dict->SetBoolean(kSupportsSpdyKey, server_pref.supports_spdy);
920 SaveSpdySettingsToServerPrefs(server_pref.settings_map, server_pref_dict);
921 SaveAlternativeServiceToServerPrefs(
922 server_pref.alternative_service_info_vector, server_pref_dict);
923 SaveNetworkStatsToServerPrefs(server_pref.server_network_stats,
924 server_pref_dict);
926 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
929 http_server_properties_dict.SetWithoutPathExpansion(kServersKey,
930 servers_dict);
931 SetVersion(&http_server_properties_dict, kVersionNumber);
933 SaveSupportsQuicToPrefs(last_quic_address, &http_server_properties_dict);
935 setting_prefs_ = true;
936 pref_service_->Set(path_, http_server_properties_dict);
937 setting_prefs_ = false;
939 // Note that |completion| will be fired after we have written everything to
940 // the Preferences, but likely before these changes are serialized to disk.
941 // This is not a problem though, as JSONPrefStore guarantees that this will
942 // happen, pretty soon, and even in the case we shut down immediately.
943 if (!completion.is_null())
944 completion.Run();
947 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
948 const SettingsMap* settings_map,
949 base::DictionaryValue* server_pref_dict) {
950 if (!settings_map) {
951 return;
953 base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
954 for (SettingsMap::const_iterator it = settings_map->begin();
955 it != settings_map->end(); ++it) {
956 SpdySettingsIds id = it->first;
957 uint32 value = it->second.second;
958 std::string key = base::StringPrintf("%u", id);
959 spdy_settings_dict->SetInteger(key, value);
961 server_pref_dict->SetWithoutPathExpansion(kSettingsKey, spdy_settings_dict);
964 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
965 const AlternativeServiceInfoVector* alternative_service_info_vector,
966 base::DictionaryValue* server_pref_dict) {
967 if (!alternative_service_info_vector ||
968 alternative_service_info_vector->empty()) {
969 return;
971 scoped_ptr<base::ListValue> alternative_service_list(new base::ListValue);
972 for (const AlternativeServiceInfo& alternative_service_info :
973 *alternative_service_info_vector) {
974 const AlternativeService alternative_service =
975 alternative_service_info.alternative_service;
976 DCHECK(IsAlternateProtocolValid(alternative_service.protocol));
977 base::DictionaryValue* alternative_service_dict = new base::DictionaryValue;
978 alternative_service_dict->SetInteger(kPortKey, alternative_service.port);
979 if (!alternative_service.host.empty()) {
980 alternative_service_dict->SetString(kHostKey, alternative_service.host);
982 alternative_service_dict->SetString(
983 kProtocolKey, AlternateProtocolToString(alternative_service.protocol));
984 alternative_service_dict->SetDouble(kProbabilityKey,
985 alternative_service_info.probability);
986 alternative_service_list->Append(alternative_service_dict);
988 if (alternative_service_list->GetSize() == 0)
989 return;
990 server_pref_dict->SetWithoutPathExpansion(kAlternativeServiceKey,
991 alternative_service_list.release());
994 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
995 const IPAddressNumber* last_quic_address,
996 base::DictionaryValue* http_server_properties_dict) {
997 if (!last_quic_address || last_quic_address->empty())
998 return;
1000 base::DictionaryValue* supports_quic_dict = new base::DictionaryValue;
1001 supports_quic_dict->SetBoolean(kUsedQuicKey, true);
1002 supports_quic_dict->SetString(kAddressKey,
1003 IPAddressToString(*last_quic_address));
1004 http_server_properties_dict->SetWithoutPathExpansion(kSupportsQuicKey,
1005 supports_quic_dict);
1008 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
1009 const ServerNetworkStats* server_network_stats,
1010 base::DictionaryValue* server_pref_dict) {
1011 if (!server_network_stats)
1012 return;
1014 base::DictionaryValue* server_network_stats_dict = new base::DictionaryValue;
1015 // Becasue JSON doesn't support int64, persist int64 as a string.
1016 server_network_stats_dict->SetInteger(
1017 kSrttKey, static_cast<int>(server_network_stats->srtt.ToInternalValue()));
1018 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
1019 // bandwidth_estimate.
1020 server_pref_dict->SetWithoutPathExpansion(kNetworkStatsKey,
1021 server_network_stats_dict);
1024 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
1025 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
1026 if (!setting_prefs_)
1027 ScheduleUpdateCacheOnPrefThread();
1030 } // namespace net