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