1// Copyright (c) 2012 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. 4 5#include "chrome/browser/net/http_server_properties_manager.h" 6 7#include "base/bind.h" 8#include "base/metrics/histogram.h" 9#include "base/prefs/pref_service.h" 10#include "base/stl_util.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/strings/stringprintf.h" 13#include "base/values.h" 14#include "chrome/browser/chrome_notification_types.h" 15#include "chrome/common/pref_names.h" 16#include "components/user_prefs/pref_registry_syncable.h" 17#include "content/public/browser/browser_thread.h" 18#include "content/public/browser/notification_details.h" 19#include "content/public/browser/notification_source.h" 20 21using content::BrowserThread; 22 23namespace chrome_browser_net { 24 25namespace { 26 27// Time to wait before starting an update the http_server_properties_impl_ cache 28// from preferences. Scheduling another update during this period will reset the 29// timer. 30const int64 kUpdateCacheDelayMs = 1000; 31 32// Time to wait before starting an update the preferences from the 33// http_server_properties_impl_ cache. Scheduling another update during this 34// period will reset the timer. 35const int64 kUpdatePrefsDelayMs = 5000; 36 37// "version" 0 indicates, http_server_properties doesn't have "version" 38// property. 39const int kMissingVersion = 0; 40 41// The version number of persisted http_server_properties. 42const int kVersionNumber = 2; 43 44typedef std::vector<std::string> StringVector; 45 46} // namespace 47 48//////////////////////////////////////////////////////////////////////////////// 49// HttpServerPropertiesManager 50 51HttpServerPropertiesManager::HttpServerPropertiesManager( 52 PrefService* pref_service) 53 : pref_service_(pref_service), 54 setting_prefs_(false) { 55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 56 DCHECK(pref_service); 57 ui_weak_ptr_factory_.reset( 58 new base::WeakPtrFactory<HttpServerPropertiesManager>(this)); 59 ui_weak_ptr_ = ui_weak_ptr_factory_->GetWeakPtr(); 60 ui_cache_update_timer_.reset( 61 new base::OneShotTimer<HttpServerPropertiesManager>); 62 pref_change_registrar_.Init(pref_service_); 63 pref_change_registrar_.Add( 64 prefs::kHttpServerProperties, 65 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged, 66 base::Unretained(this))); 67} 68 69HttpServerPropertiesManager::~HttpServerPropertiesManager() { 70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 71 io_weak_ptr_factory_.reset(); 72} 73 74void HttpServerPropertiesManager::InitializeOnIOThread() { 75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 76 io_weak_ptr_factory_.reset( 77 new base::WeakPtrFactory<HttpServerPropertiesManager>(this)); 78 http_server_properties_impl_.reset(new net::HttpServerPropertiesImpl()); 79 80 io_prefs_update_timer_.reset( 81 new base::OneShotTimer<HttpServerPropertiesManager>); 82 83 BrowserThread::PostTask( 84 BrowserThread::UI, 85 FROM_HERE, 86 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnUI, 87 ui_weak_ptr_)); 88} 89 90void HttpServerPropertiesManager::ShutdownOnUIThread() { 91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 92 // Cancel any pending updates, and stop listening for pref change updates. 93 ui_cache_update_timer_->Stop(); 94 ui_weak_ptr_factory_.reset(); 95 pref_change_registrar_.RemoveAll(); 96} 97 98// static 99void HttpServerPropertiesManager::RegisterProfilePrefs( 100 user_prefs::PrefRegistrySyncable* prefs) { 101 prefs->RegisterDictionaryPref( 102 prefs::kHttpServerProperties, 103 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 104} 105 106// static 107void HttpServerPropertiesManager::SetVersion( 108 base::DictionaryValue* http_server_properties_dict, 109 int version_number) { 110 if (version_number < 0) 111 version_number = kVersionNumber; 112 DCHECK_LE(version_number, kVersionNumber); 113 if (version_number <= kVersionNumber) 114 http_server_properties_dict->SetInteger("version", version_number); 115} 116 117// This is required for conformance with the HttpServerProperties interface. 118base::WeakPtr<net::HttpServerProperties> 119 HttpServerPropertiesManager::GetWeakPtr() { 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 121 return io_weak_ptr_factory_->GetWeakPtr(); 122} 123 124void HttpServerPropertiesManager::Clear() { 125 Clear(base::Closure()); 126} 127 128void HttpServerPropertiesManager::Clear(const base::Closure& completion) { 129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 130 131 http_server_properties_impl_->Clear(); 132 UpdatePrefsFromCacheOnIO(completion); 133} 134 135bool HttpServerPropertiesManager::SupportsSpdy( 136 const net::HostPortPair& server) const { 137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 138 return http_server_properties_impl_->SupportsSpdy(server); 139} 140 141void HttpServerPropertiesManager::SetSupportsSpdy( 142 const net::HostPortPair& server, 143 bool support_spdy) { 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 145 146 http_server_properties_impl_->SetSupportsSpdy(server, support_spdy); 147 ScheduleUpdatePrefsOnIO(); 148} 149 150bool HttpServerPropertiesManager::HasAlternateProtocol( 151 const net::HostPortPair& server) const { 152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 153 return http_server_properties_impl_->HasAlternateProtocol(server); 154} 155 156net::PortAlternateProtocolPair 157HttpServerPropertiesManager::GetAlternateProtocol( 158 const net::HostPortPair& server) const { 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 160 return http_server_properties_impl_->GetAlternateProtocol(server); 161} 162 163void HttpServerPropertiesManager::SetAlternateProtocol( 164 const net::HostPortPair& server, 165 uint16 alternate_port, 166 net::AlternateProtocol alternate_protocol) { 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 168 http_server_properties_impl_->SetAlternateProtocol( 169 server, alternate_port, alternate_protocol); 170 ScheduleUpdatePrefsOnIO(); 171} 172 173void HttpServerPropertiesManager::SetBrokenAlternateProtocol( 174 const net::HostPortPair& server) { 175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 176 http_server_properties_impl_->SetBrokenAlternateProtocol(server); 177 ScheduleUpdatePrefsOnIO(); 178} 179 180const net::AlternateProtocolMap& 181HttpServerPropertiesManager::alternate_protocol_map() const { 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 183 return http_server_properties_impl_->alternate_protocol_map(); 184} 185 186const net::SettingsMap& 187HttpServerPropertiesManager::GetSpdySettings( 188 const net::HostPortPair& host_port_pair) const { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 190 return http_server_properties_impl_->GetSpdySettings(host_port_pair); 191} 192 193bool HttpServerPropertiesManager::SetSpdySetting( 194 const net::HostPortPair& host_port_pair, 195 net::SpdySettingsIds id, 196 net::SpdySettingsFlags flags, 197 uint32 value) { 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 199 bool persist = http_server_properties_impl_->SetSpdySetting( 200 host_port_pair, id, flags, value); 201 if (persist) 202 ScheduleUpdatePrefsOnIO(); 203 return persist; 204} 205 206void HttpServerPropertiesManager::ClearSpdySettings( 207 const net::HostPortPair& host_port_pair) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 209 http_server_properties_impl_->ClearSpdySettings(host_port_pair); 210 ScheduleUpdatePrefsOnIO(); 211} 212 213void HttpServerPropertiesManager::ClearAllSpdySettings() { 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 215 http_server_properties_impl_->ClearAllSpdySettings(); 216 ScheduleUpdatePrefsOnIO(); 217} 218 219const net::SpdySettingsMap& 220HttpServerPropertiesManager::spdy_settings_map() const { 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 222 return http_server_properties_impl_->spdy_settings_map(); 223} 224 225net::HttpPipelinedHostCapability 226HttpServerPropertiesManager::GetPipelineCapability( 227 const net::HostPortPair& origin) { 228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 229 return http_server_properties_impl_->GetPipelineCapability(origin); 230} 231 232void HttpServerPropertiesManager::SetPipelineCapability( 233 const net::HostPortPair& origin, 234 net::HttpPipelinedHostCapability capability) { 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 236 http_server_properties_impl_->SetPipelineCapability(origin, capability); 237 ScheduleUpdatePrefsOnIO(); 238} 239 240void HttpServerPropertiesManager::ClearPipelineCapabilities() { 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 242 http_server_properties_impl_->ClearPipelineCapabilities(); 243 ScheduleUpdatePrefsOnIO(); 244} 245 246net::PipelineCapabilityMap 247HttpServerPropertiesManager::GetPipelineCapabilityMap() const { 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 249 return http_server_properties_impl_->GetPipelineCapabilityMap(); 250} 251 252// 253// Update the HttpServerPropertiesImpl's cache with data from preferences. 254// 255void HttpServerPropertiesManager::ScheduleUpdateCacheOnUI() { 256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 257 // Cancel pending updates, if any. 258 ui_cache_update_timer_->Stop(); 259 StartCacheUpdateTimerOnUI( 260 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs)); 261} 262 263void HttpServerPropertiesManager::StartCacheUpdateTimerOnUI( 264 base::TimeDelta delay) { 265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 266 ui_cache_update_timer_->Start( 267 FROM_HERE, delay, this, 268 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnUI); 269} 270 271void HttpServerPropertiesManager::UpdateCacheFromPrefsOnUI() { 272 // The preferences can only be read on the UI thread. 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 274 275 if (!pref_service_->HasPrefPath(prefs::kHttpServerProperties)) 276 return; 277 278 bool detected_corrupted_prefs = false; 279 const base::DictionaryValue& http_server_properties_dict = 280 *pref_service_->GetDictionary(prefs::kHttpServerProperties); 281 282 int version = kMissingVersion; 283 if (!http_server_properties_dict.GetIntegerWithoutPathExpansion( 284 "version", &version)) { 285 DVLOG(1) << "Missing version. Clearing all properties."; 286 return; 287 } 288 289 // The properties for a given server is in 290 // http_server_properties_dict["servers"][server]. 291 const base::DictionaryValue* servers_dict = NULL; 292 if (!http_server_properties_dict.GetDictionaryWithoutPathExpansion( 293 "servers", &servers_dict)) { 294 DVLOG(1) << "Malformed http_server_properties for servers."; 295 return; 296 } 297 298 // TODO(rtenneti): Mark entries with an LRU sequence number (date of access?), 299 // and then truncate down deleting old stuff. 300 if (version != kVersionNumber && servers_dict->size() > 300) { 301 DVLOG(1) << "Size is too large. Clearing all properties."; 302 return; 303 } 304 305 // String is host/port pair of spdy server. 306 scoped_ptr<StringVector> spdy_servers(new StringVector); 307 scoped_ptr<net::SpdySettingsMap> spdy_settings_map(new net::SpdySettingsMap); 308 scoped_ptr<net::PipelineCapabilityMap> pipeline_capability_map( 309 new net::PipelineCapabilityMap); 310 scoped_ptr<net::AlternateProtocolMap> alternate_protocol_map( 311 new net::AlternateProtocolMap); 312 313 for (base::DictionaryValue::Iterator it(*servers_dict); !it.IsAtEnd(); 314 it.Advance()) { 315 // Get server's host/pair. 316 const std::string& server_str = it.key(); 317 net::HostPortPair server = net::HostPortPair::FromString(server_str); 318 if (server.host().empty()) { 319 DVLOG(1) << "Malformed http_server_properties for server: " << server_str; 320 detected_corrupted_prefs = true; 321 continue; 322 } 323 324 const base::DictionaryValue* server_pref_dict = NULL; 325 if (!it.value().GetAsDictionary(&server_pref_dict)) { 326 DVLOG(1) << "Malformed http_server_properties server: " << server_str; 327 detected_corrupted_prefs = true; 328 continue; 329 } 330 331 // Get if server supports Spdy. 332 bool supports_spdy = false; 333 if ((server_pref_dict->GetBoolean( 334 "supports_spdy", &supports_spdy)) && supports_spdy) { 335 spdy_servers->push_back(server_str); 336 } 337 338 // Get SpdySettings. 339 DCHECK(!ContainsKey(*spdy_settings_map, server)); 340 const base::DictionaryValue* spdy_settings_dict = NULL; 341 if (server_pref_dict->GetDictionaryWithoutPathExpansion( 342 "settings", &spdy_settings_dict)) { 343 net::SettingsMap settings_map; 344 for (base::DictionaryValue::Iterator dict_it(*spdy_settings_dict); 345 !dict_it.IsAtEnd(); dict_it.Advance()) { 346 const std::string& id_str = dict_it.key(); 347 int id = 0; 348 if (!base::StringToInt(id_str, &id)) { 349 DVLOG(1) << "Malformed id in SpdySettings for server: " << 350 server_str; 351 NOTREACHED(); 352 continue; 353 } 354 int value = 0; 355 if (!dict_it.value().GetAsInteger(&value)) { 356 DVLOG(1) << "Malformed value in SpdySettings for server: " << 357 server_str; 358 NOTREACHED(); 359 continue; 360 } 361 net::SettingsFlagsAndValue flags_and_value( 362 net::SETTINGS_FLAG_PERSISTED, value); 363 settings_map[static_cast<net::SpdySettingsIds>(id)] = flags_and_value; 364 } 365 (*spdy_settings_map)[server] = settings_map; 366 } 367 368 int pipeline_capability = net::PIPELINE_UNKNOWN; 369 if ((server_pref_dict->GetInteger( 370 "pipeline_capability", &pipeline_capability)) && 371 pipeline_capability != net::PIPELINE_UNKNOWN) { 372 (*pipeline_capability_map)[server] = 373 static_cast<net::HttpPipelinedHostCapability>(pipeline_capability); 374 } 375 376 // Get alternate_protocol server. 377 DCHECK(!ContainsKey(*alternate_protocol_map, server)); 378 const base::DictionaryValue* port_alternate_protocol_dict = NULL; 379 if (!server_pref_dict->GetDictionaryWithoutPathExpansion( 380 "alternate_protocol", &port_alternate_protocol_dict)) { 381 continue; 382 } 383 384 do { 385 int port = 0; 386 if (!port_alternate_protocol_dict->GetIntegerWithoutPathExpansion( 387 "port", &port) || (port > (1 << 16))) { 388 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str; 389 detected_corrupted_prefs = true; 390 continue; 391 } 392 std::string protocol_str; 393 if (!port_alternate_protocol_dict->GetStringWithoutPathExpansion( 394 "protocol_str", &protocol_str)) { 395 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str; 396 detected_corrupted_prefs = true; 397 continue; 398 } 399 net::AlternateProtocol protocol = 400 net::AlternateProtocolFromString(protocol_str); 401 if (protocol > net::NUM_ALTERNATE_PROTOCOLS) { 402 DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str; 403 detected_corrupted_prefs = true; 404 continue; 405 } 406 407 net::PortAlternateProtocolPair port_alternate_protocol; 408 port_alternate_protocol.port = port; 409 port_alternate_protocol.protocol = protocol; 410 411 (*alternate_protocol_map)[server] = port_alternate_protocol; 412 } while (false); 413 } 414 415 BrowserThread::PostTask( 416 BrowserThread::IO, 417 FROM_HERE, 418 base::Bind(&HttpServerPropertiesManager:: 419 UpdateCacheFromPrefsOnIO, 420 base::Unretained(this), 421 base::Owned(spdy_servers.release()), 422 base::Owned(spdy_settings_map.release()), 423 base::Owned(alternate_protocol_map.release()), 424 base::Owned(pipeline_capability_map.release()), 425 detected_corrupted_prefs)); 426} 427 428void HttpServerPropertiesManager::UpdateCacheFromPrefsOnIO( 429 StringVector* spdy_servers, 430 net::SpdySettingsMap* spdy_settings_map, 431 net::AlternateProtocolMap* alternate_protocol_map, 432 net::PipelineCapabilityMap* pipeline_capability_map, 433 bool detected_corrupted_prefs) { 434 // Preferences have the master data because admins might have pushed new 435 // preferences. Update the cached data with new data from preferences. 436 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 437 438 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers->size()); 439 http_server_properties_impl_->InitializeSpdyServers(spdy_servers, true); 440 441 // Clear the cached data and use the new spdy_settings from preferences. 442 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map->size()); 443 http_server_properties_impl_->InitializeSpdySettingsServers( 444 spdy_settings_map); 445 446 // Clear the cached data and use the new Alternate-Protocol server list from 447 // preferences. 448 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers", 449 alternate_protocol_map->size()); 450 http_server_properties_impl_->InitializeAlternateProtocolServers( 451 alternate_protocol_map); 452 453 UMA_HISTOGRAM_COUNTS("Net.CountOfPipelineCapableServers", 454 pipeline_capability_map->size()); 455 http_server_properties_impl_->InitializePipelineCapabilities( 456 pipeline_capability_map); 457 458 // Update the prefs with what we have read (delete all corrupted prefs). 459 if (detected_corrupted_prefs) 460 ScheduleUpdatePrefsOnIO(); 461} 462 463 464// 465// Update Preferences with data from the cached data. 466// 467void HttpServerPropertiesManager::ScheduleUpdatePrefsOnIO() { 468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 469 // Cancel pending updates, if any. 470 io_prefs_update_timer_->Stop(); 471 StartPrefsUpdateTimerOnIO( 472 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs)); 473} 474 475void HttpServerPropertiesManager::StartPrefsUpdateTimerOnIO( 476 base::TimeDelta delay) { 477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 478 // This is overridden in tests to post the task without the delay. 479 io_prefs_update_timer_->Start( 480 FROM_HERE, delay, this, 481 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnIO); 482} 483 484// This is required so we can set this as the callback for a timer. 485void HttpServerPropertiesManager::UpdatePrefsFromCacheOnIO() { 486 UpdatePrefsFromCacheOnIO(base::Closure()); 487} 488 489void HttpServerPropertiesManager::UpdatePrefsFromCacheOnIO( 490 const base::Closure& completion) { 491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 492 493 base::ListValue* spdy_server_list = new base::ListValue; 494 http_server_properties_impl_->GetSpdyServerList(spdy_server_list); 495 496 net::SpdySettingsMap* spdy_settings_map = new net::SpdySettingsMap; 497 *spdy_settings_map = http_server_properties_impl_->spdy_settings_map(); 498 499 net::AlternateProtocolMap* alternate_protocol_map = 500 new net::AlternateProtocolMap; 501 *alternate_protocol_map = 502 http_server_properties_impl_->alternate_protocol_map(); 503 504 net::PipelineCapabilityMap* pipeline_capability_map = 505 new net::PipelineCapabilityMap; 506 *pipeline_capability_map = 507 http_server_properties_impl_->GetPipelineCapabilityMap(); 508 509 // Update the preferences on the UI thread. 510 BrowserThread::PostTask( 511 BrowserThread::UI, 512 FROM_HERE, 513 base::Bind(&HttpServerPropertiesManager::UpdatePrefsOnUI, 514 ui_weak_ptr_, 515 base::Owned(spdy_server_list), 516 base::Owned(spdy_settings_map), 517 base::Owned(alternate_protocol_map), 518 base::Owned(pipeline_capability_map), 519 completion)); 520} 521 522// A local or temporary data structure to hold |supports_spdy|, SpdySettings, 523// PortAlternateProtocolPair, and |pipeline_capability| preferences for a 524// server. This is used only in UpdatePrefsOnUI. 525struct ServerPref { 526 ServerPref() 527 : supports_spdy(false), 528 settings_map(NULL), 529 alternate_protocol(NULL), 530 pipeline_capability(net::PIPELINE_UNKNOWN) { 531 } 532 ServerPref(bool supports_spdy, 533 const net::SettingsMap* settings_map, 534 const net::PortAlternateProtocolPair* alternate_protocol) 535 : supports_spdy(supports_spdy), 536 settings_map(settings_map), 537 alternate_protocol(alternate_protocol), 538 pipeline_capability(net::PIPELINE_UNKNOWN) { 539 } 540 bool supports_spdy; 541 const net::SettingsMap* settings_map; 542 const net::PortAlternateProtocolPair* alternate_protocol; 543 net::HttpPipelinedHostCapability pipeline_capability; 544}; 545 546void HttpServerPropertiesManager::UpdatePrefsOnUI( 547 base::ListValue* spdy_server_list, 548 net::SpdySettingsMap* spdy_settings_map, 549 net::AlternateProtocolMap* alternate_protocol_map, 550 net::PipelineCapabilityMap* pipeline_capability_map, 551 const base::Closure& completion) { 552 553 typedef std::map<net::HostPortPair, ServerPref> ServerPrefMap; 554 ServerPrefMap server_pref_map; 555 556 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 557 558 // Add servers that support spdy to server_pref_map. 559 std::string s; 560 for (base::ListValue::const_iterator list_it = spdy_server_list->begin(); 561 list_it != spdy_server_list->end(); ++list_it) { 562 if ((*list_it)->GetAsString(&s)) { 563 net::HostPortPair server = net::HostPortPair::FromString(s); 564 565 ServerPrefMap::iterator it = server_pref_map.find(server); 566 if (it == server_pref_map.end()) { 567 ServerPref server_pref(true, NULL, NULL); 568 server_pref_map[server] = server_pref; 569 } else { 570 it->second.supports_spdy = true; 571 } 572 } 573 } 574 575 // Add servers that have SpdySettings to server_pref_map. 576 for (net::SpdySettingsMap::iterator map_it = 577 spdy_settings_map->begin(); 578 map_it != spdy_settings_map->end(); ++map_it) { 579 const net::HostPortPair& server = map_it->first; 580 581 ServerPrefMap::iterator it = server_pref_map.find(server); 582 if (it == server_pref_map.end()) { 583 ServerPref server_pref(false, &map_it->second, NULL); 584 server_pref_map[server] = server_pref; 585 } else { 586 it->second.settings_map = &map_it->second; 587 } 588 } 589 590 // Add AlternateProtocol servers to server_pref_map. 591 for (net::AlternateProtocolMap::const_iterator map_it = 592 alternate_protocol_map->begin(); 593 map_it != alternate_protocol_map->end(); ++map_it) { 594 const net::HostPortPair& server = map_it->first; 595 const net::PortAlternateProtocolPair& port_alternate_protocol = 596 map_it->second; 597 if (port_alternate_protocol.protocol < 0 || 598 port_alternate_protocol.protocol >= net::NUM_ALTERNATE_PROTOCOLS) { 599 continue; 600 } 601 602 ServerPrefMap::iterator it = server_pref_map.find(server); 603 if (it == server_pref_map.end()) { 604 ServerPref server_pref(false, NULL, &map_it->second); 605 server_pref_map[server] = server_pref; 606 } else { 607 it->second.alternate_protocol = &map_it->second; 608 } 609 } 610 611 for (net::PipelineCapabilityMap::const_iterator map_it = 612 pipeline_capability_map->begin(); 613 map_it != pipeline_capability_map->end(); ++map_it) { 614 const net::HostPortPair& server = map_it->first; 615 const net::HttpPipelinedHostCapability& pipeline_capability = 616 map_it->second; 617 618 ServerPrefMap::iterator it = server_pref_map.find(server); 619 if (it == server_pref_map.end()) { 620 ServerPref server_pref; 621 server_pref.pipeline_capability = pipeline_capability; 622 server_pref_map[server] = server_pref; 623 } else { 624 it->second.pipeline_capability = pipeline_capability; 625 } 626 } 627 628 // Persist the prefs::kHttpServerProperties. 629 base::DictionaryValue http_server_properties_dict; 630 base::DictionaryValue* servers_dict = new base::DictionaryValue; 631 for (ServerPrefMap::const_iterator map_it = 632 server_pref_map.begin(); 633 map_it != server_pref_map.end(); ++map_it) { 634 const net::HostPortPair& server = map_it->first; 635 const ServerPref& server_pref = map_it->second; 636 637 base::DictionaryValue* server_pref_dict = new base::DictionaryValue; 638 639 // Save supports_spdy. 640 server_pref_dict->SetBoolean("supports_spdy", server_pref.supports_spdy); 641 642 // Save SPDY settings. 643 if (server_pref.settings_map) { 644 base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue; 645 for (net::SettingsMap::const_iterator it = 646 server_pref.settings_map->begin(); 647 it != server_pref.settings_map->end(); ++it) { 648 net::SpdySettingsIds id = it->first; 649 uint32 value = it->second.second; 650 std::string key = base::StringPrintf("%u", id); 651 spdy_settings_dict->SetInteger(key, value); 652 } 653 server_pref_dict->SetWithoutPathExpansion("settings", spdy_settings_dict); 654 } 655 656 // Save alternate_protocol. 657 if (server_pref.alternate_protocol) { 658 base::DictionaryValue* port_alternate_protocol_dict = 659 new base::DictionaryValue; 660 const net::PortAlternateProtocolPair* port_alternate_protocol = 661 server_pref.alternate_protocol; 662 port_alternate_protocol_dict->SetInteger( 663 "port", port_alternate_protocol->port); 664 const char* protocol_str = 665 net::AlternateProtocolToString(port_alternate_protocol->protocol); 666 port_alternate_protocol_dict->SetString("protocol_str", protocol_str); 667 server_pref_dict->SetWithoutPathExpansion( 668 "alternate_protocol", port_alternate_protocol_dict); 669 } 670 671 if (server_pref.pipeline_capability != net::PIPELINE_UNKNOWN) { 672 server_pref_dict->SetInteger("pipeline_capability", 673 server_pref.pipeline_capability); 674 } 675 676 servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict); 677 } 678 679 http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict); 680 SetVersion(&http_server_properties_dict, kVersionNumber); 681 setting_prefs_ = true; 682 pref_service_->Set(prefs::kHttpServerProperties, 683 http_server_properties_dict); 684 setting_prefs_ = false; 685 686 // Note that |completion| will be fired after we have written everything to 687 // the Preferences, but likely before these changes are serialized to disk. 688 // This is not a problem though, as JSONPrefStore guarantees that this will 689 // happen, pretty soon, and even in the case we shut down immediately. 690 if (!completion.is_null()) 691 completion.Run(); 692} 693 694void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() { 695 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 696 if (!setting_prefs_) 697 ScheduleUpdateCacheOnUI(); 698} 699 700} // namespace chrome_browser_net 701