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"
17 #include "net/base/port_util.h"
23 // Time to wait before starting an update the http_server_properties_impl_ cache
24 // from preferences. Scheduling another update during this period will reset the
26 const int64 kUpdateCacheDelayMs
= 1000;
28 // Time to wait before starting an update the preferences from the
29 // http_server_properties_impl_ cache. Scheduling another update during this
30 // period will reset the timer.
31 const int64 kUpdatePrefsDelayMs
= 60000;
33 // "version" 0 indicates, http_server_properties doesn't have "version"
35 const int kMissingVersion
= 0;
37 // The version number of persisted http_server_properties.
38 const int kVersionNumber
= 3;
40 typedef std::vector
<std::string
> StringVector
;
42 // Persist 200 MRU AlternateProtocolHostPortPairs.
43 const int kMaxAlternateProtocolHostsToPersist
= 200;
45 // Persist 200 MRU SpdySettingsHostPortPairs.
46 const int kMaxSpdySettingsHostsToPersist
= 200;
48 // Persist 300 MRU SupportsSpdyServerHostPortPairs.
49 const int kMaxSupportsSpdyServerHostsToPersist
= 300;
51 // Persist 200 ServerNetworkStats.
52 const int kMaxServerNetworkStatsHostsToPersist
= 200;
54 const char kVersionKey
[] = "version";
55 const char kServersKey
[] = "servers";
56 const char kSupportsSpdyKey
[] = "supports_spdy";
57 const char kSettingsKey
[] = "settings";
58 const char kSupportsQuicKey
[] = "supports_quic";
59 const char kUsedQuicKey
[] = "used_quic";
60 const char kAddressKey
[] = "address";
61 const char kAlternateProtocolKey
[] = "alternate_protocol";
62 const char kAlternativeServiceKey
[] = "alternative_service";
63 const char kProtocolKey
[] = "protocol_str";
64 const char kHostKey
[] = "host";
65 const char kPortKey
[] = "port";
66 const char kProbabilityKey
[] = "probability";
67 const char kExpirationKey
[] = "expiration";
68 const char kNetworkStatsKey
[] = "network_stats";
69 const char kSrttKey
[] = "srtt";
73 ////////////////////////////////////////////////////////////////////////////////
74 // HttpServerPropertiesManager
76 HttpServerPropertiesManager::HttpServerPropertiesManager(
77 PrefService
* pref_service
,
78 const char* pref_path
,
79 scoped_refptr
<base::SequencedTaskRunner
> network_task_runner
)
80 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
81 pref_service_(pref_service
),
82 setting_prefs_(false),
84 network_task_runner_(network_task_runner
) {
86 pref_weak_ptr_factory_
.reset(
87 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
88 pref_weak_ptr_
= pref_weak_ptr_factory_
->GetWeakPtr();
89 pref_cache_update_timer_
.reset(
90 new base::OneShotTimer
<HttpServerPropertiesManager
>);
91 pref_change_registrar_
.Init(pref_service_
);
92 pref_change_registrar_
.Add(
94 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged
,
95 base::Unretained(this)));
98 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
99 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
100 network_weak_ptr_factory_
.reset();
103 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
104 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
105 network_weak_ptr_factory_
.reset(
106 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
107 http_server_properties_impl_
.reset(new HttpServerPropertiesImpl());
109 network_prefs_update_timer_
.reset(
110 new base::OneShotTimer
<HttpServerPropertiesManager
>);
112 pref_task_runner_
->PostTask(
114 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
,
118 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
119 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
120 // Cancel any pending updates, and stop listening for pref change updates.
121 pref_cache_update_timer_
->Stop();
122 pref_weak_ptr_factory_
.reset();
123 pref_change_registrar_
.RemoveAll();
127 void HttpServerPropertiesManager::SetVersion(
128 base::DictionaryValue
* http_server_properties_dict
,
129 int version_number
) {
130 if (version_number
< 0)
131 version_number
= kVersionNumber
;
132 DCHECK_LE(version_number
, kVersionNumber
);
133 if (version_number
<= kVersionNumber
)
134 http_server_properties_dict
->SetInteger(kVersionKey
, version_number
);
137 // This is required for conformance with the HttpServerProperties interface.
138 base::WeakPtr
<HttpServerProperties
> HttpServerPropertiesManager::GetWeakPtr() {
139 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
140 return network_weak_ptr_factory_
->GetWeakPtr();
143 void HttpServerPropertiesManager::Clear() {
144 Clear(base::Closure());
147 void HttpServerPropertiesManager::Clear(const base::Closure
& completion
) {
148 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
150 http_server_properties_impl_
->Clear();
151 UpdatePrefsFromCacheOnNetworkThread(completion
);
154 bool HttpServerPropertiesManager::SupportsRequestPriority(
155 const HostPortPair
& server
) {
156 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
157 return http_server_properties_impl_
->SupportsRequestPriority(server
);
160 bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair
& server
) {
161 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
162 return http_server_properties_impl_
->GetSupportsSpdy(server
);
165 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair
& server
,
167 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
169 bool old_support_spdy
= http_server_properties_impl_
->GetSupportsSpdy(server
);
170 http_server_properties_impl_
->SetSupportsSpdy(server
, support_spdy
);
171 bool new_support_spdy
= http_server_properties_impl_
->GetSupportsSpdy(server
);
172 if (old_support_spdy
!= new_support_spdy
)
173 ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY
);
176 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair
& server
) {
177 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
178 return http_server_properties_impl_
->RequiresHTTP11(server
);
181 void HttpServerPropertiesManager::SetHTTP11Required(
182 const HostPortPair
& server
) {
183 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
185 http_server_properties_impl_
->SetHTTP11Required(server
);
186 ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED
);
189 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair
& server
,
190 SSLConfig
* ssl_config
) {
191 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
192 http_server_properties_impl_
->MaybeForceHTTP11(server
, ssl_config
);
195 AlternativeServiceVector
HttpServerPropertiesManager::GetAlternativeServices(
196 const HostPortPair
& origin
) {
197 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
198 return http_server_properties_impl_
->GetAlternativeServices(origin
);
201 bool HttpServerPropertiesManager::SetAlternativeService(
202 const HostPortPair
& origin
,
203 const AlternativeService
& alternative_service
,
204 double alternative_probability
,
205 base::Time expiration
) {
206 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
207 const bool changed
= http_server_properties_impl_
->SetAlternativeService(
208 origin
, alternative_service
, alternative_probability
, expiration
);
210 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES
);
215 bool HttpServerPropertiesManager::SetAlternativeServices(
216 const HostPortPair
& origin
,
217 const AlternativeServiceInfoVector
& alternative_service_info_vector
) {
218 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
219 const bool changed
= http_server_properties_impl_
->SetAlternativeServices(
220 origin
, alternative_service_info_vector
);
222 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES
);
227 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
228 const AlternativeService
& alternative_service
) {
229 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
230 http_server_properties_impl_
->MarkAlternativeServiceBroken(
231 alternative_service
);
232 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN
);
235 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
236 const AlternativeService
& alternative_service
) {
237 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
238 http_server_properties_impl_
->MarkAlternativeServiceRecentlyBroken(
239 alternative_service
);
240 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN
);
243 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
244 const AlternativeService
& alternative_service
) const {
245 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
246 return http_server_properties_impl_
->IsAlternativeServiceBroken(
247 alternative_service
);
250 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
251 const AlternativeService
& alternative_service
) {
252 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
253 return http_server_properties_impl_
->WasAlternativeServiceRecentlyBroken(
254 alternative_service
);
257 void HttpServerPropertiesManager::ConfirmAlternativeService(
258 const AlternativeService
& alternative_service
) {
259 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
260 bool old_value
= http_server_properties_impl_
->IsAlternativeServiceBroken(
261 alternative_service
);
262 http_server_properties_impl_
->ConfirmAlternativeService(alternative_service
);
263 bool new_value
= http_server_properties_impl_
->IsAlternativeServiceBroken(
264 alternative_service
);
265 // For persisting, we only care about the value returned by
266 // IsAlternativeServiceBroken. If that value changes, then call persist.
267 if (old_value
!= new_value
)
268 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE
);
271 void HttpServerPropertiesManager::ClearAlternativeServices(
272 const HostPortPair
& origin
) {
273 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
274 const AlternativeServiceMap
& map
=
275 http_server_properties_impl_
->alternative_service_map();
276 size_t old_size
= map
.size();
277 http_server_properties_impl_
->ClearAlternativeServices(origin
);
278 size_t new_size
= map
.size();
279 // Persist only if we have deleted an entry.
280 if (old_size
!= new_size
)
281 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE
);
284 const AlternativeServiceMap
&
285 HttpServerPropertiesManager::alternative_service_map() const {
286 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
287 return http_server_properties_impl_
->alternative_service_map();
290 scoped_ptr
<base::Value
>
291 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
293 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
294 return http_server_properties_impl_
->GetAlternativeServiceInfoAsValue();
297 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
299 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
300 http_server_properties_impl_
->SetAlternativeServiceProbabilityThreshold(
304 const SettingsMap
& HttpServerPropertiesManager::GetSpdySettings(
305 const HostPortPair
& host_port_pair
) {
306 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
307 return http_server_properties_impl_
->GetSpdySettings(host_port_pair
);
310 bool HttpServerPropertiesManager::SetSpdySetting(
311 const HostPortPair
& host_port_pair
,
313 SpdySettingsFlags flags
,
315 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
316 bool persist
= http_server_properties_impl_
->SetSpdySetting(
317 host_port_pair
, id
, flags
, value
);
319 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING
);
323 void HttpServerPropertiesManager::ClearSpdySettings(
324 const HostPortPair
& host_port_pair
) {
325 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
326 http_server_properties_impl_
->ClearSpdySettings(host_port_pair
);
327 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS
);
330 void HttpServerPropertiesManager::ClearAllSpdySettings() {
331 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
332 http_server_properties_impl_
->ClearAllSpdySettings();
333 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS
);
336 const SpdySettingsMap
& HttpServerPropertiesManager::spdy_settings_map()
338 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
339 return http_server_properties_impl_
->spdy_settings_map();
342 bool HttpServerPropertiesManager::GetSupportsQuic(
343 IPAddressNumber
* last_address
) const {
344 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
345 return http_server_properties_impl_
->GetSupportsQuic(last_address
);
348 void HttpServerPropertiesManager::SetSupportsQuic(
350 const IPAddressNumber
& address
) {
351 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
352 IPAddressNumber old_last_quic_addr
;
353 http_server_properties_impl_
->GetSupportsQuic(&old_last_quic_addr
);
354 http_server_properties_impl_
->SetSupportsQuic(used_quic
, address
);
355 IPAddressNumber new_last_quic_addr
;
356 http_server_properties_impl_
->GetSupportsQuic(&new_last_quic_addr
);
357 if (old_last_quic_addr
!= new_last_quic_addr
)
358 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC
);
361 void HttpServerPropertiesManager::SetServerNetworkStats(
362 const HostPortPair
& host_port_pair
,
363 ServerNetworkStats stats
) {
364 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
365 ServerNetworkStats old_stats
;
366 const ServerNetworkStats
* old_stats_ptr
=
367 http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
368 if (http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
))
369 old_stats
= *old_stats_ptr
;
370 http_server_properties_impl_
->SetServerNetworkStats(host_port_pair
, stats
);
371 ServerNetworkStats new_stats
=
372 *(http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
));
373 if (old_stats
!= new_stats
)
374 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS
);
377 const ServerNetworkStats
* HttpServerPropertiesManager::GetServerNetworkStats(
378 const HostPortPair
& host_port_pair
) {
379 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
380 return http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
383 const ServerNetworkStatsMap
&
384 HttpServerPropertiesManager::server_network_stats_map() const {
385 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
386 return http_server_properties_impl_
->server_network_stats_map();
390 // Update the HttpServerPropertiesImpl's cache with data from preferences.
392 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
393 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
394 // Cancel pending updates, if any.
395 pref_cache_update_timer_
->Stop();
396 StartCacheUpdateTimerOnPrefThread(
397 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs
));
400 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
401 base::TimeDelta delay
) {
402 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
403 pref_cache_update_timer_
->Start(
407 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
);
410 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
411 // The preferences can only be read on the pref thread.
412 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
414 if (!pref_service_
->HasPrefPath(path_
))
417 bool detected_corrupted_prefs
= false;
418 const base::DictionaryValue
& http_server_properties_dict
=
419 *pref_service_
->GetDictionary(path_
);
421 int version
= kMissingVersion
;
422 if (!http_server_properties_dict
.GetIntegerWithoutPathExpansion(kVersionKey
,
424 DVLOG(1) << "Missing version. Clearing all properties.";
428 // The properties for a given server is in
429 // http_server_properties_dict["servers"][server].
430 const base::DictionaryValue
* servers_dict
= NULL
;
431 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
432 kServersKey
, &servers_dict
)) {
433 DVLOG(1) << "Malformed http_server_properties for servers.";
437 IPAddressNumber
* addr
= new IPAddressNumber
;
438 ReadSupportsQuic(http_server_properties_dict
, addr
);
440 // String is host/port pair of spdy server.
441 scoped_ptr
<StringVector
> spdy_servers(new StringVector
);
442 scoped_ptr
<SpdySettingsMap
> spdy_settings_map(
443 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
));
444 scoped_ptr
<AlternativeServiceMap
> alternative_service_map(
445 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
));
446 scoped_ptr
<ServerNetworkStatsMap
> server_network_stats_map(
447 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
));
449 for (base::DictionaryValue::Iterator
it(*servers_dict
); !it
.IsAtEnd();
451 // Get server's host/pair.
452 const std::string
& server_str
= it
.key();
453 HostPortPair server
= HostPortPair::FromString(server_str
);
454 if (server
.host().empty()) {
455 DVLOG(1) << "Malformed http_server_properties for server: " << server_str
;
456 detected_corrupted_prefs
= true;
460 const base::DictionaryValue
* server_pref_dict
= NULL
;
461 if (!it
.value().GetAsDictionary(&server_pref_dict
)) {
462 DVLOG(1) << "Malformed http_server_properties server: " << server_str
;
463 detected_corrupted_prefs
= true;
467 // Get if server supports Spdy.
468 bool supports_spdy
= false;
469 if ((server_pref_dict
->GetBoolean(kSupportsSpdyKey
, &supports_spdy
)) &&
471 spdy_servers
->push_back(server_str
);
474 AddToSpdySettingsMap(server
, *server_pref_dict
, spdy_settings_map
.get());
475 if (!AddToAlternativeServiceMap(server
, *server_pref_dict
,
476 alternative_service_map
.get()) ||
477 !AddToNetworkStatsMap(server
, *server_pref_dict
,
478 server_network_stats_map
.get())) {
479 detected_corrupted_prefs
= true;
483 network_task_runner_
->PostTask(
486 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread
,
487 base::Unretained(this), base::Owned(spdy_servers
.release()),
488 base::Owned(spdy_settings_map
.release()),
489 base::Owned(alternative_service_map
.release()), base::Owned(addr
),
490 base::Owned(server_network_stats_map
.release()),
491 detected_corrupted_prefs
));
494 void HttpServerPropertiesManager::AddToSpdySettingsMap(
495 const HostPortPair
& server
,
496 const base::DictionaryValue
& server_pref_dict
,
497 SpdySettingsMap
* spdy_settings_map
) {
499 DCHECK(spdy_settings_map
->Peek(server
) == spdy_settings_map
->end());
500 const base::DictionaryValue
* spdy_settings_dict
= NULL
;
501 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
502 kSettingsKey
, &spdy_settings_dict
)) {
505 SettingsMap settings_map
;
506 for (base::DictionaryValue::Iterator
dict_it(*spdy_settings_dict
);
507 !dict_it
.IsAtEnd(); dict_it
.Advance()) {
508 const std::string
& id_str
= dict_it
.key();
510 if (!base::StringToInt(id_str
, &id
)) {
511 DVLOG(1) << "Malformed id in SpdySettings for server: "
512 << server
.ToString();
517 if (!dict_it
.value().GetAsInteger(&value
)) {
518 DVLOG(1) << "Malformed value in SpdySettings for server: "
519 << server
.ToString();
523 SettingsFlagsAndValue
flags_and_value(SETTINGS_FLAG_PERSISTED
, value
);
524 settings_map
[static_cast<SpdySettingsIds
>(id
)] = flags_and_value
;
526 spdy_settings_map
->Put(server
, settings_map
);
529 bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
530 const base::DictionaryValue
& alternative_service_dict
,
531 const std::string
& server_str
,
532 AlternativeServiceInfo
* alternative_service_info
) {
533 // Protocol is mandatory.
534 std::string protocol_str
;
535 if (!alternative_service_dict
.GetStringWithoutPathExpansion(kProtocolKey
,
537 DVLOG(1) << "Malformed alternative service protocol string for server: "
541 AlternateProtocol protocol
= AlternateProtocolFromString(protocol_str
);
542 if (!IsAlternateProtocolValid(protocol
)) {
543 DVLOG(1) << "Invalid alternative service protocol string for server: "
547 alternative_service_info
->alternative_service
.protocol
= protocol
;
549 // Host is optional, defaults to "".
550 alternative_service_info
->alternative_service
.host
.clear();
551 if (alternative_service_dict
.HasKey(kHostKey
) &&
552 !alternative_service_dict
.GetStringWithoutPathExpansion(
553 kHostKey
, &(alternative_service_info
->alternative_service
.host
))) {
554 DVLOG(1) << "Malformed alternative service host string for server: "
559 // Port is mandatory.
561 if (!alternative_service_dict
.GetInteger(kPortKey
, &port
) ||
562 !IsPortValid(port
)) {
563 DVLOG(1) << "Malformed alternative service port for server: " << server_str
;
566 alternative_service_info
->alternative_service
.port
=
567 static_cast<uint32
>(port
);
569 // Probability is optional, defaults to 1.0.
570 alternative_service_info
->probability
= 1.0;
571 if (alternative_service_dict
.HasKey(kProbabilityKey
) &&
572 !alternative_service_dict
.GetDoubleWithoutPathExpansion(
573 kProbabilityKey
, &(alternative_service_info
->probability
))) {
574 DVLOG(1) << "Malformed alternative service probability for server: "
579 // Expiration is optional, defaults to one day.
580 base::Time expiration
;
581 if (!alternative_service_dict
.HasKey(kExpirationKey
)) {
582 alternative_service_info
->expiration
=
583 base::Time::Now() + base::TimeDelta::FromDays(1);
587 std::string expiration_string
;
588 if (alternative_service_dict
.GetStringWithoutPathExpansion(
589 kExpirationKey
, &expiration_string
)) {
590 int64 expiration_int64
= 0;
591 if (!base::StringToInt64(expiration_string
, &expiration_int64
)) {
592 DVLOG(1) << "Malformed alternative service expiration for server: "
596 alternative_service_info
->expiration
=
597 base::Time::FromInternalValue(expiration_int64
);
601 // Early release 46 Dev and Canary versions stored expiration as double.
602 // TODO(bnc) Remove the following code parsing double around 2015-10-01.
603 double expiration_double
;
604 if (alternative_service_dict
.GetDoubleWithoutPathExpansion(
605 kExpirationKey
, &expiration_double
)) {
606 alternative_service_info
->expiration
=
607 base::Time::FromDoubleT(expiration_double
);
611 DVLOG(1) << "Malformed alternative service expiration for server: "
616 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
617 const HostPortPair
& server
,
618 const base::DictionaryValue
& server_pref_dict
,
619 AlternativeServiceMap
* alternative_service_map
) {
620 DCHECK(alternative_service_map
->Peek(server
) ==
621 alternative_service_map
->end());
622 // Get alternative_services...
623 const base::ListValue
* alternative_service_list
;
624 const base::DictionaryValue
* alternative_service_dict
;
625 AlternativeServiceInfoVector alternative_service_info_vector
;
626 if (server_pref_dict
.GetListWithoutPathExpansion(kAlternativeServiceKey
,
627 &alternative_service_list
)) {
628 for (const base::Value
* alternative_service_list_item
:
629 *alternative_service_list
) {
630 if (!alternative_service_list_item
->GetAsDictionary(
631 &alternative_service_dict
))
633 AlternativeServiceInfo alternative_service_info
;
634 if (!ParseAlternativeServiceDict(*alternative_service_dict
,
636 &alternative_service_info
)) {
639 alternative_service_info_vector
.push_back(alternative_service_info
);
642 // ...or alternate_protocol.
643 // TODO(bnc): Remove this in M46, we do not need preference migration for
645 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
646 kAlternateProtocolKey
, &alternative_service_dict
)) {
649 AlternativeServiceInfo alternative_service_info
;
650 if (!ParseAlternativeServiceDict(*alternative_service_dict
,
652 &alternative_service_info
)) {
655 alternative_service_info_vector
.push_back(alternative_service_info
);
658 if (alternative_service_info_vector
.empty()) {
662 alternative_service_map
->Put(server
, alternative_service_info_vector
);
666 bool HttpServerPropertiesManager::ReadSupportsQuic(
667 const base::DictionaryValue
& http_server_properties_dict
,
668 IPAddressNumber
* last_quic_address
) {
669 const base::DictionaryValue
* supports_quic_dict
= NULL
;
670 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
671 kSupportsQuicKey
, &supports_quic_dict
)) {
674 bool used_quic
= false;
675 if (!supports_quic_dict
->GetBooleanWithoutPathExpansion(kUsedQuicKey
,
677 DVLOG(1) << "Malformed SupportsQuic";
684 if (!supports_quic_dict
->GetStringWithoutPathExpansion(kAddressKey
,
686 !ParseIPLiteralToNumber(address
, last_quic_address
)) {
687 DVLOG(1) << "Malformed SupportsQuic";
693 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
694 const HostPortPair
& server
,
695 const base::DictionaryValue
& server_pref_dict
,
696 ServerNetworkStatsMap
* network_stats_map
) {
697 DCHECK(network_stats_map
->Peek(server
) == network_stats_map
->end());
698 const base::DictionaryValue
* server_network_stats_dict
= NULL
;
699 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
700 kNetworkStatsKey
, &server_network_stats_dict
)) {
704 if (!server_network_stats_dict
->GetIntegerWithoutPathExpansion(kSrttKey
,
706 DVLOG(1) << "Malformed ServerNetworkStats for server: "
707 << server
.ToString();
710 ServerNetworkStats server_network_stats
;
711 server_network_stats
.srtt
= base::TimeDelta::FromInternalValue(srtt
);
712 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
713 // bandwidth_estimate.
714 network_stats_map
->Put(server
, server_network_stats
);
718 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
719 StringVector
* spdy_servers
,
720 SpdySettingsMap
* spdy_settings_map
,
721 AlternativeServiceMap
* alternative_service_map
,
722 IPAddressNumber
* last_quic_address
,
723 ServerNetworkStatsMap
* server_network_stats_map
,
724 bool detected_corrupted_prefs
) {
725 // Preferences have the master data because admins might have pushed new
726 // preferences. Update the cached data with new data from preferences.
727 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
729 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers
->size());
730 http_server_properties_impl_
->InitializeSpdyServers(spdy_servers
, true);
732 // Update the cached data and use the new spdy_settings from preferences.
733 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map
->size());
734 http_server_properties_impl_
->InitializeSpdySettingsServers(
737 // Update the cached data and use the new alternative service list from
739 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
740 alternative_service_map
->size());
741 http_server_properties_impl_
->InitializeAlternativeServiceServers(
742 alternative_service_map
);
744 http_server_properties_impl_
->InitializeSupportsQuic(last_quic_address
);
746 http_server_properties_impl_
->InitializeServerNetworkStats(
747 server_network_stats_map
);
749 // Update the prefs with what we have read (delete all corrupted prefs).
750 if (detected_corrupted_prefs
)
751 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS
);
755 // Update Preferences with data from the cached data.
757 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
759 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
760 // Cancel pending updates, if any.
761 network_prefs_update_timer_
->Stop();
762 StartPrefsUpdateTimerOnNetworkThread(
763 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs
));
764 // TODO(rtenneti): Delete the following histogram after collecting some data.
765 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location
,
766 HttpServerPropertiesManager::NUM_LOCATIONS
);
769 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
770 base::TimeDelta delay
) {
771 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
772 // This is overridden in tests to post the task without the delay.
773 network_prefs_update_timer_
->Start(
777 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread
);
780 // This is required so we can set this as the callback for a timer.
781 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
782 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
785 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
786 const base::Closure
& completion
) {
787 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
789 base::ListValue
* spdy_server_list
= new base::ListValue
;
790 http_server_properties_impl_
->GetSpdyServerList(
791 spdy_server_list
, kMaxSupportsSpdyServerHostsToPersist
);
793 SpdySettingsMap
* spdy_settings_map
=
794 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
);
795 const SpdySettingsMap
& main_map
=
796 http_server_properties_impl_
->spdy_settings_map();
798 for (SpdySettingsMap::const_iterator it
= main_map
.begin();
799 it
!= main_map
.end() && count
< kMaxSpdySettingsHostsToPersist
;
801 spdy_settings_map
->Put(it
->first
, it
->second
);
804 AlternativeServiceMap
* alternative_service_map
=
805 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
);
806 const AlternativeServiceMap
& map
=
807 http_server_properties_impl_
->alternative_service_map();
809 typedef std::map
<std::string
, bool> CanonicalHostPersistedMap
;
810 CanonicalHostPersistedMap persisted_map
;
811 for (AlternativeServiceMap::const_iterator it
= map
.begin();
812 it
!= map
.end() && count
< kMaxAlternateProtocolHostsToPersist
; ++it
) {
813 const HostPortPair
& server
= it
->first
;
814 AlternativeServiceInfoVector notbroken_alternative_service_info_vector
;
815 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
816 if (!IsAlternateProtocolValid(
817 alternative_service_info
.alternative_service
.protocol
)) {
820 AlternativeService
alternative_service(
821 alternative_service_info
.alternative_service
);
822 if (alternative_service
.host
.empty()) {
823 alternative_service
.host
= server
.host();
825 if (IsAlternativeServiceBroken(alternative_service
)) {
828 notbroken_alternative_service_info_vector
.push_back(
829 alternative_service_info
);
831 if (notbroken_alternative_service_info_vector
.empty()) {
834 alternative_service_map
->Put(server
,
835 notbroken_alternative_service_info_vector
);
836 std::string canonical_suffix
=
837 http_server_properties_impl_
->GetCanonicalSuffix(server
.host());
838 if (!canonical_suffix
.empty()) {
839 if (persisted_map
.find(canonical_suffix
) != persisted_map
.end())
841 persisted_map
[canonical_suffix
] = true;
846 ServerNetworkStatsMap
* server_network_stats_map
=
847 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
);
848 const ServerNetworkStatsMap
& main_server_network_stats_map
=
849 http_server_properties_impl_
->server_network_stats_map();
850 for (ServerNetworkStatsMap::const_iterator it
=
851 main_server_network_stats_map
.begin();
852 it
!= main_server_network_stats_map
.end(); ++it
) {
853 server_network_stats_map
->Put(it
->first
, it
->second
);
856 IPAddressNumber
* last_quic_addr
= new IPAddressNumber
;
857 http_server_properties_impl_
->GetSupportsQuic(last_quic_addr
);
858 // Update the preferences on the pref thread.
859 pref_task_runner_
->PostTask(
862 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread
, pref_weak_ptr_
,
863 base::Owned(spdy_server_list
), base::Owned(spdy_settings_map
),
864 base::Owned(alternative_service_map
), base::Owned(last_quic_addr
),
865 base::Owned(server_network_stats_map
), completion
));
868 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
869 // AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
870 // is used only in UpdatePrefsOnPrefThread.
873 : supports_spdy(false),
875 alternative_service_info_vector(NULL
),
877 server_network_stats(NULL
) {}
880 const SettingsMap
* settings_map
,
881 const AlternativeServiceInfoVector
* alternative_service_info_vector
,
882 const SupportsQuic
* supports_quic
,
883 const ServerNetworkStats
* server_network_stats
)
884 : supports_spdy(supports_spdy
),
885 settings_map(settings_map
),
886 alternative_service_info_vector(alternative_service_info_vector
),
887 supports_quic(supports_quic
),
888 server_network_stats(server_network_stats
) {}
890 const SettingsMap
* settings_map
;
891 const AlternativeServiceInfoVector
* alternative_service_info_vector
;
892 const SupportsQuic
* supports_quic
;
893 const ServerNetworkStats
* server_network_stats
;
896 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
897 base::ListValue
* spdy_server_list
,
898 SpdySettingsMap
* spdy_settings_map
,
899 AlternativeServiceMap
* alternative_service_map
,
900 IPAddressNumber
* last_quic_address
,
901 ServerNetworkStatsMap
* server_network_stats_map
,
902 const base::Closure
& completion
) {
903 typedef std::map
<HostPortPair
, ServerPref
> ServerPrefMap
;
904 ServerPrefMap server_pref_map
;
906 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
908 // Add servers that support spdy to server_pref_map.
910 for (base::ListValue::const_iterator list_it
= spdy_server_list
->begin();
911 list_it
!= spdy_server_list
->end();
913 if ((*list_it
)->GetAsString(&s
)) {
914 HostPortPair server
= HostPortPair::FromString(s
);
915 server_pref_map
[server
].supports_spdy
= true;
919 // Add servers that have SpdySettings to server_pref_map.
920 for (SpdySettingsMap::iterator map_it
= spdy_settings_map
->begin();
921 map_it
!= spdy_settings_map
->end(); ++map_it
) {
922 const HostPortPair
& server
= map_it
->first
;
923 server_pref_map
[server
].settings_map
= &map_it
->second
;
926 // Add alternative services to server_pref_map.
927 for (AlternativeServiceMap::const_iterator map_it
=
928 alternative_service_map
->begin();
929 map_it
!= alternative_service_map
->end(); ++map_it
) {
930 server_pref_map
[map_it
->first
].alternative_service_info_vector
=
934 // Add ServerNetworkStats servers to server_pref_map.
935 for (ServerNetworkStatsMap::const_iterator map_it
=
936 server_network_stats_map
->begin();
937 map_it
!= server_network_stats_map
->end(); ++map_it
) {
938 const HostPortPair
& server
= map_it
->first
;
939 server_pref_map
[server
].server_network_stats
= &map_it
->second
;
942 // Persist properties to the |path_|.
943 base::DictionaryValue http_server_properties_dict
;
944 base::DictionaryValue
* servers_dict
= new base::DictionaryValue
;
945 for (ServerPrefMap::const_iterator map_it
= server_pref_map
.begin();
946 map_it
!= server_pref_map
.end();
948 const HostPortPair
& server
= map_it
->first
;
949 const ServerPref
& server_pref
= map_it
->second
;
951 base::DictionaryValue
* server_pref_dict
= new base::DictionaryValue
;
953 // Save supports_spdy.
954 if (server_pref
.supports_spdy
)
955 server_pref_dict
->SetBoolean(kSupportsSpdyKey
, server_pref
.supports_spdy
);
956 SaveSpdySettingsToServerPrefs(server_pref
.settings_map
, server_pref_dict
);
957 SaveAlternativeServiceToServerPrefs(
958 server_pref
.alternative_service_info_vector
, server_pref_dict
);
959 SaveNetworkStatsToServerPrefs(server_pref
.server_network_stats
,
962 servers_dict
->SetWithoutPathExpansion(server
.ToString(), server_pref_dict
);
965 http_server_properties_dict
.SetWithoutPathExpansion(kServersKey
,
967 SetVersion(&http_server_properties_dict
, kVersionNumber
);
969 SaveSupportsQuicToPrefs(last_quic_address
, &http_server_properties_dict
);
971 setting_prefs_
= true;
972 pref_service_
->Set(path_
, http_server_properties_dict
);
973 setting_prefs_
= false;
975 // Note that |completion| will be fired after we have written everything to
976 // the Preferences, but likely before these changes are serialized to disk.
977 // This is not a problem though, as JSONPrefStore guarantees that this will
978 // happen, pretty soon, and even in the case we shut down immediately.
979 if (!completion
.is_null())
983 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
984 const SettingsMap
* settings_map
,
985 base::DictionaryValue
* server_pref_dict
) {
989 base::DictionaryValue
* spdy_settings_dict
= new base::DictionaryValue
;
990 for (SettingsMap::const_iterator it
= settings_map
->begin();
991 it
!= settings_map
->end(); ++it
) {
992 SpdySettingsIds id
= it
->first
;
993 uint32 value
= it
->second
.second
;
994 std::string key
= base::StringPrintf("%u", id
);
995 spdy_settings_dict
->SetInteger(key
, value
);
997 server_pref_dict
->SetWithoutPathExpansion(kSettingsKey
, spdy_settings_dict
);
1000 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
1001 const AlternativeServiceInfoVector
* alternative_service_info_vector
,
1002 base::DictionaryValue
* server_pref_dict
) {
1003 if (!alternative_service_info_vector
||
1004 alternative_service_info_vector
->empty()) {
1007 scoped_ptr
<base::ListValue
> alternative_service_list(new base::ListValue
);
1008 for (const AlternativeServiceInfo
& alternative_service_info
:
1009 *alternative_service_info_vector
) {
1010 const AlternativeService alternative_service
=
1011 alternative_service_info
.alternative_service
;
1012 DCHECK(IsAlternateProtocolValid(alternative_service
.protocol
));
1013 base::DictionaryValue
* alternative_service_dict
= new base::DictionaryValue
;
1014 alternative_service_dict
->SetInteger(kPortKey
, alternative_service
.port
);
1015 if (!alternative_service
.host
.empty()) {
1016 alternative_service_dict
->SetString(kHostKey
, alternative_service
.host
);
1018 alternative_service_dict
->SetString(
1019 kProtocolKey
, AlternateProtocolToString(alternative_service
.protocol
));
1020 alternative_service_dict
->SetDouble(kProbabilityKey
,
1021 alternative_service_info
.probability
);
1022 // JSON cannot store int64, so expiration is converted to a string.
1023 alternative_service_dict
->SetString(
1025 base::Int64ToString(
1026 alternative_service_info
.expiration
.ToInternalValue()));
1027 alternative_service_list
->Append(alternative_service_dict
);
1029 if (alternative_service_list
->GetSize() == 0)
1031 server_pref_dict
->SetWithoutPathExpansion(kAlternativeServiceKey
,
1032 alternative_service_list
.release());
1035 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
1036 const IPAddressNumber
* last_quic_address
,
1037 base::DictionaryValue
* http_server_properties_dict
) {
1038 if (!last_quic_address
|| last_quic_address
->empty())
1041 base::DictionaryValue
* supports_quic_dict
= new base::DictionaryValue
;
1042 supports_quic_dict
->SetBoolean(kUsedQuicKey
, true);
1043 supports_quic_dict
->SetString(kAddressKey
,
1044 IPAddressToString(*last_quic_address
));
1045 http_server_properties_dict
->SetWithoutPathExpansion(kSupportsQuicKey
,
1046 supports_quic_dict
);
1049 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
1050 const ServerNetworkStats
* server_network_stats
,
1051 base::DictionaryValue
* server_pref_dict
) {
1052 if (!server_network_stats
)
1055 base::DictionaryValue
* server_network_stats_dict
= new base::DictionaryValue
;
1056 // Becasue JSON doesn't support int64, persist int64 as a string.
1057 server_network_stats_dict
->SetInteger(
1058 kSrttKey
, static_cast<int>(server_network_stats
->srtt
.ToInternalValue()));
1059 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
1060 // bandwidth_estimate.
1061 server_pref_dict
->SetWithoutPathExpansion(kNetworkStatsKey
,
1062 server_network_stats_dict
);
1065 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
1066 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
1067 if (!setting_prefs_
)
1068 ScheduleUpdateCacheOnPrefThread();