1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/http_server_properties_manager.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/values.h"
16 #include "net/base/ip_address_number.h"
22 // Time to wait before starting an update the http_server_properties_impl_ cache
23 // from preferences. Scheduling another update during this period will reset the
25 const int64 kUpdateCacheDelayMs
= 1000;
27 // Time to wait before starting an update the preferences from the
28 // http_server_properties_impl_ cache. Scheduling another update during this
29 // period will reset the timer.
30 const int64 kUpdatePrefsDelayMs
= 60000;
32 // "version" 0 indicates, http_server_properties doesn't have "version"
34 const int kMissingVersion
= 0;
36 // The version number of persisted http_server_properties.
37 const int kVersionNumber
= 3;
39 typedef std::vector
<std::string
> StringVector
;
41 // Persist 200 MRU AlternateProtocolHostPortPairs.
42 const int kMaxAlternateProtocolHostsToPersist
= 200;
44 // Persist 200 MRU SpdySettingsHostPortPairs.
45 const int kMaxSpdySettingsHostsToPersist
= 200;
47 // Persist 300 MRU SupportsSpdyServerHostPortPairs.
48 const int kMaxSupportsSpdyServerHostsToPersist
= 300;
50 // Persist 200 ServerNetworkStats.
51 const int kMaxServerNetworkStatsHostsToPersist
= 200;
53 const char kVersionKey
[] = "version";
54 const char kServersKey
[] = "servers";
55 const char kSupportsSpdyKey
[] = "supports_spdy";
56 const char kSettingsKey
[] = "settings";
57 const char kSupportsQuicKey
[] = "supports_quic";
58 const char kUsedQuicKey
[] = "used_quic";
59 const char kAddressKey
[] = "address";
60 const char kAlternateProtocolKey
[] = "alternate_protocol";
61 const char kAlternativeServiceKey
[] = "alternative_service";
62 const char kProtocolKey
[] = "protocol_str";
63 const char kHostKey
[] = "host";
64 const char kPortKey
[] = "port";
65 const char kProbabilityKey
[] = "probability";
66 const char kNetworkStatsKey
[] = "network_stats";
67 const char kSrttKey
[] = "srtt";
71 ////////////////////////////////////////////////////////////////////////////////
72 // HttpServerPropertiesManager
74 HttpServerPropertiesManager::HttpServerPropertiesManager(
75 PrefService
* pref_service
,
76 const char* pref_path
,
77 scoped_refptr
<base::SequencedTaskRunner
> network_task_runner
)
78 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
79 pref_service_(pref_service
),
80 setting_prefs_(false),
82 network_task_runner_(network_task_runner
) {
84 pref_weak_ptr_factory_
.reset(
85 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
86 pref_weak_ptr_
= pref_weak_ptr_factory_
->GetWeakPtr();
87 pref_cache_update_timer_
.reset(
88 new base::OneShotTimer
<HttpServerPropertiesManager
>);
89 pref_change_registrar_
.Init(pref_service_
);
90 pref_change_registrar_
.Add(
92 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged
,
93 base::Unretained(this)));
96 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
97 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
98 network_weak_ptr_factory_
.reset();
101 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
102 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
103 network_weak_ptr_factory_
.reset(
104 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
105 http_server_properties_impl_
.reset(new HttpServerPropertiesImpl());
107 network_prefs_update_timer_
.reset(
108 new base::OneShotTimer
<HttpServerPropertiesManager
>);
110 pref_task_runner_
->PostTask(
112 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
,
116 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
117 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
118 // Cancel any pending updates, and stop listening for pref change updates.
119 pref_cache_update_timer_
->Stop();
120 pref_weak_ptr_factory_
.reset();
121 pref_change_registrar_
.RemoveAll();
125 void HttpServerPropertiesManager::SetVersion(
126 base::DictionaryValue
* http_server_properties_dict
,
127 int version_number
) {
128 if (version_number
< 0)
129 version_number
= kVersionNumber
;
130 DCHECK_LE(version_number
, kVersionNumber
);
131 if (version_number
<= kVersionNumber
)
132 http_server_properties_dict
->SetInteger(kVersionKey
, version_number
);
135 // This is required for conformance with the HttpServerProperties interface.
136 base::WeakPtr
<HttpServerProperties
> HttpServerPropertiesManager::GetWeakPtr() {
137 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
138 return network_weak_ptr_factory_
->GetWeakPtr();
141 void HttpServerPropertiesManager::Clear() {
142 Clear(base::Closure());
145 void HttpServerPropertiesManager::Clear(const base::Closure
& completion
) {
146 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
148 http_server_properties_impl_
->Clear();
149 UpdatePrefsFromCacheOnNetworkThread(completion
);
152 bool HttpServerPropertiesManager::SupportsRequestPriority(
153 const HostPortPair
& server
) {
154 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
155 return http_server_properties_impl_
->SupportsRequestPriority(server
);
158 bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair
& server
) {
159 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
160 return http_server_properties_impl_
->GetSupportsSpdy(server
);
163 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair
& server
,
165 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
167 bool old_support_spdy
= http_server_properties_impl_
->GetSupportsSpdy(server
);
168 http_server_properties_impl_
->SetSupportsSpdy(server
, support_spdy
);
169 bool new_support_spdy
= http_server_properties_impl_
->GetSupportsSpdy(server
);
170 if (old_support_spdy
!= new_support_spdy
)
171 ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY
);
174 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair
& server
) {
175 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
176 return http_server_properties_impl_
->RequiresHTTP11(server
);
179 void HttpServerPropertiesManager::SetHTTP11Required(
180 const HostPortPair
& server
) {
181 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
183 http_server_properties_impl_
->SetHTTP11Required(server
);
184 ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED
);
187 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair
& server
,
188 SSLConfig
* ssl_config
) {
189 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
190 http_server_properties_impl_
->MaybeForceHTTP11(server
, ssl_config
);
193 AlternativeServiceVector
HttpServerPropertiesManager::GetAlternativeServices(
194 const HostPortPair
& origin
) {
195 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
196 return http_server_properties_impl_
->GetAlternativeServices(origin
);
199 bool HttpServerPropertiesManager::SetAlternativeService(
200 const HostPortPair
& origin
,
201 const AlternativeService
& alternative_service
,
202 double alternative_probability
) {
203 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
204 const bool changed
= http_server_properties_impl_
->SetAlternativeService(
205 origin
, alternative_service
, alternative_probability
);
207 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES
);
212 bool HttpServerPropertiesManager::SetAlternativeServices(
213 const HostPortPair
& origin
,
214 const AlternativeServiceInfoVector
& alternative_service_info_vector
) {
215 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
216 const bool changed
= http_server_properties_impl_
->SetAlternativeServices(
217 origin
, alternative_service_info_vector
);
219 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES
);
224 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
225 const AlternativeService
& alternative_service
) {
226 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
227 http_server_properties_impl_
->MarkAlternativeServiceBroken(
228 alternative_service
);
229 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN
);
232 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
233 const AlternativeService
& alternative_service
) {
234 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
235 http_server_properties_impl_
->MarkAlternativeServiceRecentlyBroken(
236 alternative_service
);
237 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN
);
240 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
241 const AlternativeService
& alternative_service
) const {
242 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
243 return http_server_properties_impl_
->IsAlternativeServiceBroken(
244 alternative_service
);
247 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
248 const AlternativeService
& alternative_service
) {
249 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
250 return http_server_properties_impl_
->WasAlternativeServiceRecentlyBroken(
251 alternative_service
);
254 void HttpServerPropertiesManager::ConfirmAlternativeService(
255 const AlternativeService
& alternative_service
) {
256 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
257 bool old_value
= http_server_properties_impl_
->IsAlternativeServiceBroken(
258 alternative_service
);
259 http_server_properties_impl_
->ConfirmAlternativeService(alternative_service
);
260 bool new_value
= http_server_properties_impl_
->IsAlternativeServiceBroken(
261 alternative_service
);
262 // For persisting, we only care about the value returned by
263 // IsAlternativeServiceBroken. If that value changes, then call persist.
264 if (old_value
!= new_value
)
265 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE
);
268 void HttpServerPropertiesManager::ClearAlternativeServices(
269 const HostPortPair
& origin
) {
270 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
271 const AlternativeServiceMap
& map
=
272 http_server_properties_impl_
->alternative_service_map();
273 size_t old_size
= map
.size();
274 http_server_properties_impl_
->ClearAlternativeServices(origin
);
275 size_t new_size
= map
.size();
276 // Persist only if we have deleted an entry.
277 if (old_size
!= new_size
)
278 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE
);
281 const AlternativeServiceMap
&
282 HttpServerPropertiesManager::alternative_service_map() const {
283 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
284 return http_server_properties_impl_
->alternative_service_map();
287 scoped_ptr
<base::Value
>
288 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
290 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
291 return http_server_properties_impl_
->GetAlternativeServiceInfoAsValue();
294 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
296 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
297 http_server_properties_impl_
->SetAlternativeServiceProbabilityThreshold(
301 const SettingsMap
& HttpServerPropertiesManager::GetSpdySettings(
302 const HostPortPair
& host_port_pair
) {
303 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
304 return http_server_properties_impl_
->GetSpdySettings(host_port_pair
);
307 bool HttpServerPropertiesManager::SetSpdySetting(
308 const HostPortPair
& host_port_pair
,
310 SpdySettingsFlags flags
,
312 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
313 bool persist
= http_server_properties_impl_
->SetSpdySetting(
314 host_port_pair
, id
, flags
, value
);
316 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING
);
320 void HttpServerPropertiesManager::ClearSpdySettings(
321 const HostPortPair
& host_port_pair
) {
322 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
323 http_server_properties_impl_
->ClearSpdySettings(host_port_pair
);
324 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS
);
327 void HttpServerPropertiesManager::ClearAllSpdySettings() {
328 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
329 http_server_properties_impl_
->ClearAllSpdySettings();
330 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS
);
333 const SpdySettingsMap
& HttpServerPropertiesManager::spdy_settings_map()
335 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
336 return http_server_properties_impl_
->spdy_settings_map();
339 bool HttpServerPropertiesManager::GetSupportsQuic(
340 IPAddressNumber
* last_address
) const {
341 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
342 return http_server_properties_impl_
->GetSupportsQuic(last_address
);
345 void HttpServerPropertiesManager::SetSupportsQuic(
347 const IPAddressNumber
& address
) {
348 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
349 IPAddressNumber old_last_quic_addr
;
350 http_server_properties_impl_
->GetSupportsQuic(&old_last_quic_addr
);
351 http_server_properties_impl_
->SetSupportsQuic(used_quic
, address
);
352 IPAddressNumber new_last_quic_addr
;
353 http_server_properties_impl_
->GetSupportsQuic(&new_last_quic_addr
);
354 if (old_last_quic_addr
!= new_last_quic_addr
)
355 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC
);
358 void HttpServerPropertiesManager::SetServerNetworkStats(
359 const HostPortPair
& host_port_pair
,
360 ServerNetworkStats stats
) {
361 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
362 ServerNetworkStats old_stats
;
363 const ServerNetworkStats
* old_stats_ptr
=
364 http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
365 if (http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
))
366 old_stats
= *old_stats_ptr
;
367 http_server_properties_impl_
->SetServerNetworkStats(host_port_pair
, stats
);
368 ServerNetworkStats new_stats
=
369 *(http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
));
370 if (old_stats
!= new_stats
)
371 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS
);
374 const ServerNetworkStats
* HttpServerPropertiesManager::GetServerNetworkStats(
375 const HostPortPair
& host_port_pair
) {
376 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
377 return http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
380 const ServerNetworkStatsMap
&
381 HttpServerPropertiesManager::server_network_stats_map() const {
382 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
383 return http_server_properties_impl_
->server_network_stats_map();
387 // Update the HttpServerPropertiesImpl's cache with data from preferences.
389 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
390 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
391 // Cancel pending updates, if any.
392 pref_cache_update_timer_
->Stop();
393 StartCacheUpdateTimerOnPrefThread(
394 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs
));
397 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
398 base::TimeDelta delay
) {
399 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
400 pref_cache_update_timer_
->Start(
404 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
);
407 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
408 // The preferences can only be read on the pref thread.
409 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
411 if (!pref_service_
->HasPrefPath(path_
))
414 bool detected_corrupted_prefs
= false;
415 const base::DictionaryValue
& http_server_properties_dict
=
416 *pref_service_
->GetDictionary(path_
);
418 int version
= kMissingVersion
;
419 if (!http_server_properties_dict
.GetIntegerWithoutPathExpansion(kVersionKey
,
421 DVLOG(1) << "Missing version. Clearing all properties.";
425 // The properties for a given server is in
426 // http_server_properties_dict["servers"][server].
427 const base::DictionaryValue
* servers_dict
= NULL
;
428 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
429 kServersKey
, &servers_dict
)) {
430 DVLOG(1) << "Malformed http_server_properties for servers.";
434 IPAddressNumber
* addr
= new IPAddressNumber
;
435 ReadSupportsQuic(http_server_properties_dict
, addr
);
437 // String is host/port pair of spdy server.
438 scoped_ptr
<StringVector
> spdy_servers(new StringVector
);
439 scoped_ptr
<SpdySettingsMap
> spdy_settings_map(
440 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
));
441 scoped_ptr
<AlternativeServiceMap
> alternative_service_map(
442 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
));
443 scoped_ptr
<ServerNetworkStatsMap
> server_network_stats_map(
444 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
));
446 for (base::DictionaryValue::Iterator
it(*servers_dict
); !it
.IsAtEnd();
448 // Get server's host/pair.
449 const std::string
& server_str
= it
.key();
450 HostPortPair server
= HostPortPair::FromString(server_str
);
451 if (server
.host().empty()) {
452 DVLOG(1) << "Malformed http_server_properties for server: " << server_str
;
453 detected_corrupted_prefs
= true;
457 const base::DictionaryValue
* server_pref_dict
= NULL
;
458 if (!it
.value().GetAsDictionary(&server_pref_dict
)) {
459 DVLOG(1) << "Malformed http_server_properties server: " << server_str
;
460 detected_corrupted_prefs
= true;
464 // Get if server supports Spdy.
465 bool supports_spdy
= false;
466 if ((server_pref_dict
->GetBoolean(kSupportsSpdyKey
, &supports_spdy
)) &&
468 spdy_servers
->push_back(server_str
);
471 AddToSpdySettingsMap(server
, *server_pref_dict
, spdy_settings_map
.get());
472 if (!AddToAlternativeServiceMap(server
, *server_pref_dict
,
473 alternative_service_map
.get()) ||
474 !AddToNetworkStatsMap(server
, *server_pref_dict
,
475 server_network_stats_map
.get())) {
476 detected_corrupted_prefs
= true;
480 network_task_runner_
->PostTask(
483 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread
,
484 base::Unretained(this), base::Owned(spdy_servers
.release()),
485 base::Owned(spdy_settings_map
.release()),
486 base::Owned(alternative_service_map
.release()), base::Owned(addr
),
487 base::Owned(server_network_stats_map
.release()),
488 detected_corrupted_prefs
));
491 void HttpServerPropertiesManager::AddToSpdySettingsMap(
492 const HostPortPair
& server
,
493 const base::DictionaryValue
& server_pref_dict
,
494 SpdySettingsMap
* spdy_settings_map
) {
496 DCHECK(spdy_settings_map
->Peek(server
) == spdy_settings_map
->end());
497 const base::DictionaryValue
* spdy_settings_dict
= NULL
;
498 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
499 kSettingsKey
, &spdy_settings_dict
)) {
502 SettingsMap settings_map
;
503 for (base::DictionaryValue::Iterator
dict_it(*spdy_settings_dict
);
504 !dict_it
.IsAtEnd(); dict_it
.Advance()) {
505 const std::string
& id_str
= dict_it
.key();
507 if (!base::StringToInt(id_str
, &id
)) {
508 DVLOG(1) << "Malformed id in SpdySettings for server: "
509 << server
.ToString();
514 if (!dict_it
.value().GetAsInteger(&value
)) {
515 DVLOG(1) << "Malformed value in SpdySettings for server: "
516 << server
.ToString();
520 SettingsFlagsAndValue
flags_and_value(SETTINGS_FLAG_PERSISTED
, value
);
521 settings_map
[static_cast<SpdySettingsIds
>(id
)] = flags_and_value
;
523 spdy_settings_map
->Put(server
, settings_map
);
526 AlternativeServiceInfo
HttpServerPropertiesManager::ParseAlternativeServiceDict(
527 const base::DictionaryValue
& alternative_service_dict
,
528 const std::string
& server_str
) {
529 // Protocol is mandatory.
530 std::string protocol_str
;
531 if (!alternative_service_dict
.GetStringWithoutPathExpansion(kProtocolKey
,
533 DVLOG(1) << "Malformed alternative service protocol string for server: "
535 return AlternativeServiceInfo();
537 AlternateProtocol protocol
= AlternateProtocolFromString(protocol_str
);
538 if (!IsAlternateProtocolValid(protocol
)) {
539 DVLOG(1) << "Invalid alternative service protocol string for server: "
541 return AlternativeServiceInfo();
544 // Host is optional, defaults to "".
546 if (alternative_service_dict
.HasKey(kHostKey
) &&
547 !alternative_service_dict
.GetStringWithoutPathExpansion(kHostKey
,
549 DVLOG(1) << "Malformed alternative service host string for server: "
551 return AlternativeServiceInfo();
554 // Port is mandatory.
556 if (!alternative_service_dict
.GetInteger(kPortKey
, &port
) ||
557 !IsPortValid(port
)) {
558 DVLOG(1) << "Malformed alternative service port for server: " << server_str
;
559 return AlternativeServiceInfo();
562 // Probability is optional, defaults to 1.0.
563 double probability
= 1.0;
564 if (alternative_service_dict
.HasKey(kProbabilityKey
) &&
565 !alternative_service_dict
.GetDoubleWithoutPathExpansion(kProbabilityKey
,
567 DVLOG(1) << "Malformed alternative service probability for server: "
569 return AlternativeServiceInfo();
572 return AlternativeServiceInfo(protocol
, host
, static_cast<uint16
>(port
),
576 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
577 const HostPortPair
& server
,
578 const base::DictionaryValue
& server_pref_dict
,
579 AlternativeServiceMap
* alternative_service_map
) {
580 DCHECK(alternative_service_map
->Peek(server
) ==
581 alternative_service_map
->end());
582 // Get alternative_services...
583 const base::ListValue
* alternative_service_list
;
584 const base::DictionaryValue
* alternative_service_dict
;
585 AlternativeServiceInfoVector alternative_service_info_vector
;
586 if (server_pref_dict
.GetListWithoutPathExpansion(kAlternativeServiceKey
,
587 &alternative_service_list
)) {
588 for (const base::Value
* alternative_service_list_item
:
589 *alternative_service_list
) {
590 if (!alternative_service_list_item
->GetAsDictionary(
591 &alternative_service_dict
))
593 AlternativeServiceInfo alternative_service_info
=
594 ParseAlternativeServiceDict(*alternative_service_dict
,
596 if (alternative_service_info
.alternative_service
.protocol
==
597 UNINITIALIZED_ALTERNATE_PROTOCOL
) {
600 alternative_service_info_vector
.push_back(alternative_service_info
);
603 // ...or alternate_protocol.
604 // TODO(bnc): Remove this in M46, we do not need preference migration for
606 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
607 kAlternateProtocolKey
, &alternative_service_dict
)) {
610 AlternativeServiceInfo alternative_service_info
=
611 ParseAlternativeServiceDict(*alternative_service_dict
,
613 if (alternative_service_info
.alternative_service
.protocol
==
614 UNINITIALIZED_ALTERNATE_PROTOCOL
) {
617 alternative_service_info_vector
.push_back(alternative_service_info
);
620 if (alternative_service_info_vector
.empty()) {
624 alternative_service_map
->Put(server
, alternative_service_info_vector
);
628 bool HttpServerPropertiesManager::ReadSupportsQuic(
629 const base::DictionaryValue
& http_server_properties_dict
,
630 IPAddressNumber
* last_quic_address
) {
631 const base::DictionaryValue
* supports_quic_dict
= NULL
;
632 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
633 kSupportsQuicKey
, &supports_quic_dict
)) {
636 bool used_quic
= false;
637 if (!supports_quic_dict
->GetBooleanWithoutPathExpansion(kUsedQuicKey
,
639 DVLOG(1) << "Malformed SupportsQuic";
646 if (!supports_quic_dict
->GetStringWithoutPathExpansion(kAddressKey
,
648 !ParseIPLiteralToNumber(address
, last_quic_address
)) {
649 DVLOG(1) << "Malformed SupportsQuic";
655 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
656 const HostPortPair
& server
,
657 const base::DictionaryValue
& server_pref_dict
,
658 ServerNetworkStatsMap
* network_stats_map
) {
659 DCHECK(network_stats_map
->Peek(server
) == network_stats_map
->end());
660 const base::DictionaryValue
* server_network_stats_dict
= NULL
;
661 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
662 kNetworkStatsKey
, &server_network_stats_dict
)) {
666 if (!server_network_stats_dict
->GetIntegerWithoutPathExpansion(kSrttKey
,
668 DVLOG(1) << "Malformed ServerNetworkStats for server: "
669 << server
.ToString();
672 ServerNetworkStats server_network_stats
;
673 server_network_stats
.srtt
= base::TimeDelta::FromInternalValue(srtt
);
674 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
675 // bandwidth_estimate.
676 network_stats_map
->Put(server
, server_network_stats
);
680 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
681 StringVector
* spdy_servers
,
682 SpdySettingsMap
* spdy_settings_map
,
683 AlternativeServiceMap
* alternative_service_map
,
684 IPAddressNumber
* last_quic_address
,
685 ServerNetworkStatsMap
* server_network_stats_map
,
686 bool detected_corrupted_prefs
) {
687 // Preferences have the master data because admins might have pushed new
688 // preferences. Update the cached data with new data from preferences.
689 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
691 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers
->size());
692 http_server_properties_impl_
->InitializeSpdyServers(spdy_servers
, true);
694 // Update the cached data and use the new spdy_settings from preferences.
695 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map
->size());
696 http_server_properties_impl_
->InitializeSpdySettingsServers(
699 // Update the cached data and use the new alternative service list from
701 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
702 alternative_service_map
->size());
703 http_server_properties_impl_
->InitializeAlternativeServiceServers(
704 alternative_service_map
);
706 http_server_properties_impl_
->InitializeSupportsQuic(last_quic_address
);
708 http_server_properties_impl_
->InitializeServerNetworkStats(
709 server_network_stats_map
);
711 // Update the prefs with what we have read (delete all corrupted prefs).
712 if (detected_corrupted_prefs
)
713 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS
);
717 // Update Preferences with data from the cached data.
719 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
721 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
722 // Cancel pending updates, if any.
723 network_prefs_update_timer_
->Stop();
724 StartPrefsUpdateTimerOnNetworkThread(
725 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs
));
726 // TODO(rtenneti): Delete the following histogram after collecting some data.
727 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location
,
728 HttpServerPropertiesManager::NUM_LOCATIONS
);
731 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
732 base::TimeDelta delay
) {
733 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
734 // This is overridden in tests to post the task without the delay.
735 network_prefs_update_timer_
->Start(
739 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread
);
742 // This is required so we can set this as the callback for a timer.
743 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
744 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
747 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
748 const base::Closure
& completion
) {
749 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
751 base::ListValue
* spdy_server_list
= new base::ListValue
;
752 http_server_properties_impl_
->GetSpdyServerList(
753 spdy_server_list
, kMaxSupportsSpdyServerHostsToPersist
);
755 SpdySettingsMap
* spdy_settings_map
=
756 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
);
757 const SpdySettingsMap
& main_map
=
758 http_server_properties_impl_
->spdy_settings_map();
760 for (SpdySettingsMap::const_iterator it
= main_map
.begin();
761 it
!= main_map
.end() && count
< kMaxSpdySettingsHostsToPersist
;
763 spdy_settings_map
->Put(it
->first
, it
->second
);
766 AlternativeServiceMap
* alternative_service_map
=
767 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
);
768 const AlternativeServiceMap
& map
=
769 http_server_properties_impl_
->alternative_service_map();
771 typedef std::map
<std::string
, bool> CanonicalHostPersistedMap
;
772 CanonicalHostPersistedMap persisted_map
;
773 for (AlternativeServiceMap::const_iterator it
= map
.begin();
774 it
!= map
.end() && count
< kMaxAlternateProtocolHostsToPersist
; ++it
) {
775 const HostPortPair
& server
= it
->first
;
776 AlternativeServiceInfoVector notbroken_alternative_service_info_vector
;
777 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
778 if (!IsAlternateProtocolValid(
779 alternative_service_info
.alternative_service
.protocol
)) {
782 AlternativeService
alternative_service(
783 alternative_service_info
.alternative_service
);
784 if (alternative_service
.host
.empty()) {
785 alternative_service
.host
= server
.host();
787 if (IsAlternativeServiceBroken(alternative_service
)) {
790 notbroken_alternative_service_info_vector
.push_back(
791 alternative_service_info
);
793 if (notbroken_alternative_service_info_vector
.empty()) {
796 alternative_service_map
->Put(server
,
797 notbroken_alternative_service_info_vector
);
798 std::string canonical_suffix
=
799 http_server_properties_impl_
->GetCanonicalSuffix(server
.host());
800 if (!canonical_suffix
.empty()) {
801 if (persisted_map
.find(canonical_suffix
) != persisted_map
.end())
803 persisted_map
[canonical_suffix
] = true;
808 ServerNetworkStatsMap
* server_network_stats_map
=
809 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
);
810 const ServerNetworkStatsMap
& main_server_network_stats_map
=
811 http_server_properties_impl_
->server_network_stats_map();
812 for (ServerNetworkStatsMap::const_iterator it
=
813 main_server_network_stats_map
.begin();
814 it
!= main_server_network_stats_map
.end(); ++it
) {
815 server_network_stats_map
->Put(it
->first
, it
->second
);
818 IPAddressNumber
* last_quic_addr
= new IPAddressNumber
;
819 http_server_properties_impl_
->GetSupportsQuic(last_quic_addr
);
820 // Update the preferences on the pref thread.
821 pref_task_runner_
->PostTask(
824 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread
, pref_weak_ptr_
,
825 base::Owned(spdy_server_list
), base::Owned(spdy_settings_map
),
826 base::Owned(alternative_service_map
), base::Owned(last_quic_addr
),
827 base::Owned(server_network_stats_map
), completion
));
830 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
831 // AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
832 // is used only in UpdatePrefsOnPrefThread.
835 : supports_spdy(false),
837 alternative_service_info_vector(NULL
),
839 server_network_stats(NULL
) {}
842 const SettingsMap
* settings_map
,
843 const AlternativeServiceInfoVector
* alternative_service_info_vector
,
844 const SupportsQuic
* supports_quic
,
845 const ServerNetworkStats
* server_network_stats
)
846 : supports_spdy(supports_spdy
),
847 settings_map(settings_map
),
848 alternative_service_info_vector(alternative_service_info_vector
),
849 supports_quic(supports_quic
),
850 server_network_stats(server_network_stats
) {}
852 const SettingsMap
* settings_map
;
853 const AlternativeServiceInfoVector
* alternative_service_info_vector
;
854 const SupportsQuic
* supports_quic
;
855 const ServerNetworkStats
* server_network_stats
;
858 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
859 base::ListValue
* spdy_server_list
,
860 SpdySettingsMap
* spdy_settings_map
,
861 AlternativeServiceMap
* alternative_service_map
,
862 IPAddressNumber
* last_quic_address
,
863 ServerNetworkStatsMap
* server_network_stats_map
,
864 const base::Closure
& completion
) {
865 typedef std::map
<HostPortPair
, ServerPref
> ServerPrefMap
;
866 ServerPrefMap server_pref_map
;
868 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
870 // Add servers that support spdy to server_pref_map.
872 for (base::ListValue::const_iterator list_it
= spdy_server_list
->begin();
873 list_it
!= spdy_server_list
->end();
875 if ((*list_it
)->GetAsString(&s
)) {
876 HostPortPair server
= HostPortPair::FromString(s
);
877 server_pref_map
[server
].supports_spdy
= true;
881 // Add servers that have SpdySettings to server_pref_map.
882 for (SpdySettingsMap::iterator map_it
= spdy_settings_map
->begin();
883 map_it
!= spdy_settings_map
->end(); ++map_it
) {
884 const HostPortPair
& server
= map_it
->first
;
885 server_pref_map
[server
].settings_map
= &map_it
->second
;
888 // Add alternative services to server_pref_map.
889 for (AlternativeServiceMap::const_iterator map_it
=
890 alternative_service_map
->begin();
891 map_it
!= alternative_service_map
->end(); ++map_it
) {
892 server_pref_map
[map_it
->first
].alternative_service_info_vector
=
896 // Add ServerNetworkStats servers to server_pref_map.
897 for (ServerNetworkStatsMap::const_iterator map_it
=
898 server_network_stats_map
->begin();
899 map_it
!= server_network_stats_map
->end(); ++map_it
) {
900 const HostPortPair
& server
= map_it
->first
;
901 server_pref_map
[server
].server_network_stats
= &map_it
->second
;
904 // Persist properties to the |path_|.
905 base::DictionaryValue http_server_properties_dict
;
906 base::DictionaryValue
* servers_dict
= new base::DictionaryValue
;
907 for (ServerPrefMap::const_iterator map_it
= server_pref_map
.begin();
908 map_it
!= server_pref_map
.end();
910 const HostPortPair
& server
= map_it
->first
;
911 const ServerPref
& server_pref
= map_it
->second
;
913 base::DictionaryValue
* server_pref_dict
= new base::DictionaryValue
;
915 // Save supports_spdy.
916 if (server_pref
.supports_spdy
)
917 server_pref_dict
->SetBoolean(kSupportsSpdyKey
, server_pref
.supports_spdy
);
918 SaveSpdySettingsToServerPrefs(server_pref
.settings_map
, server_pref_dict
);
919 SaveAlternativeServiceToServerPrefs(
920 server_pref
.alternative_service_info_vector
, server_pref_dict
);
921 SaveNetworkStatsToServerPrefs(server_pref
.server_network_stats
,
924 servers_dict
->SetWithoutPathExpansion(server
.ToString(), server_pref_dict
);
927 http_server_properties_dict
.SetWithoutPathExpansion(kServersKey
,
929 SetVersion(&http_server_properties_dict
, kVersionNumber
);
931 SaveSupportsQuicToPrefs(last_quic_address
, &http_server_properties_dict
);
933 setting_prefs_
= true;
934 pref_service_
->Set(path_
, http_server_properties_dict
);
935 setting_prefs_
= false;
937 // Note that |completion| will be fired after we have written everything to
938 // the Preferences, but likely before these changes are serialized to disk.
939 // This is not a problem though, as JSONPrefStore guarantees that this will
940 // happen, pretty soon, and even in the case we shut down immediately.
941 if (!completion
.is_null())
945 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
946 const SettingsMap
* settings_map
,
947 base::DictionaryValue
* server_pref_dict
) {
951 base::DictionaryValue
* spdy_settings_dict
= new base::DictionaryValue
;
952 for (SettingsMap::const_iterator it
= settings_map
->begin();
953 it
!= settings_map
->end(); ++it
) {
954 SpdySettingsIds id
= it
->first
;
955 uint32 value
= it
->second
.second
;
956 std::string key
= base::StringPrintf("%u", id
);
957 spdy_settings_dict
->SetInteger(key
, value
);
959 server_pref_dict
->SetWithoutPathExpansion(kSettingsKey
, spdy_settings_dict
);
962 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
963 const AlternativeServiceInfoVector
* alternative_service_info_vector
,
964 base::DictionaryValue
* server_pref_dict
) {
965 if (!alternative_service_info_vector
||
966 alternative_service_info_vector
->empty()) {
969 scoped_ptr
<base::ListValue
> alternative_service_list(new base::ListValue
);
970 for (const AlternativeServiceInfo
& alternative_service_info
:
971 *alternative_service_info_vector
) {
972 const AlternativeService alternative_service
=
973 alternative_service_info
.alternative_service
;
974 DCHECK(IsAlternateProtocolValid(alternative_service
.protocol
));
975 base::DictionaryValue
* alternative_service_dict
= new base::DictionaryValue
;
976 alternative_service_dict
->SetInteger(kPortKey
, alternative_service
.port
);
977 if (!alternative_service
.host
.empty()) {
978 alternative_service_dict
->SetString(kHostKey
, alternative_service
.host
);
980 alternative_service_dict
->SetString(
981 kProtocolKey
, AlternateProtocolToString(alternative_service
.protocol
));
982 alternative_service_dict
->SetDouble(kProbabilityKey
,
983 alternative_service_info
.probability
);
984 alternative_service_list
->Append(alternative_service_dict
);
986 if (alternative_service_list
->GetSize() == 0)
988 server_pref_dict
->SetWithoutPathExpansion(kAlternativeServiceKey
,
989 alternative_service_list
.release());
992 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
993 const IPAddressNumber
* last_quic_address
,
994 base::DictionaryValue
* http_server_properties_dict
) {
995 if (!last_quic_address
|| last_quic_address
->empty())
998 base::DictionaryValue
* supports_quic_dict
= new base::DictionaryValue
;
999 supports_quic_dict
->SetBoolean(kUsedQuicKey
, true);
1000 supports_quic_dict
->SetString(kAddressKey
,
1001 IPAddressToString(*last_quic_address
));
1002 http_server_properties_dict
->SetWithoutPathExpansion(kSupportsQuicKey
,
1003 supports_quic_dict
);
1006 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
1007 const ServerNetworkStats
* server_network_stats
,
1008 base::DictionaryValue
* server_pref_dict
) {
1009 if (!server_network_stats
)
1012 base::DictionaryValue
* server_network_stats_dict
= new base::DictionaryValue
;
1013 // Becasue JSON doesn't support int64, persist int64 as a string.
1014 server_network_stats_dict
->SetInteger(
1015 kSrttKey
, static_cast<int>(server_network_stats
->srtt
.ToInternalValue()));
1016 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
1017 // bandwidth_estimate.
1018 server_pref_dict
->SetWithoutPathExpansion(kNetworkStatsKey
,
1019 server_network_stats_dict
);
1022 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
1023 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
1024 if (!setting_prefs_
)
1025 ScheduleUpdateCacheOnPrefThread();