Chromium Code Reviews| Index: net/http/http_server_properties_impl.cc | 
| diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc | 
| index 6ea3b86a37ecb1392a8540e8f4531eb68e6e95cb..e1daf1b446a009961f339a5c15a2579106bdc7d1 100644 | 
| --- a/net/http/http_server_properties_impl.cc | 
| +++ b/net/http/http_server_properties_impl.cc | 
| @@ -20,25 +20,18 @@ | 
| namespace net { | 
| -namespace { | 
| - | 
| -// Initial delay for broken alternative services. | 
| -const uint64_t kBrokenAlternativeProtocolDelaySecs = 300; | 
| -// Subsequent failures result in exponential (base 2) backoff. | 
| -// Limit binary shift to limit delay to approximately 2 days. | 
| -const int kBrokenDelayMaxShift = 9; | 
| - | 
| -} // namespace | 
| - | 
| HttpServerPropertiesImpl::HttpServerPropertiesImpl() | 
| - : spdy_servers_map_(SpdyServersMap::NO_AUTO_EVICT), | 
| + : HttpServerPropertiesImpl( | 
| + HttpBrokenAlternativeServicesManager::DefaultClock::GetInstance()) {} | 
| + | 
| +HttpServerPropertiesImpl::HttpServerPropertiesImpl( | 
| + HttpBrokenAlternativeServicesManager::Clock* clock) | 
| + : broken_alternative_services_(this, clock), | 
| + spdy_servers_map_(SpdyServersMap::NO_AUTO_EVICT), | 
| alternative_service_map_(AlternativeServiceMap::NO_AUTO_EVICT), | 
| - recently_broken_alternative_services_( | 
| - RecentlyBrokenAlternativeServices::NO_AUTO_EVICT), | 
| server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT), | 
| quic_server_info_map_(QuicServerInfoMap::NO_AUTO_EVICT), | 
| - max_server_configs_stored_in_properties_(kMaxQuicServersToPersist), | 
| - weak_ptr_factory_(this) { | 
| + max_server_configs_stored_in_properties_(kMaxQuicServersToPersist) { | 
| canonical_suffixes_.push_back(".ggpht.com"); | 
| canonical_suffixes_.push_back(".c.youtube.com"); | 
| canonical_suffixes_.push_back(".googlevideo.com"); | 
| @@ -450,71 +443,31 @@ bool HttpServerPropertiesImpl::SetAlternativeServices( | 
| void HttpServerPropertiesImpl::MarkAlternativeServiceBroken( | 
| const AlternativeService& alternative_service) { | 
| - // Empty host means use host of origin, callers are supposed to substitute. | 
| - DCHECK(!alternative_service.host.empty()); | 
| - if (alternative_service.protocol == kProtoUnknown) { | 
| - LOG(DFATAL) << "Trying to mark unknown alternate protocol broken."; | 
| - return; | 
| - } | 
| - auto it = recently_broken_alternative_services_.Get(alternative_service); | 
| - int shift = 0; | 
| - if (it == recently_broken_alternative_services_.end()) { | 
| - recently_broken_alternative_services_.Put(alternative_service, 1); | 
| - } else { | 
| - shift = it->second++; | 
| - } | 
| - if (shift > kBrokenDelayMaxShift) | 
| - shift = kBrokenDelayMaxShift; | 
| - base::TimeDelta delay = | 
| - base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs); | 
| - base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << shift); | 
| - auto result = broken_alternative_services_.insert( | 
| - std::make_pair(alternative_service, when)); | 
| - // Return if alternative service is already in expiration queue. | 
| - if (!result.second) { | 
| - return; | 
| - } | 
| - | 
| - // If this is the only entry in the list, schedule an expiration task. | 
| - // Otherwise it will be rescheduled automatically when the pending task runs. | 
| - if (broken_alternative_services_.size() == 1) { | 
| - ScheduleBrokenAlternateProtocolMappingsExpiration(); | 
| - } | 
| + broken_alternative_services_.MarkAlternativeServiceBroken( | 
| + alternative_service); | 
| } | 
| void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken( | 
| const AlternativeService& alternative_service) { | 
| - if (recently_broken_alternative_services_.Get(alternative_service) == | 
| - recently_broken_alternative_services_.end()) { | 
| - recently_broken_alternative_services_.Put(alternative_service, 1); | 
| - } | 
| + broken_alternative_services_.MarkAlternativeServiceRecentlyBroken( | 
| + alternative_service); | 
| } | 
| bool HttpServerPropertiesImpl::IsAlternativeServiceBroken( | 
| const AlternativeService& alternative_service) const { | 
| - // Empty host means use host of origin, callers are supposed to substitute. | 
| - DCHECK(!alternative_service.host.empty()); | 
| - return base::ContainsKey(broken_alternative_services_, alternative_service); | 
| + return broken_alternative_services_.IsAlternativeServiceBroken( | 
| + alternative_service); | 
| } | 
| bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken( | 
| const AlternativeService& alternative_service) { | 
| - if (alternative_service.protocol == kProtoUnknown) | 
| - return false; | 
| - | 
| - return recently_broken_alternative_services_.Get(alternative_service) != | 
| - recently_broken_alternative_services_.end(); | 
| + return broken_alternative_services_.WasAlternativeServiceRecentlyBroken( | 
| + alternative_service); | 
| } | 
| void HttpServerPropertiesImpl::ConfirmAlternativeService( | 
| const AlternativeService& alternative_service) { | 
| - if (alternative_service.protocol == kProtoUnknown) | 
| - return; | 
| - broken_alternative_services_.erase(alternative_service); | 
| - auto it = recently_broken_alternative_services_.Get(alternative_service); | 
| - if (it != recently_broken_alternative_services_.end()) { | 
| - recently_broken_alternative_services_.Erase(it); | 
| - } | 
| + broken_alternative_services_.ConfirmAlternativeService(alternative_service); | 
| } | 
| const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map() | 
| @@ -649,6 +602,39 @@ bool HttpServerPropertiesImpl::IsInitialized() const { | 
| return true; | 
| } | 
| +void HttpServerPropertiesImpl::OnExpireBrokenAlternativeService( | 
| + const AlternativeService& expired_alternative_service) { | 
| + // Remove every occurrence of |expired_alternative_service| from | 
| + // |alternative_service_map_|. | 
| + for (AlternativeServiceMap::iterator map_it = | 
| + alternative_service_map_.begin(); | 
| + map_it != alternative_service_map_.end();) { | 
| + for (AlternativeServiceInfoVector::iterator it = map_it->second.begin(); | 
| + it != map_it->second.end();) { | 
| + AlternativeService alternative_service(it->alternative_service); | 
| + // Empty hostname in map means hostname of key: substitute before | 
| + // comparing to |expired_alternative_service|. | 
| + if (alternative_service.host.empty()) { | 
| + alternative_service.host = map_it->first.host(); | 
| + } | 
| + if (alternative_service == expired_alternative_service) { | 
| + it = map_it->second.erase(it); | 
| + continue; | 
| + } | 
| + ++it; | 
| + } | 
| + // If an origin has an empty list of alternative services, then remove it | 
| + // from both |canonical_host_to_origin_map_| and | 
| + // |alternative_service_map_|. | 
| + if (map_it->second.empty()) { | 
| + RemoveCanonicalHost(map_it->first); | 
| + map_it = alternative_service_map_.Erase(map_it); | 
| + continue; | 
| + } | 
| + ++map_it; | 
| + } | 
| +} | 
| 
 
Ryan Hamilton
2017/05/25 03:03:50
nit: would you mind moving this back to where the
 
wangyix1
2017/05/26 01:14:25
Done.
 
 | 
| + | 
| AlternativeServiceMap::const_iterator | 
| HttpServerPropertiesImpl::GetAlternateProtocolIterator( | 
| const url::SchemeHostPort& server) { | 
| @@ -708,65 +694,4 @@ void HttpServerPropertiesImpl::RemoveCanonicalHost( | 
| canonical_host_to_origin_map_.erase(canonical->first); | 
| } | 
| -void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() { | 
| - base::TimeTicks now = base::TimeTicks::Now(); | 
| - while (!broken_alternative_services_.empty()) { | 
| - BrokenAlternativeServices::iterator it = | 
| - broken_alternative_services_.begin(); | 
| - if (now < it->second) { | 
| - break; | 
| - } | 
| - | 
| - const AlternativeService expired_alternative_service = it->first; | 
| - broken_alternative_services_.erase(it); | 
| - | 
| - // Remove every occurrence of |expired_alternative_service| from | 
| - // |alternative_service_map_|. | 
| - for (AlternativeServiceMap::iterator map_it = | 
| - alternative_service_map_.begin(); | 
| - map_it != alternative_service_map_.end();) { | 
| - for (AlternativeServiceInfoVector::iterator it = map_it->second.begin(); | 
| - it != map_it->second.end();) { | 
| - AlternativeService alternative_service(it->alternative_service); | 
| - // Empty hostname in map means hostname of key: substitute before | 
| - // comparing to |expired_alternative_service|. | 
| - if (alternative_service.host.empty()) { | 
| - alternative_service.host = map_it->first.host(); | 
| - } | 
| - if (alternative_service == expired_alternative_service) { | 
| - it = map_it->second.erase(it); | 
| - continue; | 
| - } | 
| - ++it; | 
| - } | 
| - // If an origin has an empty list of alternative services, then remove it | 
| - // from both |canonical_host_to_origin_map_| and | 
| - // |alternative_service_map_|. | 
| - if (map_it->second.empty()) { | 
| - RemoveCanonicalHost(map_it->first); | 
| - map_it = alternative_service_map_.Erase(map_it); | 
| - continue; | 
| - } | 
| - ++map_it; | 
| - } | 
| - } | 
| - ScheduleBrokenAlternateProtocolMappingsExpiration(); | 
| -} | 
| - | 
| -void | 
| -HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() { | 
| - if (broken_alternative_services_.empty()) { | 
| - return; | 
| - } | 
| - base::TimeTicks now = base::TimeTicks::Now(); | 
| - base::TimeTicks when = broken_alternative_services_.front().second; | 
| - base::TimeDelta delay = when > now ? when - now : base::TimeDelta(); | 
| - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
| - FROM_HERE, | 
| - base::Bind( | 
| - &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings, | 
| - weak_ptr_factory_.GetWeakPtr()), | 
| - delay); | 
| -} | 
| - | 
| } // namespace net |