Index: net/http/http_server_properties_manager.cc |
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc |
index 95ef2f444496beced2a3b87578b9781792a0ca76..bcab74c1e3dc0bff3c40a3ba2203eaab6576fea9 100644 |
--- a/net/http/http_server_properties_manager.cc |
+++ b/net/http/http_server_properties_manager.cc |
@@ -49,6 +49,12 @@ const int kMaxSupportsSpdyServerHostsToPersist = 300; |
// Persist 200 ServerNetworkStats. |
const int kMaxServerNetworkStatsHostsToPersist = 200; |
+// Persist 200 BrokenAlternativeServices |
+const int kMaxBrokenAlternativeServicesToPersist = 200; |
+ |
+// Persist 200 RecentlyBrokenAlternativeServices |
+const int kMaxRecentlyBrokenAlternativeServicesToPersist = 200; |
+ |
const char kVersionKey[] = "version"; |
const char kServersKey[] = "servers"; |
const char kSupportsSpdyKey[] = "supports_spdy"; |
@@ -64,6 +70,9 @@ const char kPortKey[] = "port"; |
const char kExpirationKey[] = "expiration"; |
const char kNetworkStatsKey[] = "network_stats"; |
const char kSrttKey[] = "srtt"; |
+const char kBrokenAlternativeServicesKey[] = "broken_alternative_services"; |
+const char kRecentlyBrokenAlternativeServicesKey[] = |
+ "recently_broken_alternative_services"; |
} // namespace |
@@ -79,6 +88,7 @@ HttpServerPropertiesManager::HttpServerPropertiesManager( |
: pref_task_runner_(std::move(pref_task_runner)), |
pref_delegate_(pref_delegate), |
setting_prefs_(false), |
+ clock_(&default_clock_), |
is_initialized_(false), |
network_task_runner_(std::move(network_task_runner)) { |
DCHECK(pref_task_runner_->RunsTasksInCurrentSequence()); |
@@ -514,6 +524,64 @@ void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefSequence() { |
detected_corrupted_prefs = true; |
} |
+ std::unique_ptr<RecentlyBrokenAlternativeServices> |
+ recently_broken_alternative_services; |
+ const base::ListValue* recently_broken_alt_svc_list = nullptr; |
+ |
+ std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list; |
+ const base::ListValue* broken_alt_svc_list = nullptr; |
+ |
+ // Read recently broken alternative services if they exist. |
+ if (http_server_properties_dict.GetListWithoutPathExpansion( |
+ kRecentlyBrokenAlternativeServicesKey, |
+ &recently_broken_alt_svc_list)) { |
+ recently_broken_alternative_services.reset( |
+ new RecentlyBrokenAlternativeServices( |
+ RecentlyBrokenAlternativeServices::NO_AUTO_EVICT)); |
+ |
+ for (auto it = recently_broken_alt_svc_list->begin(); |
+ it != recently_broken_alt_svc_list->end(); ++it) { |
+ const base::DictionaryValue* entry_dict = nullptr; |
+ if (!it->GetAsDictionary(&entry_dict) || |
+ !AddRecentlyBrokenAlternativeServiceData( |
+ entry_dict, recently_broken_alternative_services.get())) { |
+ DVLOG(1) << "Malformed http_server_properties for recently broken " |
+ << "alternative services list."; |
+ detected_corrupted_prefs = true; |
+ } |
+ } |
+ |
+ // Read broken alternative services if they exist |
+ if (http_server_properties_dict.GetListWithoutPathExpansion( |
+ kBrokenAlternativeServicesKey, &broken_alt_svc_list)) { |
+ broken_alternative_service_list.reset(new BrokenAlternativeServiceList()); |
+ |
+ for (auto it = broken_alt_svc_list->begin(); |
+ it != broken_alt_svc_list->end(); ++it) { |
+ const base::DictionaryValue* entry_dict = nullptr; |
+ AlternativeService alternative_service; |
+ base::TimeTicks expiration_time_ticks; |
+ if (!it->GetAsDictionary(&entry_dict) || |
+ !ExtractBrokenAlternativeServiceData( |
+ entry_dict, &alternative_service, &expiration_time_ticks)) { |
+ DVLOG(1) << "Malformed http_server_properties for broken alternative " |
+ << "services list."; |
+ detected_corrupted_prefs = true; |
+ continue; |
+ } |
+ if (recently_broken_alternative_services->Peek(alternative_service) != |
+ recently_broken_alternative_services->end()) { |
+ broken_alternative_service_list->push_back( |
+ std::make_pair(alternative_service, expiration_time_ticks)); |
+ } else { |
+ DVLOG(1) << "Broken alternative service does not have an entry in " |
+ << "map of recently broken alternative services. " |
+ << "Will not be added."; |
+ } |
+ } |
+ } |
+ } |
+ |
network_task_runner_->PostTask( |
FROM_HERE, |
base::Bind( |
@@ -522,9 +590,65 @@ void HttpServerPropertiesManager::UpdateCacheFromPrefsOnPrefSequence() { |
base::Owned(alternative_service_map.release()), base::Owned(addr), |
base::Owned(server_network_stats_map.release()), |
base::Owned(quic_server_info_map.release()), |
+ base::Passed(&broken_alternative_service_list), |
+ base::Passed(&recently_broken_alternative_services), |
detected_corrupted_prefs)); |
} |
+bool HttpServerPropertiesManager::ExtractBrokenAlternativeServiceData( |
+ const base::DictionaryValue* broken_alternative_service_dict, |
+ AlternativeService* alternative_service, |
+ base::TimeTicks* expiration_time_ticks) { |
+ DCHECK(broken_alternative_service_dict); |
+ |
+ if (broken_alternative_service_dict->size() != 1u) |
+ return false; |
+ |
+ base::DictionaryValue::Iterator it(*broken_alternative_service_dict); |
+ |
+ const std::string& alternative_service_string = it.key(); |
+ if (!AlternativeService::FromString(alternative_service_string, |
+ alternative_service)) |
+ return false; |
+ |
+ int64_t expiration_int64; |
+ std::string time_ticks_string; |
+ if (!it.value().GetAsString(&time_ticks_string)) |
+ return false; |
+ if (!base::StringToInt64(time_ticks_string, &expiration_int64)) |
+ return false; |
+ time_t expiration_time_t = static_cast<time_t>(expiration_int64); |
+ // Convert expiration from time_t to Time to TimeTicks |
+ *expiration_time_ticks = |
+ clock_->NowTicks() + |
+ (base::Time::FromTimeT(expiration_time_t) - base::Time::Now()); |
+ |
+ return true; |
+} |
+ |
+bool HttpServerPropertiesManager::AddRecentlyBrokenAlternativeServiceData( |
+ const base::DictionaryValue* recently_broken_alternative_service_dict, |
+ RecentlyBrokenAlternativeServices* recently_broken_alternative_services) { |
+ DCHECK(recently_broken_alternative_service_dict); |
+ |
+ if (recently_broken_alternative_service_dict->size() != 1u) |
+ return false; |
+ |
+ base::DictionaryValue::Iterator it(*recently_broken_alternative_service_dict); |
+ |
+ AlternativeService alt_service; |
+ const std::string& alt_service_string = it.key(); |
+ if (!AlternativeService::FromString(alt_service_string, &alt_service)) |
+ return false; |
+ |
+ int broken_count; |
+ if (!it.value().GetAsInteger(&broken_count)) |
+ return false; |
+ |
+ recently_broken_alternative_services->Put(alt_service, broken_count); |
+ return true; |
+} |
+ |
bool HttpServerPropertiesManager::AddServersData( |
const base::DictionaryValue& servers_dict, |
ServerList* spdy_servers, |
@@ -780,6 +904,10 @@ void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkSequence( |
IPAddress* last_quic_address, |
ServerNetworkStatsMap* server_network_stats_map, |
QuicServerInfoMap* quic_server_info_map, |
+ std::unique_ptr<BrokenAlternativeServiceList> |
+ broken_alternative_service_list, |
+ std::unique_ptr<RecentlyBrokenAlternativeServices> |
+ recently_broken_alternative_services, |
bool detected_corrupted_prefs) { |
// Preferences have the master data because admins might have pushed new |
// preferences. Update the cached data with new data from preferences. |
@@ -804,6 +932,13 @@ void HttpServerPropertiesManager::UpdateCacheFromPrefsOnNetworkSequence( |
http_server_properties_impl_->SetQuicServerInfoMap(quic_server_info_map); |
+ if (recently_broken_alternative_services) { |
+ DCHECK(broken_alternative_service_list); |
+ http_server_properties_impl_->AddBrokenAndRecentlyBrokenAlternativeServices( |
+ std::move(broken_alternative_service_list), |
+ std::move(recently_broken_alternative_services)); |
+ } |
+ |
// Update the prefs with what we have read (delete all corrupted prefs). |
if (detected_corrupted_prefs) |
ScheduleUpdatePrefsOnNetworkSequence(DETECTED_CORRUPTED_PREFS); |
@@ -869,9 +1004,6 @@ void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkSequence( |
if (alternative_service.host.empty()) { |
alternative_service.host = server.host(); |
} |
- if (IsAlternativeServiceBroken(alternative_service)) { |
- continue; |
- } |
notbroken_alternative_service_info_vector.push_back( |
alternative_service_info); |
} |
@@ -915,6 +1047,41 @@ void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkSequence( |
} |
} |
+ // Make copy of list of broken alternative services stored in |
+ // |http_server_properties_impl_| |
+ BrokenAlternativeServiceList* broken_alt_svc_list_copy = nullptr; |
+ const BrokenAlternativeServiceList& broken_alternative_service_list = |
+ http_server_properties_impl_->broken_alternative_service_list(); |
+ if (broken_alternative_service_list.size() > 0) { |
+ broken_alt_svc_list_copy = new BrokenAlternativeServiceList(); |
+ size_t count = 0; |
+ for (auto it = broken_alternative_service_list.begin(); |
+ it != broken_alternative_service_list.end() && |
+ count < kMaxBrokenAlternativeServicesToPersist; |
+ ++it) { |
+ broken_alt_svc_list_copy->push_back(*it); |
+ ++count; |
+ } |
+ } |
+ |
+ // Make copy of RecentlyBrokenAternativeServices stored in |
+ // |http_server_properties_impl_|. |
+ RecentlyBrokenAlternativeServices* recently_broken_alt_svc_copy = nullptr; |
+ const RecentlyBrokenAlternativeServices& recently_broken_alt_services = |
+ http_server_properties_impl_->recently_broken_alternative_services(); |
+ if (recently_broken_alt_services.size() > 0) { |
+ recently_broken_alt_svc_copy = new RecentlyBrokenAlternativeServices( |
+ kMaxRecentlyBrokenAlternativeServicesToPersist); |
+ size_t count = 0; |
+ for (auto it = recently_broken_alt_services.rbegin(); |
+ it != recently_broken_alt_services.rend() && |
+ count < kMaxRecentlyBrokenAlternativeServicesToPersist; |
+ ++it) { |
+ recently_broken_alt_svc_copy->Put(it->first, it->second); |
+ ++count; |
+ } |
+ } |
+ |
IPAddress* last_quic_addr = new IPAddress; |
http_server_properties_impl_->GetSupportsQuic(last_quic_addr); |
// Update the preferences on the pref thread. |
@@ -924,7 +1091,9 @@ void HttpServerPropertiesManager::UpdatePrefsFromCacheOnNetworkSequence( |
&HttpServerPropertiesManager::UpdatePrefsOnPrefThread, pref_weak_ptr_, |
base::Owned(spdy_server_list), base::Owned(alternative_service_map), |
base::Owned(last_quic_addr), base::Owned(server_network_stats_map), |
- base::Owned(quic_server_info_map), completion)); |
+ base::Owned(quic_server_info_map), |
+ base::Owned(broken_alt_svc_list_copy), |
+ base::Owned(recently_broken_alt_svc_copy), completion)); |
} |
// A local or temporary data structure to hold |supports_spdy|, SpdySettings, |
@@ -962,6 +1131,8 @@ void HttpServerPropertiesManager::UpdatePrefsOnPrefThread( |
IPAddress* last_quic_address, |
ServerNetworkStatsMap* server_network_stats_map, |
QuicServerInfoMap* quic_server_info_map, |
+ BrokenAlternativeServiceList* broken_alternative_service_list, |
+ RecentlyBrokenAlternativeServices* recently_broken_alternative_services, |
const base::Closure& completion) { |
typedef base::MRUCache<url::SchemeHostPort, ServerPref> ServerPrefMap; |
ServerPrefMap server_pref_map(ServerPrefMap::NO_AUTO_EVICT); |
@@ -1048,6 +1219,12 @@ void HttpServerPropertiesManager::UpdatePrefsOnPrefThread( |
SaveQuicServerInfoMapToServerPrefs(quic_server_info_map, |
&http_server_properties_dict); |
+ SaveBrokenAlternativeServiceListToPrefs(broken_alternative_service_list, |
+ &http_server_properties_dict); |
+ |
+ SaveRecentlyBrokenAlternativeServicesToPrefs( |
+ recently_broken_alternative_services, &http_server_properties_dict); |
+ |
setting_prefs_ = true; |
pref_delegate_->SetServerProperties(http_server_properties_dict); |
setting_prefs_ = false; |
@@ -1144,6 +1321,57 @@ void HttpServerPropertiesManager::SaveQuicServerInfoMapToServerPrefs( |
kQuicServers, std::move(quic_servers_dict)); |
} |
+void HttpServerPropertiesManager::SaveBrokenAlternativeServiceListToPrefs( |
+ const BrokenAlternativeServiceList* broken_alternative_service_list, |
+ base::DictionaryValue* http_server_properties_dict) { |
+ if (!broken_alternative_service_list) |
+ return; |
+ |
+ base::ListValue* broken_alt_services_list = new base::ListValue; |
+ for (const auto& entry : *broken_alternative_service_list) { |
+ const AlternativeService& alt_service = entry.first; |
+ const base::TimeTicks& expiration_time_ticks = entry.second; |
+ // Convert expiration from TimeTicks to Time to time_t |
+ time_t expiration_time_t = |
+ (base::Time::Now() + (expiration_time_ticks - clock_->NowTicks())) |
+ .ToTimeT(); |
+ int64_t expiration_int64 = static_cast<int64_t>(expiration_time_t); |
+ std::unique_ptr<base::DictionaryValue> broken_alt_service_entry_dict = |
+ base::MakeUnique<base::DictionaryValue>(); |
+ broken_alt_service_entry_dict->SetStringWithoutPathExpansion( |
+ alt_service.ToString(), base::Int64ToString(expiration_int64)); |
+ broken_alt_services_list->Append(std::move(broken_alt_service_entry_dict)); |
+ } |
+ http_server_properties_dict->SetWithoutPathExpansion( |
+ kBrokenAlternativeServicesKey, |
+ std::unique_ptr<base::Value>(broken_alt_services_list)); |
+} |
+ |
+void HttpServerPropertiesManager::SaveRecentlyBrokenAlternativeServicesToPrefs( |
+ const RecentlyBrokenAlternativeServices* |
+ recently_broken_alternative_services, |
+ base::DictionaryValue* http_server_properties_dict) { |
+ if (!recently_broken_alternative_services) |
+ return; |
+ |
+ // JSON list will have entries ordered from least recent to most recent. |
+ base::ListValue* recently_broken_alt_services_list = new base::ListValue; |
+ for (auto it = recently_broken_alternative_services->rbegin(); |
+ it != recently_broken_alternative_services->rend(); ++it) { |
+ const AlternativeService& alt_service = it->first; |
+ int broken_count = it->second; |
+ std::unique_ptr<base::DictionaryValue> broken_alt_service_entry_dict = |
+ base::MakeUnique<base::DictionaryValue>(); |
+ broken_alt_service_entry_dict->SetIntegerWithoutPathExpansion( |
+ alt_service.ToString(), broken_count); |
+ recently_broken_alt_services_list->Append( |
+ std::move(broken_alt_service_entry_dict)); |
+ } |
+ http_server_properties_dict->SetWithoutPathExpansion( |
+ kRecentlyBrokenAlternativeServicesKey, |
+ std::unique_ptr<base::Value>(recently_broken_alt_services_list)); |
+} |
+ |
void HttpServerPropertiesManager::OnHttpServerPropertiesChanged() { |
DCHECK(pref_task_runner_->RunsTasksInCurrentSequence()); |
if (!setting_prefs_) |
@@ -1155,4 +1383,13 @@ void HttpServerPropertiesManager::SetInitialized() { |
is_initialized_ = true; |
} |
+void HttpServerPropertiesManager::SetTickClockForTesting( |
+ base::TickClock* clock) { |
+ DCHECK(clock); |
+ DCHECK(http_server_properties_impl_); |
+ clock_ = clock; |
+ http_server_properties_impl_->SetBrokenAlternativeServicesTickClockForTesting( |
+ clock); |
+} |
+ |
} // namespace net |