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 kNetworkStatsKey
[] = "network_stats";
68 const char kSrttKey
[] = "srtt";
72 ////////////////////////////////////////////////////////////////////////////////
73 // HttpServerPropertiesManager
75 HttpServerPropertiesManager::HttpServerPropertiesManager(
76 PrefService
* pref_service
,
77 const char* pref_path
,
78 scoped_refptr
<base::SequencedTaskRunner
> network_task_runner
)
79 : pref_task_runner_(base::ThreadTaskRunnerHandle::Get()),
80 pref_service_(pref_service
),
81 setting_prefs_(false),
83 network_task_runner_(network_task_runner
) {
85 pref_weak_ptr_factory_
.reset(
86 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
87 pref_weak_ptr_
= pref_weak_ptr_factory_
->GetWeakPtr();
88 pref_cache_update_timer_
.reset(
89 new base::OneShotTimer
<HttpServerPropertiesManager
>);
90 pref_change_registrar_
.Init(pref_service_
);
91 pref_change_registrar_
.Add(
93 base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged
,
94 base::Unretained(this)));
97 HttpServerPropertiesManager::~HttpServerPropertiesManager() {
98 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
99 network_weak_ptr_factory_
.reset();
102 void HttpServerPropertiesManager::InitializeOnNetworkThread() {
103 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
104 network_weak_ptr_factory_
.reset(
105 new base::WeakPtrFactory
<HttpServerPropertiesManager
>(this));
106 http_server_properties_impl_
.reset(new HttpServerPropertiesImpl());
108 network_prefs_update_timer_
.reset(
109 new base::OneShotTimer
<HttpServerPropertiesManager
>);
111 pref_task_runner_
->PostTask(
113 base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
,
117 void HttpServerPropertiesManager::ShutdownOnPrefThread() {
118 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
119 // Cancel any pending updates, and stop listening for pref change updates.
120 pref_cache_update_timer_
->Stop();
121 pref_weak_ptr_factory_
.reset();
122 pref_change_registrar_
.RemoveAll();
126 void HttpServerPropertiesManager::SetVersion(
127 base::DictionaryValue
* http_server_properties_dict
,
128 int version_number
) {
129 if (version_number
< 0)
130 version_number
= kVersionNumber
;
131 DCHECK_LE(version_number
, kVersionNumber
);
132 if (version_number
<= kVersionNumber
)
133 http_server_properties_dict
->SetInteger(kVersionKey
, version_number
);
136 // This is required for conformance with the HttpServerProperties interface.
137 base::WeakPtr
<HttpServerProperties
> HttpServerPropertiesManager::GetWeakPtr() {
138 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
139 return network_weak_ptr_factory_
->GetWeakPtr();
142 void HttpServerPropertiesManager::Clear() {
143 Clear(base::Closure());
146 void HttpServerPropertiesManager::Clear(const base::Closure
& completion
) {
147 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
149 http_server_properties_impl_
->Clear();
150 UpdatePrefsFromCacheOnNetworkThread(completion
);
153 bool HttpServerPropertiesManager::SupportsRequestPriority(
154 const HostPortPair
& server
) {
155 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
156 return http_server_properties_impl_
->SupportsRequestPriority(server
);
159 bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair
& server
) {
160 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
161 return http_server_properties_impl_
->GetSupportsSpdy(server
);
164 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair
& server
,
166 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
168 bool old_support_spdy
= http_server_properties_impl_
->GetSupportsSpdy(server
);
169 http_server_properties_impl_
->SetSupportsSpdy(server
, support_spdy
);
170 bool new_support_spdy
= http_server_properties_impl_
->GetSupportsSpdy(server
);
171 if (old_support_spdy
!= new_support_spdy
)
172 ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY
);
175 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair
& server
) {
176 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
177 return http_server_properties_impl_
->RequiresHTTP11(server
);
180 void HttpServerPropertiesManager::SetHTTP11Required(
181 const HostPortPair
& server
) {
182 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
184 http_server_properties_impl_
->SetHTTP11Required(server
);
185 ScheduleUpdatePrefsOnNetworkThread(HTTP_11_REQUIRED
);
188 void HttpServerPropertiesManager::MaybeForceHTTP11(const HostPortPair
& server
,
189 SSLConfig
* ssl_config
) {
190 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
191 http_server_properties_impl_
->MaybeForceHTTP11(server
, ssl_config
);
194 AlternativeServiceVector
HttpServerPropertiesManager::GetAlternativeServices(
195 const HostPortPair
& origin
) {
196 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
197 return http_server_properties_impl_
->GetAlternativeServices(origin
);
200 bool HttpServerPropertiesManager::SetAlternativeService(
201 const HostPortPair
& origin
,
202 const AlternativeService
& alternative_service
,
203 double alternative_probability
) {
204 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
205 const bool changed
= http_server_properties_impl_
->SetAlternativeService(
206 origin
, alternative_service
, alternative_probability
);
208 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES
);
213 bool HttpServerPropertiesManager::SetAlternativeServices(
214 const HostPortPair
& origin
,
215 const AlternativeServiceInfoVector
& alternative_service_info_vector
) {
216 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
217 const bool changed
= http_server_properties_impl_
->SetAlternativeServices(
218 origin
, alternative_service_info_vector
);
220 ScheduleUpdatePrefsOnNetworkThread(SET_ALTERNATIVE_SERVICES
);
225 void HttpServerPropertiesManager::MarkAlternativeServiceBroken(
226 const AlternativeService
& alternative_service
) {
227 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
228 http_server_properties_impl_
->MarkAlternativeServiceBroken(
229 alternative_service
);
230 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_BROKEN
);
233 void HttpServerPropertiesManager::MarkAlternativeServiceRecentlyBroken(
234 const AlternativeService
& alternative_service
) {
235 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
236 http_server_properties_impl_
->MarkAlternativeServiceRecentlyBroken(
237 alternative_service
);
238 ScheduleUpdatePrefsOnNetworkThread(MARK_ALTERNATIVE_SERVICE_RECENTLY_BROKEN
);
241 bool HttpServerPropertiesManager::IsAlternativeServiceBroken(
242 const AlternativeService
& alternative_service
) const {
243 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
244 return http_server_properties_impl_
->IsAlternativeServiceBroken(
245 alternative_service
);
248 bool HttpServerPropertiesManager::WasAlternativeServiceRecentlyBroken(
249 const AlternativeService
& alternative_service
) {
250 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
251 return http_server_properties_impl_
->WasAlternativeServiceRecentlyBroken(
252 alternative_service
);
255 void HttpServerPropertiesManager::ConfirmAlternativeService(
256 const AlternativeService
& alternative_service
) {
257 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
258 bool old_value
= http_server_properties_impl_
->IsAlternativeServiceBroken(
259 alternative_service
);
260 http_server_properties_impl_
->ConfirmAlternativeService(alternative_service
);
261 bool new_value
= http_server_properties_impl_
->IsAlternativeServiceBroken(
262 alternative_service
);
263 // For persisting, we only care about the value returned by
264 // IsAlternativeServiceBroken. If that value changes, then call persist.
265 if (old_value
!= new_value
)
266 ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE
);
269 void HttpServerPropertiesManager::ClearAlternativeServices(
270 const HostPortPair
& origin
) {
271 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
272 const AlternativeServiceMap
& map
=
273 http_server_properties_impl_
->alternative_service_map();
274 size_t old_size
= map
.size();
275 http_server_properties_impl_
->ClearAlternativeServices(origin
);
276 size_t new_size
= map
.size();
277 // Persist only if we have deleted an entry.
278 if (old_size
!= new_size
)
279 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE
);
282 const AlternativeServiceMap
&
283 HttpServerPropertiesManager::alternative_service_map() const {
284 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
285 return http_server_properties_impl_
->alternative_service_map();
288 scoped_ptr
<base::Value
>
289 HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
291 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
292 return http_server_properties_impl_
->GetAlternativeServiceInfoAsValue();
295 void HttpServerPropertiesManager::SetAlternativeServiceProbabilityThreshold(
297 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
298 http_server_properties_impl_
->SetAlternativeServiceProbabilityThreshold(
302 const SettingsMap
& HttpServerPropertiesManager::GetSpdySettings(
303 const HostPortPair
& host_port_pair
) {
304 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
305 return http_server_properties_impl_
->GetSpdySettings(host_port_pair
);
308 bool HttpServerPropertiesManager::SetSpdySetting(
309 const HostPortPair
& host_port_pair
,
311 SpdySettingsFlags flags
,
313 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
314 bool persist
= http_server_properties_impl_
->SetSpdySetting(
315 host_port_pair
, id
, flags
, value
);
317 ScheduleUpdatePrefsOnNetworkThread(SET_SPDY_SETTING
);
321 void HttpServerPropertiesManager::ClearSpdySettings(
322 const HostPortPair
& host_port_pair
) {
323 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
324 http_server_properties_impl_
->ClearSpdySettings(host_port_pair
);
325 ScheduleUpdatePrefsOnNetworkThread(CLEAR_SPDY_SETTINGS
);
328 void HttpServerPropertiesManager::ClearAllSpdySettings() {
329 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
330 http_server_properties_impl_
->ClearAllSpdySettings();
331 ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALL_SPDY_SETTINGS
);
334 const SpdySettingsMap
& HttpServerPropertiesManager::spdy_settings_map()
336 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
337 return http_server_properties_impl_
->spdy_settings_map();
340 bool HttpServerPropertiesManager::GetSupportsQuic(
341 IPAddressNumber
* last_address
) const {
342 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
343 return http_server_properties_impl_
->GetSupportsQuic(last_address
);
346 void HttpServerPropertiesManager::SetSupportsQuic(
348 const IPAddressNumber
& address
) {
349 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
350 IPAddressNumber old_last_quic_addr
;
351 http_server_properties_impl_
->GetSupportsQuic(&old_last_quic_addr
);
352 http_server_properties_impl_
->SetSupportsQuic(used_quic
, address
);
353 IPAddressNumber new_last_quic_addr
;
354 http_server_properties_impl_
->GetSupportsQuic(&new_last_quic_addr
);
355 if (old_last_quic_addr
!= new_last_quic_addr
)
356 ScheduleUpdatePrefsOnNetworkThread(SET_SUPPORTS_QUIC
);
359 void HttpServerPropertiesManager::SetServerNetworkStats(
360 const HostPortPair
& host_port_pair
,
361 ServerNetworkStats stats
) {
362 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
363 ServerNetworkStats old_stats
;
364 const ServerNetworkStats
* old_stats_ptr
=
365 http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
366 if (http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
))
367 old_stats
= *old_stats_ptr
;
368 http_server_properties_impl_
->SetServerNetworkStats(host_port_pair
, stats
);
369 ServerNetworkStats new_stats
=
370 *(http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
));
371 if (old_stats
!= new_stats
)
372 ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS
);
375 const ServerNetworkStats
* HttpServerPropertiesManager::GetServerNetworkStats(
376 const HostPortPair
& host_port_pair
) {
377 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
378 return http_server_properties_impl_
->GetServerNetworkStats(host_port_pair
);
381 const ServerNetworkStatsMap
&
382 HttpServerPropertiesManager::server_network_stats_map() const {
383 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
384 return http_server_properties_impl_
->server_network_stats_map();
388 // Update the HttpServerPropertiesImpl's cache with data from preferences.
390 void HttpServerPropertiesManager::ScheduleUpdateCacheOnPrefThread() {
391 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
392 // Cancel pending updates, if any.
393 pref_cache_update_timer_
->Stop();
394 StartCacheUpdateTimerOnPrefThread(
395 base::TimeDelta::FromMilliseconds(kUpdateCacheDelayMs
));
398 void HttpServerPropertiesManager::StartCacheUpdateTimerOnPrefThread(
399 base::TimeDelta delay
) {
400 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
401 pref_cache_update_timer_
->Start(
405 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread
);
408 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefThread() {
409 // The preferences can only be read on the pref thread.
410 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
412 if (!pref_service_
->HasPrefPath(path_
))
415 bool detected_corrupted_prefs
= false;
416 const base::DictionaryValue
& http_server_properties_dict
=
417 *pref_service_
->GetDictionary(path_
);
419 int version
= kMissingVersion
;
420 if (!http_server_properties_dict
.GetIntegerWithoutPathExpansion(kVersionKey
,
422 DVLOG(1) << "Missing version. Clearing all properties.";
426 // The properties for a given server is in
427 // http_server_properties_dict["servers"][server].
428 const base::DictionaryValue
* servers_dict
= NULL
;
429 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
430 kServersKey
, &servers_dict
)) {
431 DVLOG(1) << "Malformed http_server_properties for servers.";
435 IPAddressNumber
* addr
= new IPAddressNumber
;
436 ReadSupportsQuic(http_server_properties_dict
, addr
);
438 // String is host/port pair of spdy server.
439 scoped_ptr
<StringVector
> spdy_servers(new StringVector
);
440 scoped_ptr
<SpdySettingsMap
> spdy_settings_map(
441 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
));
442 scoped_ptr
<AlternativeServiceMap
> alternative_service_map(
443 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
));
444 scoped_ptr
<ServerNetworkStatsMap
> server_network_stats_map(
445 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
));
447 for (base::DictionaryValue::Iterator
it(*servers_dict
); !it
.IsAtEnd();
449 // Get server's host/pair.
450 const std::string
& server_str
= it
.key();
451 HostPortPair server
= HostPortPair::FromString(server_str
);
452 if (server
.host().empty()) {
453 DVLOG(1) << "Malformed http_server_properties for server: " << server_str
;
454 detected_corrupted_prefs
= true;
458 const base::DictionaryValue
* server_pref_dict
= NULL
;
459 if (!it
.value().GetAsDictionary(&server_pref_dict
)) {
460 DVLOG(1) << "Malformed http_server_properties server: " << server_str
;
461 detected_corrupted_prefs
= true;
465 // Get if server supports Spdy.
466 bool supports_spdy
= false;
467 if ((server_pref_dict
->GetBoolean(kSupportsSpdyKey
, &supports_spdy
)) &&
469 spdy_servers
->push_back(server_str
);
472 AddToSpdySettingsMap(server
, *server_pref_dict
, spdy_settings_map
.get());
473 if (!AddToAlternativeServiceMap(server
, *server_pref_dict
,
474 alternative_service_map
.get()) ||
475 !AddToNetworkStatsMap(server
, *server_pref_dict
,
476 server_network_stats_map
.get())) {
477 detected_corrupted_prefs
= true;
481 network_task_runner_
->PostTask(
484 &HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread
,
485 base::Unretained(this), base::Owned(spdy_servers
.release()),
486 base::Owned(spdy_settings_map
.release()),
487 base::Owned(alternative_service_map
.release()), base::Owned(addr
),
488 base::Owned(server_network_stats_map
.release()),
489 detected_corrupted_prefs
));
492 void HttpServerPropertiesManager::AddToSpdySettingsMap(
493 const HostPortPair
& server
,
494 const base::DictionaryValue
& server_pref_dict
,
495 SpdySettingsMap
* spdy_settings_map
) {
497 DCHECK(spdy_settings_map
->Peek(server
) == spdy_settings_map
->end());
498 const base::DictionaryValue
* spdy_settings_dict
= NULL
;
499 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
500 kSettingsKey
, &spdy_settings_dict
)) {
503 SettingsMap settings_map
;
504 for (base::DictionaryValue::Iterator
dict_it(*spdy_settings_dict
);
505 !dict_it
.IsAtEnd(); dict_it
.Advance()) {
506 const std::string
& id_str
= dict_it
.key();
508 if (!base::StringToInt(id_str
, &id
)) {
509 DVLOG(1) << "Malformed id in SpdySettings for server: "
510 << server
.ToString();
515 if (!dict_it
.value().GetAsInteger(&value
)) {
516 DVLOG(1) << "Malformed value in SpdySettings for server: "
517 << server
.ToString();
521 SettingsFlagsAndValue
flags_and_value(SETTINGS_FLAG_PERSISTED
, value
);
522 settings_map
[static_cast<SpdySettingsIds
>(id
)] = flags_and_value
;
524 spdy_settings_map
->Put(server
, settings_map
);
527 bool HttpServerPropertiesManager::ParseAlternativeServiceDict(
528 const base::DictionaryValue
& alternative_service_dict
,
529 const std::string
& server_str
,
530 AlternativeServiceInfo
* alternative_service_info
) {
531 // Protocol is mandatory.
532 std::string protocol_str
;
533 if (!alternative_service_dict
.GetStringWithoutPathExpansion(kProtocolKey
,
535 DVLOG(1) << "Malformed alternative service protocol string for server: "
539 AlternateProtocol protocol
= AlternateProtocolFromString(protocol_str
);
540 if (!IsAlternateProtocolValid(protocol
)) {
541 DVLOG(1) << "Invalid alternative service protocol string for server: "
545 alternative_service_info
->alternative_service
.protocol
= protocol
;
547 // Host is optional, defaults to "".
548 alternative_service_info
->alternative_service
.host
.clear();
549 if (alternative_service_dict
.HasKey(kHostKey
) &&
550 !alternative_service_dict
.GetStringWithoutPathExpansion(
551 kHostKey
, &(alternative_service_info
->alternative_service
.host
))) {
552 DVLOG(1) << "Malformed alternative service host string for server: "
557 // Port is mandatory.
559 if (!alternative_service_dict
.GetInteger(kPortKey
, &port
) ||
560 !IsPortValid(port
)) {
561 DVLOG(1) << "Malformed alternative service port for server: " << server_str
;
564 alternative_service_info
->alternative_service
.port
=
565 static_cast<uint32
>(port
);
567 // Probability is optional, defaults to 1.0.
568 alternative_service_info
->probability
= 1.0;
569 if (alternative_service_dict
.HasKey(kProbabilityKey
) &&
570 !alternative_service_dict
.GetDoubleWithoutPathExpansion(
571 kProbabilityKey
, &(alternative_service_info
->probability
))) {
572 DVLOG(1) << "Malformed alternative service probability for server: "
580 bool HttpServerPropertiesManager::AddToAlternativeServiceMap(
581 const HostPortPair
& server
,
582 const base::DictionaryValue
& server_pref_dict
,
583 AlternativeServiceMap
* alternative_service_map
) {
584 DCHECK(alternative_service_map
->Peek(server
) ==
585 alternative_service_map
->end());
586 // Get alternative_services...
587 const base::ListValue
* alternative_service_list
;
588 const base::DictionaryValue
* alternative_service_dict
;
589 AlternativeServiceInfoVector alternative_service_info_vector
;
590 if (server_pref_dict
.GetListWithoutPathExpansion(kAlternativeServiceKey
,
591 &alternative_service_list
)) {
592 for (const base::Value
* alternative_service_list_item
:
593 *alternative_service_list
) {
594 if (!alternative_service_list_item
->GetAsDictionary(
595 &alternative_service_dict
))
597 AlternativeServiceInfo alternative_service_info
;
598 if (!ParseAlternativeServiceDict(*alternative_service_dict
,
600 &alternative_service_info
)) {
603 alternative_service_info_vector
.push_back(alternative_service_info
);
606 // ...or alternate_protocol.
607 // TODO(bnc): Remove this in M46, we do not need preference migration for
609 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
610 kAlternateProtocolKey
, &alternative_service_dict
)) {
613 AlternativeServiceInfo alternative_service_info
;
614 if (!ParseAlternativeServiceDict(*alternative_service_dict
,
616 &alternative_service_info
)) {
619 alternative_service_info_vector
.push_back(alternative_service_info
);
622 if (alternative_service_info_vector
.empty()) {
626 alternative_service_map
->Put(server
, alternative_service_info_vector
);
630 bool HttpServerPropertiesManager::ReadSupportsQuic(
631 const base::DictionaryValue
& http_server_properties_dict
,
632 IPAddressNumber
* last_quic_address
) {
633 const base::DictionaryValue
* supports_quic_dict
= NULL
;
634 if (!http_server_properties_dict
.GetDictionaryWithoutPathExpansion(
635 kSupportsQuicKey
, &supports_quic_dict
)) {
638 bool used_quic
= false;
639 if (!supports_quic_dict
->GetBooleanWithoutPathExpansion(kUsedQuicKey
,
641 DVLOG(1) << "Malformed SupportsQuic";
648 if (!supports_quic_dict
->GetStringWithoutPathExpansion(kAddressKey
,
650 !ParseIPLiteralToNumber(address
, last_quic_address
)) {
651 DVLOG(1) << "Malformed SupportsQuic";
657 bool HttpServerPropertiesManager::AddToNetworkStatsMap(
658 const HostPortPair
& server
,
659 const base::DictionaryValue
& server_pref_dict
,
660 ServerNetworkStatsMap
* network_stats_map
) {
661 DCHECK(network_stats_map
->Peek(server
) == network_stats_map
->end());
662 const base::DictionaryValue
* server_network_stats_dict
= NULL
;
663 if (!server_pref_dict
.GetDictionaryWithoutPathExpansion(
664 kNetworkStatsKey
, &server_network_stats_dict
)) {
668 if (!server_network_stats_dict
->GetIntegerWithoutPathExpansion(kSrttKey
,
670 DVLOG(1) << "Malformed ServerNetworkStats for server: "
671 << server
.ToString();
674 ServerNetworkStats server_network_stats
;
675 server_network_stats
.srtt
= base::TimeDelta::FromInternalValue(srtt
);
676 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
677 // bandwidth_estimate.
678 network_stats_map
->Put(server
, server_network_stats
);
682 void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkThread(
683 StringVector
* spdy_servers
,
684 SpdySettingsMap
* spdy_settings_map
,
685 AlternativeServiceMap
* alternative_service_map
,
686 IPAddressNumber
* last_quic_address
,
687 ServerNetworkStatsMap
* server_network_stats_map
,
688 bool detected_corrupted_prefs
) {
689 // Preferences have the master data because admins might have pushed new
690 // preferences. Update the cached data with new data from preferences.
691 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
693 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdyServers", spdy_servers
->size());
694 http_server_properties_impl_
->InitializeSpdyServers(spdy_servers
, true);
696 // Update the cached data and use the new spdy_settings from preferences.
697 UMA_HISTOGRAM_COUNTS("Net.CountOfSpdySettings", spdy_settings_map
->size());
698 http_server_properties_impl_
->InitializeSpdySettingsServers(
701 // Update the cached data and use the new alternative service list from
703 UMA_HISTOGRAM_COUNTS("Net.CountOfAlternateProtocolServers",
704 alternative_service_map
->size());
705 http_server_properties_impl_
->InitializeAlternativeServiceServers(
706 alternative_service_map
);
708 http_server_properties_impl_
->InitializeSupportsQuic(last_quic_address
);
710 http_server_properties_impl_
->InitializeServerNetworkStats(
711 server_network_stats_map
);
713 // Update the prefs with what we have read (delete all corrupted prefs).
714 if (detected_corrupted_prefs
)
715 ScheduleUpdatePrefsOnNetworkThread(DETECTED_CORRUPTED_PREFS
);
719 // Update Preferences with data from the cached data.
721 void HttpServerPropertiesManager::ScheduleUpdatePrefsOnNetworkThread(
723 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
724 // Cancel pending updates, if any.
725 network_prefs_update_timer_
->Stop();
726 StartPrefsUpdateTimerOnNetworkThread(
727 base::TimeDelta::FromMilliseconds(kUpdatePrefsDelayMs
));
728 // TODO(rtenneti): Delete the following histogram after collecting some data.
729 UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location
,
730 HttpServerPropertiesManager::NUM_LOCATIONS
);
733 void HttpServerPropertiesManager::StartPrefsUpdateTimerOnNetworkThread(
734 base::TimeDelta delay
) {
735 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
736 // This is overridden in tests to post the task without the delay.
737 network_prefs_update_timer_
->Start(
741 &HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread
);
744 // This is required so we can set this as the callback for a timer.
745 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread() {
746 UpdatePrefsFromCacheOnNetworkThread(base::Closure());
749 void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkThread(
750 const base::Closure
& completion
) {
751 DCHECK(network_task_runner_
->RunsTasksOnCurrentThread());
753 base::ListValue
* spdy_server_list
= new base::ListValue
;
754 http_server_properties_impl_
->GetSpdyServerList(
755 spdy_server_list
, kMaxSupportsSpdyServerHostsToPersist
);
757 SpdySettingsMap
* spdy_settings_map
=
758 new SpdySettingsMap(kMaxSpdySettingsHostsToPersist
);
759 const SpdySettingsMap
& main_map
=
760 http_server_properties_impl_
->spdy_settings_map();
762 for (SpdySettingsMap::const_iterator it
= main_map
.begin();
763 it
!= main_map
.end() && count
< kMaxSpdySettingsHostsToPersist
;
765 spdy_settings_map
->Put(it
->first
, it
->second
);
768 AlternativeServiceMap
* alternative_service_map
=
769 new AlternativeServiceMap(kMaxAlternateProtocolHostsToPersist
);
770 const AlternativeServiceMap
& map
=
771 http_server_properties_impl_
->alternative_service_map();
773 typedef std::map
<std::string
, bool> CanonicalHostPersistedMap
;
774 CanonicalHostPersistedMap persisted_map
;
775 for (AlternativeServiceMap::const_iterator it
= map
.begin();
776 it
!= map
.end() && count
< kMaxAlternateProtocolHostsToPersist
; ++it
) {
777 const HostPortPair
& server
= it
->first
;
778 AlternativeServiceInfoVector notbroken_alternative_service_info_vector
;
779 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
780 if (!IsAlternateProtocolValid(
781 alternative_service_info
.alternative_service
.protocol
)) {
784 AlternativeService
alternative_service(
785 alternative_service_info
.alternative_service
);
786 if (alternative_service
.host
.empty()) {
787 alternative_service
.host
= server
.host();
789 if (IsAlternativeServiceBroken(alternative_service
)) {
792 notbroken_alternative_service_info_vector
.push_back(
793 alternative_service_info
);
795 if (notbroken_alternative_service_info_vector
.empty()) {
798 alternative_service_map
->Put(server
,
799 notbroken_alternative_service_info_vector
);
800 std::string canonical_suffix
=
801 http_server_properties_impl_
->GetCanonicalSuffix(server
.host());
802 if (!canonical_suffix
.empty()) {
803 if (persisted_map
.find(canonical_suffix
) != persisted_map
.end())
805 persisted_map
[canonical_suffix
] = true;
810 ServerNetworkStatsMap
* server_network_stats_map
=
811 new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist
);
812 const ServerNetworkStatsMap
& main_server_network_stats_map
=
813 http_server_properties_impl_
->server_network_stats_map();
814 for (ServerNetworkStatsMap::const_iterator it
=
815 main_server_network_stats_map
.begin();
816 it
!= main_server_network_stats_map
.end(); ++it
) {
817 server_network_stats_map
->Put(it
->first
, it
->second
);
820 IPAddressNumber
* last_quic_addr
= new IPAddressNumber
;
821 http_server_properties_impl_
->GetSupportsQuic(last_quic_addr
);
822 // Update the preferences on the pref thread.
823 pref_task_runner_
->PostTask(
826 &HttpServerPropertiesManager::UpdatePrefsOnPrefThread
, pref_weak_ptr_
,
827 base::Owned(spdy_server_list
), base::Owned(spdy_settings_map
),
828 base::Owned(alternative_service_map
), base::Owned(last_quic_addr
),
829 base::Owned(server_network_stats_map
), completion
));
832 // A local or temporary data structure to hold |supports_spdy|, SpdySettings,
833 // AlternativeServiceInfoVector, and SupportsQuic preferences for a server. This
834 // is used only in UpdatePrefsOnPrefThread.
837 : supports_spdy(false),
839 alternative_service_info_vector(NULL
),
841 server_network_stats(NULL
) {}
844 const SettingsMap
* settings_map
,
845 const AlternativeServiceInfoVector
* alternative_service_info_vector
,
846 const SupportsQuic
* supports_quic
,
847 const ServerNetworkStats
* server_network_stats
)
848 : supports_spdy(supports_spdy
),
849 settings_map(settings_map
),
850 alternative_service_info_vector(alternative_service_info_vector
),
851 supports_quic(supports_quic
),
852 server_network_stats(server_network_stats
) {}
854 const SettingsMap
* settings_map
;
855 const AlternativeServiceInfoVector
* alternative_service_info_vector
;
856 const SupportsQuic
* supports_quic
;
857 const ServerNetworkStats
* server_network_stats
;
860 void HttpServerPropertiesManager::UpdatePrefsOnPrefThread(
861 base::ListValue
* spdy_server_list
,
862 SpdySettingsMap
* spdy_settings_map
,
863 AlternativeServiceMap
* alternative_service_map
,
864 IPAddressNumber
* last_quic_address
,
865 ServerNetworkStatsMap
* server_network_stats_map
,
866 const base::Closure
& completion
) {
867 typedef std::map
<HostPortPair
, ServerPref
> ServerPrefMap
;
868 ServerPrefMap server_pref_map
;
870 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
872 // Add servers that support spdy to server_pref_map.
874 for (base::ListValue::const_iterator list_it
= spdy_server_list
->begin();
875 list_it
!= spdy_server_list
->end();
877 if ((*list_it
)->GetAsString(&s
)) {
878 HostPortPair server
= HostPortPair::FromString(s
);
879 server_pref_map
[server
].supports_spdy
= true;
883 // Add servers that have SpdySettings to server_pref_map.
884 for (SpdySettingsMap::iterator map_it
= spdy_settings_map
->begin();
885 map_it
!= spdy_settings_map
->end(); ++map_it
) {
886 const HostPortPair
& server
= map_it
->first
;
887 server_pref_map
[server
].settings_map
= &map_it
->second
;
890 // Add alternative services to server_pref_map.
891 for (AlternativeServiceMap::const_iterator map_it
=
892 alternative_service_map
->begin();
893 map_it
!= alternative_service_map
->end(); ++map_it
) {
894 server_pref_map
[map_it
->first
].alternative_service_info_vector
=
898 // Add ServerNetworkStats servers to server_pref_map.
899 for (ServerNetworkStatsMap::const_iterator map_it
=
900 server_network_stats_map
->begin();
901 map_it
!= server_network_stats_map
->end(); ++map_it
) {
902 const HostPortPair
& server
= map_it
->first
;
903 server_pref_map
[server
].server_network_stats
= &map_it
->second
;
906 // Persist properties to the |path_|.
907 base::DictionaryValue http_server_properties_dict
;
908 base::DictionaryValue
* servers_dict
= new base::DictionaryValue
;
909 for (ServerPrefMap::const_iterator map_it
= server_pref_map
.begin();
910 map_it
!= server_pref_map
.end();
912 const HostPortPair
& server
= map_it
->first
;
913 const ServerPref
& server_pref
= map_it
->second
;
915 base::DictionaryValue
* server_pref_dict
= new base::DictionaryValue
;
917 // Save supports_spdy.
918 if (server_pref
.supports_spdy
)
919 server_pref_dict
->SetBoolean(kSupportsSpdyKey
, server_pref
.supports_spdy
);
920 SaveSpdySettingsToServerPrefs(server_pref
.settings_map
, server_pref_dict
);
921 SaveAlternativeServiceToServerPrefs(
922 server_pref
.alternative_service_info_vector
, server_pref_dict
);
923 SaveNetworkStatsToServerPrefs(server_pref
.server_network_stats
,
926 servers_dict
->SetWithoutPathExpansion(server
.ToString(), server_pref_dict
);
929 http_server_properties_dict
.SetWithoutPathExpansion(kServersKey
,
931 SetVersion(&http_server_properties_dict
, kVersionNumber
);
933 SaveSupportsQuicToPrefs(last_quic_address
, &http_server_properties_dict
);
935 setting_prefs_
= true;
936 pref_service_
->Set(path_
, http_server_properties_dict
);
937 setting_prefs_
= false;
939 // Note that |completion| will be fired after we have written everything to
940 // the Preferences, but likely before these changes are serialized to disk.
941 // This is not a problem though, as JSONPrefStore guarantees that this will
942 // happen, pretty soon, and even in the case we shut down immediately.
943 if (!completion
.is_null())
947 void HttpServerPropertiesManager::SaveSpdySettingsToServerPrefs(
948 const SettingsMap
* settings_map
,
949 base::DictionaryValue
* server_pref_dict
) {
953 base::DictionaryValue
* spdy_settings_dict
= new base::DictionaryValue
;
954 for (SettingsMap::const_iterator it
= settings_map
->begin();
955 it
!= settings_map
->end(); ++it
) {
956 SpdySettingsIds id
= it
->first
;
957 uint32 value
= it
->second
.second
;
958 std::string key
= base::StringPrintf("%u", id
);
959 spdy_settings_dict
->SetInteger(key
, value
);
961 server_pref_dict
->SetWithoutPathExpansion(kSettingsKey
, spdy_settings_dict
);
964 void HttpServerPropertiesManager::SaveAlternativeServiceToServerPrefs(
965 const AlternativeServiceInfoVector
* alternative_service_info_vector
,
966 base::DictionaryValue
* server_pref_dict
) {
967 if (!alternative_service_info_vector
||
968 alternative_service_info_vector
->empty()) {
971 scoped_ptr
<base::ListValue
> alternative_service_list(new base::ListValue
);
972 for (const AlternativeServiceInfo
& alternative_service_info
:
973 *alternative_service_info_vector
) {
974 const AlternativeService alternative_service
=
975 alternative_service_info
.alternative_service
;
976 DCHECK(IsAlternateProtocolValid(alternative_service
.protocol
));
977 base::DictionaryValue
* alternative_service_dict
= new base::DictionaryValue
;
978 alternative_service_dict
->SetInteger(kPortKey
, alternative_service
.port
);
979 if (!alternative_service
.host
.empty()) {
980 alternative_service_dict
->SetString(kHostKey
, alternative_service
.host
);
982 alternative_service_dict
->SetString(
983 kProtocolKey
, AlternateProtocolToString(alternative_service
.protocol
));
984 alternative_service_dict
->SetDouble(kProbabilityKey
,
985 alternative_service_info
.probability
);
986 alternative_service_list
->Append(alternative_service_dict
);
988 if (alternative_service_list
->GetSize() == 0)
990 server_pref_dict
->SetWithoutPathExpansion(kAlternativeServiceKey
,
991 alternative_service_list
.release());
994 void HttpServerPropertiesManager::SaveSupportsQuicToPrefs(
995 const IPAddressNumber
* last_quic_address
,
996 base::DictionaryValue
* http_server_properties_dict
) {
997 if (!last_quic_address
|| last_quic_address
->empty())
1000 base::DictionaryValue
* supports_quic_dict
= new base::DictionaryValue
;
1001 supports_quic_dict
->SetBoolean(kUsedQuicKey
, true);
1002 supports_quic_dict
->SetString(kAddressKey
,
1003 IPAddressToString(*last_quic_address
));
1004 http_server_properties_dict
->SetWithoutPathExpansion(kSupportsQuicKey
,
1005 supports_quic_dict
);
1008 void HttpServerPropertiesManager::SaveNetworkStatsToServerPrefs(
1009 const ServerNetworkStats
* server_network_stats
,
1010 base::DictionaryValue
* server_pref_dict
) {
1011 if (!server_network_stats
)
1014 base::DictionaryValue
* server_network_stats_dict
= new base::DictionaryValue
;
1015 // Becasue JSON doesn't support int64, persist int64 as a string.
1016 server_network_stats_dict
->SetInteger(
1017 kSrttKey
, static_cast<int>(server_network_stats
->srtt
.ToInternalValue()));
1018 // TODO(rtenneti): When QUIC starts using bandwidth_estimate, then persist
1019 // bandwidth_estimate.
1020 server_pref_dict
->SetWithoutPathExpansion(kNetworkStatsKey
,
1021 server_network_stats_dict
);
1024 void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() {
1025 DCHECK(pref_task_runner_
->RunsTasksOnCurrentThread());
1026 if (!setting_prefs_
)
1027 ScheduleUpdateCacheOnPrefThread();