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