- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / http_server_properties_manager.cc
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
21 using content::BrowserThread;
22
23 namespace chrome_browser_net {
24
25 namespace {
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.
30 const 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.
35 const int64 kUpdatePrefsDelayMs = 5000;
36
37 // "version" 0 indicates, http_server_properties doesn't have "version"
38 // property.
39 const int kMissingVersion = 0;
40
41 // The version number of persisted http_server_properties.
42 const int kVersionNumber = 2;
43
44 typedef std::vector<std::string> StringVector;
45
46 }  // namespace
47
48 ////////////////////////////////////////////////////////////////////////////////
49 //  HttpServerPropertiesManager
50
51 HttpServerPropertiesManager::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
69 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
70   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71   io_weak_ptr_factory_.reset();
72 }
73
74 void 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
90 void 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
99 void HttpServerPropertiesManager::RegisterProfilePrefs(
100     user_prefs::PrefRegistrySyncable* prefs) {
101   prefs->RegisterDictionaryPref(
102       prefs::kHttpServerProperties,
103       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
104 }
105
106 // static
107 void 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.
118 base::WeakPtr<net::HttpServerProperties>
119     HttpServerPropertiesManager::GetWeakPtr() {
120   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
121   return io_weak_ptr_factory_->GetWeakPtr();
122 }
123
124 void HttpServerPropertiesManager::Clear() {
125   Clear(base::Closure());
126 }
127
128 void HttpServerPropertiesManager::Clear(const base::Closure& completion) {
129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130
131   http_server_properties_impl_->Clear();
132   UpdatePrefsFromCacheOnIO(completion);
133 }
134
135 bool HttpServerPropertiesManager::SupportsSpdy(
136     const net::HostPortPair& server) const {
137   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
138   return http_server_properties_impl_->SupportsSpdy(server);
139 }
140
141 void 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
150 bool HttpServerPropertiesManager::HasAlternateProtocol(
151     const net::HostPortPair& server) const {
152   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
153   return http_server_properties_impl_->HasAlternateProtocol(server);
154 }
155
156 net::PortAlternateProtocolPair
157 HttpServerPropertiesManager::GetAlternateProtocol(
158     const net::HostPortPair& server) const {
159   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
160   return http_server_properties_impl_->GetAlternateProtocol(server);
161 }
162
163 void 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
173 void HttpServerPropertiesManager::SetBrokenAlternateProtocol(
174     const net::HostPortPair& server) {
175   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
176   http_server_properties_impl_->SetBrokenAlternateProtocol(server);
177   ScheduleUpdatePrefsOnIO();
178 }
179
180 const net::AlternateProtocolMap&
181 HttpServerPropertiesManager::alternate_protocol_map() const {
182   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
183   return http_server_properties_impl_->alternate_protocol_map();
184 }
185
186 const net::SettingsMap&
187 HttpServerPropertiesManager::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
193 bool 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
206 void 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
213 void HttpServerPropertiesManager::ClearAllSpdySettings() {
214   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
215   http_server_properties_impl_->ClearAllSpdySettings();
216   ScheduleUpdatePrefsOnIO();
217 }
218
219 const net::SpdySettingsMap&
220 HttpServerPropertiesManager::spdy_settings_map() const {
221   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222   return http_server_properties_impl_->spdy_settings_map();
223 }
224
225 net::HttpPipelinedHostCapability
226 HttpServerPropertiesManager::GetPipelineCapability(
227     const net::HostPortPair& origin) {
228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
229   return http_server_properties_impl_->GetPipelineCapability(origin);
230 }
231
232 void 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
240 void HttpServerPropertiesManager::ClearPipelineCapabilities() {
241   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
242   http_server_properties_impl_->ClearPipelineCapabilities();
243   ScheduleUpdatePrefsOnIO();
244 }
245
246 net::PipelineCapabilityMap
247 HttpServerPropertiesManager::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 //
255 void 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
263 void 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
271 void 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 (!net::IsAlternateProtocolValid(protocol)) {
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
428 void 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 //
467 void 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
475 void 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.
485 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnIO() {
486   UpdatePrefsFromCacheOnIO(base::Closure());
487 }
488
489 void 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.
525 struct 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
546 void 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 (!net::IsAlternateProtocolValid(port_alternate_protocol.protocol)) {
598       continue;
599     }
600
601     ServerPrefMap::iterator it = server_pref_map.find(server);
602     if (it == server_pref_map.end()) {
603       ServerPref server_pref(false, NULL, &map_it->second);
604       server_pref_map[server] = server_pref;
605     } else {
606       it->second.alternate_protocol = &map_it->second;
607     }
608   }
609
610   for (net::PipelineCapabilityMap::const_iterator map_it =
611            pipeline_capability_map->begin();
612        map_it != pipeline_capability_map->end(); ++map_it) {
613     const net::HostPortPair& server = map_it->first;
614     const net::HttpPipelinedHostCapability& pipeline_capability =
615         map_it->second;
616
617     ServerPrefMap::iterator it = server_pref_map.find(server);
618     if (it == server_pref_map.end()) {
619       ServerPref server_pref;
620       server_pref.pipeline_capability = pipeline_capability;
621       server_pref_map[server] = server_pref;
622     } else {
623       it->second.pipeline_capability = pipeline_capability;
624     }
625   }
626
627   // Persist the prefs::kHttpServerProperties.
628   base::DictionaryValue http_server_properties_dict;
629   base::DictionaryValue* servers_dict = new base::DictionaryValue;
630   for (ServerPrefMap::const_iterator map_it =
631        server_pref_map.begin();
632        map_it != server_pref_map.end(); ++map_it) {
633     const net::HostPortPair& server = map_it->first;
634     const ServerPref& server_pref = map_it->second;
635
636     base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
637
638     // Save supports_spdy.
639     server_pref_dict->SetBoolean("supports_spdy", server_pref.supports_spdy);
640
641     // Save SPDY settings.
642     if (server_pref.settings_map) {
643       base::DictionaryValue* spdy_settings_dict = new base::DictionaryValue;
644       for (net::SettingsMap::const_iterator it =
645            server_pref.settings_map->begin();
646            it != server_pref.settings_map->end(); ++it) {
647         net::SpdySettingsIds id = it->first;
648         uint32 value = it->second.second;
649         std::string key = base::StringPrintf("%u", id);
650         spdy_settings_dict->SetInteger(key, value);
651       }
652       server_pref_dict->SetWithoutPathExpansion("settings", spdy_settings_dict);
653     }
654
655     // Save alternate_protocol.
656     if (server_pref.alternate_protocol) {
657       base::DictionaryValue* port_alternate_protocol_dict =
658           new base::DictionaryValue;
659       const net::PortAlternateProtocolPair* port_alternate_protocol =
660           server_pref.alternate_protocol;
661       port_alternate_protocol_dict->SetInteger(
662           "port", port_alternate_protocol->port);
663       const char* protocol_str =
664           net::AlternateProtocolToString(port_alternate_protocol->protocol);
665       port_alternate_protocol_dict->SetString("protocol_str", protocol_str);
666       server_pref_dict->SetWithoutPathExpansion(
667           "alternate_protocol", port_alternate_protocol_dict);
668     }
669
670     if (server_pref.pipeline_capability != net::PIPELINE_UNKNOWN) {
671       server_pref_dict->SetInteger("pipeline_capability",
672                                    server_pref.pipeline_capability);
673     }
674
675     servers_dict->SetWithoutPathExpansion(server.ToString(), server_pref_dict);
676   }
677
678   http_server_properties_dict.SetWithoutPathExpansion("servers", servers_dict);
679   SetVersion(&http_server_properties_dict, kVersionNumber);
680   setting_prefs_ = true;
681   pref_service_->Set(prefs::kHttpServerProperties,
682                      http_server_properties_dict);
683   setting_prefs_ = false;
684
685   // Note that |completion| will be fired after we have written everything to
686   // the Preferences, but likely before these changes are serialized to disk.
687   // This is not a problem though, as JSONPrefStore guarantees that this will
688   // happen, pretty soon, and even in the case we shut down immediately.
689   if (!completion.is_null())
690     completion.Run();
691 }
692
693 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
694   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
695   if (!setting_prefs_)
696     ScheduleUpdateCacheOnUI();
697 }
698
699 }  // namespace chrome_browser_net