Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / http / http_server_properties_manager.cc
blob35458ca7bfd6e575cbc5a27d65fccb605163251f
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_server_properties_manager.h"
7 #include "base/bind.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/rand_util.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
18 namespace net {
20 namespace {
22 // Time to wait before starting an update the http_server_properties_impl_ cache
23 // from preferences. Scheduling another update during this period will reset the
24 // timer.
25 const int64 kUpdateCacheDelayMs = 1000;
27 // Time to wait before starting an update the preferences from the
28 // http_server_properties_impl_ cache. Scheduling another update during this
29 // period will reset the timer.
30 const int64 kUpdatePrefsDelayMs = 5000;
32 // "version" 0 indicates, http_server_properties doesn't have "version"
33 // property.
34 const int kMissingVersion = 0;
36 // The version number of persisted http_server_properties.
37 const int kVersionNumber = 3;
39 typedef std::vector<std::string> StringVector;
41 // Load either 200 or 1000 servers based on a coin flip.
42 const int k200AlternateProtocolHostsToLoad = 200;
43 const int k1000AlternateProtocolHostsToLoad = 1000;
44 // Persist 1000 MRU AlternateProtocolHostPortPairs.
45 const int kMaxAlternateProtocolHostsToPersist = 1000;
47 // Persist 200 MRU SpdySettingsHostPortPairs.
48 const int kMaxSpdySettingsHostsToPersist = 200;
50 // Persist 300 MRU SupportsSpdyServerHostPortPairs.
51 const int kMaxSupportsSpdyServerHostsToPersist = 300;
53 } // namespace
55 ////////////////////////////////////////////////////////////////////////////////
56 // HttpServerPropertiesManager
58 HttpServerPropertiesManager::HttpServerPropertiesManager(
59 PrefService* pref_service,
60 const char* pref_path,
61 scoped_refptr<base::SequencedTaskRunner> network_task_runner)
62 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
63 pref_service_(pref_service),
64 setting_prefs_(false),
65 path_(pref_path),
66 network_task_runner_(network_task_runner) {
67 DCHECK(pref_service);
68 pref_weak_ptr_factory_.reset(
69 new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
70 pref_weak_ptr_ = pref_weak_ptr_factory_->GetWeakPtr();
71 pref_cache_update_timer_.reset(
72 new base::OneShotTimer<HttpServerPropertiesManager>);
73 pref_change_registrar_.Init(pref_service_);
74 pref_change_registrar_.Add(
75 path_,
76 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged,
77 base::Unretained(this)));
80 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
81 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
82 network_weak_ptr_factory_.reset();
85 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
86 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
87 network_weak_ptr_factory_.reset(
88 new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
89 http_server_properties_impl_.reset(new net::HttpServerPropertiesImpl());
91 network_prefs_update_timer_.reset(
92 new base::OneShotTimer<HttpServerPropertiesManager>);
94 pref_task_runner_->PostTask(
95 FROM_HERE,
96 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread,
97 pref_weak_ptr_));
100 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
101 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
102 // Cancel any pending updates, and stop listening for pref change updates.
103 pref_cache_update_timer_->Stop();
104 pref_weak_ptr_factory_.reset();
105 pref_change_registrar_.RemoveAll();
108 // static
109 void HttpServerPropertiesManager::SetVersion(
110 base::DictionaryValue* http_server_properties_dict,
111 int version_number) {
112 if (version_number < 0)
113 version_number = kVersionNumber;
114 DCHECK_LE(version_number, kVersionNumber);
115 if (version_number <= kVersionNumber)
116 http_server_properties_dict->SetInteger("version", version_number);
119 // This is required for conformance with the HttpServerProperties interface.
120 base::WeakPtr<net::HttpServerProperties>
121 HttpServerPropertiesManager::GetWeakPtr() {
122 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
123 return network_weak_ptr_factory_->GetWeakPtr();
126 void HttpServerPropertiesManager::Clear() {
127 Clear(base::Closure());
130 void HttpServerPropertiesManager::Clear(const base::Closure& completion) {
131 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
133 http_server_properties_impl_->Clear();
134 UpdatePrefsFromCacheOnNetworkThread(completion);
137 bool HttpServerPropertiesManager::SupportsSpdy(
138 const net::HostPortPair& server) {
139 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
140 return http_server_properties_impl_->SupportsSpdy(server);
143 void HttpServerPropertiesManager::SetSupportsSpdy(
144 const net::HostPortPair& server,
145 bool support_spdy) {
146 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
148 http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
149 ScheduleUpdatePrefsOnNetworkThread();
152 bool HttpServerPropertiesManager::HasAlternateProtocol(
153 const net::HostPortPair& server) {
154 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
155 return http_server_properties_impl_->HasAlternateProtocol(server);
158 net::AlternateProtocolInfo
159 HttpServerPropertiesManager::GetAlternateProtocol(
160 const net::HostPortPair& server) {
161 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
162 return http_server_properties_impl_->GetAlternateProtocol(server);
165 void HttpServerPropertiesManager::SetAlternateProtocol(
166 const net::HostPortPair& server,
167 uint16 alternate_port,
168 AlternateProtocol alternate_protocol,
169 double alternate_probability) {
170 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
171 http_server_properties_impl_->SetAlternateProtocol(
172 server, alternate_port, alternate_protocol, alternate_probability);
173 ScheduleUpdatePrefsOnNetworkThread();
176 void HttpServerPropertiesManager::SetBrokenAlternateProtocol(
177 const net::HostPortPair& server) {
178 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
179 http_server_properties_impl_->SetBrokenAlternateProtocol(server);
180 ScheduleUpdatePrefsOnNetworkThread();
183 bool HttpServerPropertiesManager::WasAlternateProtocolRecentlyBroken(
184 const net::HostPortPair& server) {
185 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
186 return http_server_properties_impl_->WasAlternateProtocolRecentlyBroken(
187 server);
190 void HttpServerPropertiesManager::ConfirmAlternateProtocol(
191 const net::HostPortPair& server) {
192 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
193 http_server_properties_impl_->ConfirmAlternateProtocol(server);
194 ScheduleUpdatePrefsOnNetworkThread();
197 void HttpServerPropertiesManager::ClearAlternateProtocol(
198 const net::HostPortPair& server) {
199 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
200 http_server_properties_impl_->ClearAlternateProtocol(server);
201 ScheduleUpdatePrefsOnNetworkThread();
204 const net::AlternateProtocolMap&
205 HttpServerPropertiesManager::alternate_protocol_map() const {
206 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
207 return http_server_properties_impl_->alternate_protocol_map();
210 void HttpServerPropertiesManager::SetAlternateProtocolExperiment(
211 AlternateProtocolExperiment experiment) {
212 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
213 http_server_properties_impl_->SetAlternateProtocolExperiment(experiment);
216 void HttpServerPropertiesManager::SetAlternateProtocolProbabilityThreshold(
217 double threshold) {
218 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
219 http_server_properties_impl_->SetAlternateProtocolProbabilityThreshold(
220 threshold);
223 AlternateProtocolExperiment
224 HttpServerPropertiesManager::GetAlternateProtocolExperiment() const {
225 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
226 return http_server_properties_impl_->GetAlternateProtocolExperiment();
229 const SettingsMap& HttpServerPropertiesManager::GetSpdySettings(
230 const HostPortPair& host_port_pair) {
231 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
232 return http_server_properties_impl_->GetSpdySettings(host_port_pair);
235 bool HttpServerPropertiesManager::SetSpdySetting(
236 const HostPortPair& host_port_pair,
237 SpdySettingsIds id,
238 SpdySettingsFlags flags,
239 uint32 value) {
240 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
241 bool persist = http_server_properties_impl_->SetSpdySetting(
242 host_port_pair, id, flags, value);
243 if (persist)
244 ScheduleUpdatePrefsOnNetworkThread();
245 return persist;
248 void HttpServerPropertiesManager::ClearSpdySettings(
249 const HostPortPair& host_port_pair) {
250 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
251 http_server_properties_impl_->ClearSpdySettings(host_port_pair);
252 ScheduleUpdatePrefsOnNetworkThread();
255 void HttpServerPropertiesManager::ClearAllSpdySettings() {
256 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
257 http_server_properties_impl_->ClearAllSpdySettings();
258 ScheduleUpdatePrefsOnNetworkThread();
261 const SpdySettingsMap& HttpServerPropertiesManager::spdy_settings_map()
262 const {
263 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
264 return http_server_properties_impl_->spdy_settings_map();
267 void HttpServerPropertiesManager::SetServerNetworkStats(
268 const net::HostPortPair& host_port_pair,
269 NetworkStats stats) {
270 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
271 http_server_properties_impl_->SetServerNetworkStats(host_port_pair, stats);
274 const HttpServerPropertiesManager::NetworkStats*
275 HttpServerPropertiesManager::GetServerNetworkStats(
276 const net::HostPortPair& host_port_pair) const {
277 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
278 return http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
282 // Update the HttpServerPropertiesImpl's cache with data from preferences.
284 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
285 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
286 // Cancel pending updates, if any.
287 pref_cache_update_timer_->Stop();
288 StartCacheUpdateTimerOnPrefThread(
289 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs));
292 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
293 base::TimeDelta delay) {
294 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
295 pref_cache_update_timer_->Start(
296 FROM_HERE,
297 delay,
298 this,
299 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread);
302 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
303 // The preferences can only be read on the pref thread.
304 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
306 if (!pref_service_->HasPrefPath(path_))
307 return;
309 bool detected_corrupted_prefs = false;
310 const base::DictionaryValue& http_server_properties_dict =
311 *pref_service_->GetDictionary(path_);
313 int version = kMissingVersion;
314 if (!http_server_properties_dict.GetIntegerWithoutPathExpansion("version",
315 &version)) {
316 DVLOG(1) << "Missing version. Clearing all properties.";
317 return;
320 // The properties for a given server is in
321 // http_server_properties_dict["servers"][server].
322 const base::DictionaryValue* servers_dict = NULL;
323 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion(
324 "servers", &servers_dict)) {
325 DVLOG(1) << "Malformed http_server_properties for servers.";
326 return;
329 // String is host/port pair of spdy server.
330 scoped_ptr<StringVector> spdy_servers(new StringVector);
331 scoped_ptr<net::SpdySettingsMap> spdy_settings_map(
332 new net::SpdySettingsMap(kMaxSpdySettingsHostsToPersist));
333 scoped_ptr<net::AlternateProtocolMap> alternate_protocol_map(
334 new net::AlternateProtocolMap(kMaxAlternateProtocolHostsToPersist));
335 // TODO(rtenneti): Delete the following code after the experiment.
336 int alternate_protocols_to_load = k200AlternateProtocolHostsToLoad;
337 net::AlternateProtocolExperiment alternate_protocol_experiment =
338 net::ALTERNATE_PROTOCOL_NOT_PART_OF_EXPERIMENT;
339 if (version == kVersionNumber) {
340 if (base::RandInt(0, 99) == 0) {
341 alternate_protocol_experiment =
342 net::ALTERNATE_PROTOCOL_TRUNCATED_200_SERVERS;
343 } else {
344 alternate_protocols_to_load = k1000AlternateProtocolHostsToLoad;
345 alternate_protocol_experiment =
346 net::ALTERNATE_PROTOCOL_TRUNCATED_1000_SERVERS;
348 DVLOG(1) << "# of servers that support alternate_protocol: "
349 << alternate_protocols_to_load;
352 int count = 0;
353 for (base::DictionaryValue::Iterator it(*servers_dict); !it.IsAtEnd();
354 it.Advance()) {
355 // Get server's host/pair.
356 const std::string& server_str = it.key();
357 net::HostPortPair server = net::HostPortPair::FromString(server_str);
358 if (server.host().empty()) {
359 DVLOG(1) << "Malformed http_server_properties for server: " << server_str;
360 detected_corrupted_prefs = true;
361 continue;
364 const base::DictionaryValue* server_pref_dict = NULL;
365 if (!it.value().GetAsDictionary(&server_pref_dict)) {
366 DVLOG(1) << "Malformed http_server_properties server: " << server_str;
367 detected_corrupted_prefs = true;
368 continue;
371 // Get if server supports Spdy.
372 bool supports_spdy = false;
373 if ((server_pref_dict->GetBoolean("supports_spdy", &supports_spdy)) &&
374 supports_spdy) {
375 spdy_servers->push_back(server_str);
378 // Get SpdySettings.
379 DCHECK(spdy_settings_map->Peek(server) == spdy_settings_map->end());
380 const base::DictionaryValue* spdy_settings_dict = NULL;
381 if (server_pref_dict->GetDictionaryWithoutPathExpansion(
382 "settings", &spdy_settings_dict)) {
383 net::SettingsMap settings_map;
384 for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict);
385 !dict_it.IsAtEnd();
386 dict_it.Advance()) {
387 const std::string& id_str = dict_it.key();
388 int id = 0;
389 if (!base::StringToInt(id_str, &id)) {
390 DVLOG(1) << "Malformed id in SpdySettings for server: " << server_str;
391 NOTREACHED();
392 continue;
394 int value = 0;
395 if (!dict_it.value().GetAsInteger(&value)) {
396 DVLOG(1) << "Malformed value in SpdySettings for server: "
397 << server_str;
398 NOTREACHED();
399 continue;
401 net::SettingsFlagsAndValue flags_and_value(net::SETTINGS_FLAG_PERSISTED,
402 value);
403 settings_map[static_cast<net::SpdySettingsIds>(id)] = flags_and_value;
405 spdy_settings_map->Put(server, settings_map);
408 // Get alternate_protocol server.
409 DCHECK(alternate_protocol_map->Peek(server) ==
410 alternate_protocol_map->end());
411 const base::DictionaryValue* port_alternate_protocol_dict = NULL;
412 if (!server_pref_dict->GetDictionaryWithoutPathExpansion(
413 "alternate_protocol", &port_alternate_protocol_dict)) {
414 continue;
417 if (count >= alternate_protocols_to_load)
418 continue;
419 do {
420 int port = 0;
421 if (!port_alternate_protocol_dict->GetIntegerWithoutPathExpansion(
422 "port", &port) ||
423 (port > (1 << 16))) {
424 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
425 detected_corrupted_prefs = true;
426 continue;
428 std::string protocol_str;
429 if (!port_alternate_protocol_dict->GetStringWithoutPathExpansion(
430 "protocol_str", &protocol_str)) {
431 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
432 detected_corrupted_prefs = true;
433 continue;
435 net::AlternateProtocol protocol =
436 net::AlternateProtocolFromString(protocol_str);
437 if (!net::IsAlternateProtocolValid(protocol)) {
438 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
439 detected_corrupted_prefs = true;
440 continue;
443 double probability = 1;
444 if (port_alternate_protocol_dict->HasKey("probability") &&
445 !port_alternate_protocol_dict->GetDoubleWithoutPathExpansion(
446 "probability", &probability)) {
447 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
448 detected_corrupted_prefs = true;
449 continue;
452 net::AlternateProtocolInfo port_alternate_protocol(port,
453 protocol,
454 probability);
455 alternate_protocol_map->Put(server, port_alternate_protocol);
456 ++count;
457 } while (false);
460 network_task_runner_->PostTask(
461 FROM_HERE,
462 base::Bind(
463 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread,
464 base::Unretained(this),
465 base::Owned(spdy_servers.release()),
466 base::Owned(spdy_settings_map.release()),
467 base::Owned(alternate_protocol_map.release()),
468 alternate_protocol_experiment,
469 detected_corrupted_prefs));
472 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
473 StringVector* spdy_servers,
474 net::SpdySettingsMap* spdy_settings_map,
475 net::AlternateProtocolMap* alternate_protocol_map,
476 net::AlternateProtocolExperiment alternate_protocol_experiment,
477 bool detected_corrupted_prefs) {
478 // Preferences have the master data because admins might have pushed new
479 // preferences. Update the cached data with new data from preferences.
480 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
482 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size());
483 http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true);
485 // Update the cached data and use the new spdy_settings from preferences.
486 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size());
487 http_server_properties_impl_->InitializeSpdySettingsServers(
488 spdy_settings_map);
490 // Update the cached data and use the new Alternate-Protocol server list from
491 // preferences.
492 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
493 alternate_protocol_map->size());
494 http_server_properties_impl_->InitializeAlternateProtocolServers(
495 alternate_protocol_map);
496 http_server_properties_impl_->SetAlternateProtocolExperiment(
497 alternate_protocol_experiment);
499 // Update the prefs with what we have read (delete all corrupted prefs).
500 if (detected_corrupted_prefs)
501 ScheduleUpdatePrefsOnNetworkThread();
505 // Update Preferences with data from the cached data.
507 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread() {
508 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
509 // Cancel pending updates, if any.
510 network_prefs_update_timer_->Stop();
511 StartPrefsUpdateTimerOnNetworkThread(
512 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs));
515 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
516 base::TimeDelta delay) {
517 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
518 // This is overridden in tests to post the task without the delay.
519 network_prefs_update_timer_->Start(
520 FROM_HERE,
521 delay,
522 this,
523 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread);
526 // This is required so we can set this as the callback for a timer.
527 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
528 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
531 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
532 const base::Closure& completion) {
533 DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
535 base::ListValue* spdy_server_list = new base::ListValue;
536 http_server_properties_impl_->GetSpdyServerList(
537 spdy_server_list, kMaxSupportsSpdyServerHostsToPersist);
539 net::SpdySettingsMap* spdy_settings_map =
540 new net::SpdySettingsMap(kMaxSpdySettingsHostsToPersist);
541 const net::SpdySettingsMap& main_map =
542 http_server_properties_impl_->spdy_settings_map();
543 int count = 0;
544 for (net::SpdySettingsMap::const_iterator it = main_map.begin();
545 it != main_map.end() && count < kMaxSpdySettingsHostsToPersist;
546 ++it, ++count) {
547 spdy_settings_map->Put(it->first, it->second);
550 net::AlternateProtocolMap* alternate_protocol_map =
551 new net::AlternateProtocolMap(kMaxAlternateProtocolHostsToPersist);
552 const net::AlternateProtocolMap& map =
553 http_server_properties_impl_->alternate_protocol_map();
554 count = 0;
555 typedef std::map<std::string, bool> CanonicalHostPersistedMap;
556 CanonicalHostPersistedMap persisted_map;
557 for (net::AlternateProtocolMap::const_iterator it = map.begin();
558 it != map.end() && count < kMaxAlternateProtocolHostsToPersist;
559 ++it) {
560 const net::HostPortPair& server = it->first;
561 std::string canonical_suffix =
562 http_server_properties_impl_->GetCanonicalSuffix(server);
563 if (!canonical_suffix.empty()) {
564 if (persisted_map.find(canonical_suffix) != persisted_map.end())
565 continue;
566 persisted_map[canonical_suffix] = true;
568 alternate_protocol_map->Put(server, it->second);
569 ++count;
572 // Update the preferences on the pref thread.
573 pref_task_runner_->PostTask(
574 FROM_HERE,
575 base::Bind(&HttpServerPropertiesManager::UpdatePrefsOnPrefThread,
576 pref_weak_ptr_,
577 base::Owned(spdy_server_list),
578 base::Owned(spdy_settings_map),
579 base::Owned(alternate_protocol_map),
580 completion));
583 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
584 // and AlternateProtocolInfo preferences for a server. This is used only in
585 // UpdatePrefsOnPrefThread.
586 struct ServerPref {
587 ServerPref()
588 : supports_spdy(false), settings_map(NULL), alternate_protocol(NULL) {}
589 ServerPref(bool supports_spdy,
590 const net::SettingsMap* settings_map,
591 const net::AlternateProtocolInfo* alternate_protocol)
592 : supports_spdy(supports_spdy),
593 settings_map(settings_map),
594 alternate_protocol(alternate_protocol) {}
595 bool supports_spdy;
596 const net::SettingsMap* settings_map;
597 const net::AlternateProtocolInfo* alternate_protocol;
600 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
601 base::ListValue* spdy_server_list,
602 net::SpdySettingsMap* spdy_settings_map,
603 net::AlternateProtocolMap* alternate_protocol_map,
604 const base::Closure& completion) {
605 typedef std::map<net::HostPortPair, ServerPref> ServerPrefMap;
606 ServerPrefMap server_pref_map;
608 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
610 // Add servers that support spdy to server_pref_map.
611 std::string s;
612 for (base::ListValue::const_iterator list_it = spdy_server_list->begin();
613 list_it != spdy_server_list->end();
614 ++list_it) {
615 if ((*list_it)->GetAsString(&s)) {
616 net::HostPortPair server = net::HostPortPair::FromString(s);
618 ServerPrefMap::iterator it = server_pref_map.find(server);
619 if (it == server_pref_map.end()) {
620 ServerPref server_pref(true, NULL, NULL);
621 server_pref_map[server] = server_pref;
622 } else {
623 it->second.supports_spdy = true;
628 // Add servers that have SpdySettings to server_pref_map.
629 for (net::SpdySettingsMap::iterator map_it = spdy_settings_map->begin();
630 map_it != spdy_settings_map->end();
631 ++map_it) {
632 const net::HostPortPair& server = map_it->first;
634 ServerPrefMap::iterator it = server_pref_map.find(server);
635 if (it == server_pref_map.end()) {
636 ServerPref server_pref(false, &map_it->second, NULL);
637 server_pref_map[server] = server_pref;
638 } else {
639 it->second.settings_map = &map_it->second;
643 // Add AlternateProtocol servers to server_pref_map.
644 for (net::AlternateProtocolMap::const_iterator map_it =
645 alternate_protocol_map->begin();
646 map_it != alternate_protocol_map->end();
647 ++map_it) {
648 const net::HostPortPair& server = map_it->first;
649 const net::AlternateProtocolInfo& port_alternate_protocol =
650 map_it->second;
651 if (!net::IsAlternateProtocolValid(port_alternate_protocol.protocol)) {
652 continue;
655 ServerPrefMap::iterator it = server_pref_map.find(server);
656 if (it == server_pref_map.end()) {
657 ServerPref server_pref(false, NULL, &map_it->second);
658 server_pref_map[server] = server_pref;
659 } else {
660 it->second.alternate_protocol = &map_it->second;
664 // Persist properties to the |path_|.
665 base::DictionaryValue http_server_properties_dict;
666 base::DictionaryValue* servers_dict = new base::DictionaryValue;
667 for (ServerPrefMap::const_iterator map_it = server_pref_map.begin();
668 map_it != server_pref_map.end();
669 ++map_it) {
670 const net::HostPortPair& server = map_it->first;
671 const ServerPref& server_pref = map_it->second;
673 base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
675 // Save supports_spdy.
676 if (server_pref.supports_spdy)
677 server_pref_dict->SetBoolean("supports_spdy", server_pref.supports_spdy);
679 // Save SPDY settings.
680 if (server_pref.settings_map) {
681 base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
682 for (net::SettingsMap::const_iterator it =
683 server_pref.settings_map->begin();
684 it != server_pref.settings_map->end();
685 ++it) {
686 net::SpdySettingsIds id = it->first;
687 uint32 value = it->second.second;
688 std::string key = base::StringPrintf("%u", id);
689 spdy_settings_dict->SetInteger(key, value);
691 server_pref_dict->SetWithoutPathExpansion("settings", spdy_settings_dict);
694 // Save alternate_protocol.
695 if (server_pref.alternate_protocol) {
696 base::DictionaryValue* port_alternate_protocol_dict =
697 new base::DictionaryValue;
698 const net::AlternateProtocolInfo* port_alternate_protocol =
699 server_pref.alternate_protocol;
700 port_alternate_protocol_dict->SetInteger("port",
701 port_alternate_protocol->port);
702 const char* protocol_str =
703 net::AlternateProtocolToString(port_alternate_protocol->protocol);
704 port_alternate_protocol_dict->SetString("protocol_str", protocol_str);
705 port_alternate_protocol_dict->SetDouble(
706 "probability", port_alternate_protocol->probability);
707 server_pref_dict->SetWithoutPathExpansion(
708 "alternate_protocol", port_alternate_protocol_dict);
711 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
714 http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict);
715 SetVersion(&http_server_properties_dict, kVersionNumber);
716 setting_prefs_ = true;
717 pref_service_->Set(path_, http_server_properties_dict);
718 setting_prefs_ = false;
720 // Note that |completion| will be fired after we have written everything to
721 // the Preferences, but likely before these changes are serialized to disk.
722 // This is not a problem though, as JSONPrefStore guarantees that this will
723 // happen, pretty soon, and even in the case we shut down immediately.
724 if (!completion.is_null())
725 completion.Run();
728 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
729 DCHECK(pref_task_runner_->RunsTasksOnCurrentThread());
730 if (!setting_prefs_)
731 ScheduleUpdateCacheOnPrefThread();
734 } // namespace net