Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2017 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. | |
| 4 | |
| 5 #include "net/http/broken_alternative_services.h" | |
| 6 | |
| 7 #include "base/memory/singleton.h" | |
| 8 #include "base/time/time.h" | |
| 9 #include "net/http/http_server_properties_impl.h" | |
| 10 | |
| 11 namespace net { | |
| 12 | |
| 13 namespace { | |
| 14 | |
| 15 // Initial delay for broken alternative services. | |
| 16 const uint64_t kBrokenAlternativeProtocolDelaySecs = 300; | |
| 17 // Subsequent failures result in exponential (base 2) backoff. | |
| 18 // Limit binary shift to limit delay to approximately 2 days. | |
| 19 const int kBrokenDelayMaxShift = 9; | |
| 20 | |
| 21 base::TimeDelta ComputeBrokenAlternativeServiceExpirationDelay( | |
| 22 int broken_count) { | |
| 23 DCHECK(broken_count >= 0); | |
| 24 if (broken_count > kBrokenDelayMaxShift) | |
| 25 broken_count = kBrokenDelayMaxShift; | |
| 26 return base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs) * | |
| 27 (1 << broken_count); | |
| 28 } | |
| 29 | |
| 30 // Default implementation of BrokenAlternativeServices::Clock. | |
| 31 class DefaultClock : public BrokenAlternativeServices::Clock { | |
| 32 public: | |
| 33 static DefaultClock* GetInstance() { | |
| 34 return base::Singleton<DefaultClock>::get(); | |
| 35 } | |
| 36 | |
| 37 DefaultClock() {} | |
| 38 ~DefaultClock() override {} | |
|
Ryan Hamilton
2017/05/26 03:52:08
Do you need these since they're default?
wangyix1
2017/05/27 01:20:08
Done.
| |
| 39 | |
| 40 base::TimeTicks Now() const override { return base::TimeTicks::Now(); } | |
| 41 | |
| 42 private: | |
| 43 DefaultClock(const DefaultClock&) = delete; | |
| 44 void operator=(const DefaultClock&) = delete; | |
|
Ryan Hamilton
2017/05/26 03:52:08
these don't need to be made private since they're
wangyix1
2017/05/27 01:20:09
Done.
| |
| 45 }; | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 BrokenAlternativeServices::Clock* | |
| 50 BrokenAlternativeServices::Clock::GetDefaultClockInstance() { | |
| 51 return DefaultClock::GetInstance(); | |
|
Ryan Hamilton
2017/05/26 03:52:08
I would just inline the base::Singleton<> call her
wangyix1
2017/05/27 01:20:08
Tried this and got compiler error:
'get' is a priv
Ryan Hamilton
2017/05/27 13:28:15
*mind blown*
| |
| 52 } | |
| 53 | |
| 54 BrokenAlternativeServices::BrokenAlternativeServices(Delegate* delegate, | |
| 55 Clock* clock) | |
| 56 : delegate_(delegate), | |
| 57 recently_broken_alternative_services_( | |
| 58 RecentlyBrokenAlternativeServices::NO_AUTO_EVICT), | |
| 59 clock_(clock), | |
| 60 weak_ptr_factory_(this) { | |
| 61 DCHECK(delegate_); | |
| 62 } | |
| 63 | |
| 64 BrokenAlternativeServices::~BrokenAlternativeServices() {} | |
| 65 | |
| 66 void BrokenAlternativeServices::MarkAlternativeServiceBroken( | |
| 67 const AlternativeService& alternative_service) { | |
| 68 // Empty host means use host of origin, callers are supposed to substitute. | |
| 69 DCHECK(!alternative_service.host.empty()); | |
| 70 if (alternative_service.protocol == kProtoUnknown) { | |
| 71 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken."; | |
| 72 return; | |
| 73 } | |
|
Ryan Hamilton
2017/05/26 03:52:08
I think I'd just DCHECK this.
wangyix1
2017/05/27 01:20:09
Done.
| |
| 74 auto it = recently_broken_alternative_services_.Get(alternative_service); | |
| 75 int broken_count = 0; | |
| 76 if (it == recently_broken_alternative_services_.end()) { | |
| 77 recently_broken_alternative_services_.Put(alternative_service, 1); | |
| 78 } else { | |
| 79 broken_count = it->second++; | |
| 80 } | |
| 81 base::TimeTicks expiration = | |
| 82 clock_->Now() + | |
| 83 ComputeBrokenAlternativeServiceExpirationDelay(broken_count); | |
| 84 // Return if alternative service is already in expiration queue. | |
| 85 BrokenAlternativeServiceList::iterator list_it; | |
| 86 if (!AddToBrokenAlternativeServiceListAndMap(alternative_service, expiration, | |
| 87 &list_it)) { | |
| 88 return; | |
| 89 } | |
| 90 | |
| 91 // If this is now the first entry in the list (i.e. |alternative_service| is | |
| 92 // the next alt svc to expire), schedule an expiration task for it. | |
| 93 if (list_it == broken_alternative_service_list_.begin()) { | |
| 94 ScheduleBrokenAlternateProtocolMappingsExpiration(); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 void BrokenAlternativeServices::MarkAlternativeServiceRecentlyBroken( | |
| 99 const AlternativeService& alternative_service) { | |
| 100 if (recently_broken_alternative_services_.Get(alternative_service) == | |
| 101 recently_broken_alternative_services_.end()) { | |
| 102 recently_broken_alternative_services_.Put(alternative_service, 1); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 bool BrokenAlternativeServices::IsAlternativeServiceBroken( | |
| 107 const AlternativeService& alternative_service) const { | |
| 108 // Empty host means use host of origin, callers are supposed to substitute. | |
| 109 DCHECK(!alternative_service.host.empty()); | |
| 110 return broken_alternative_service_map_.find(alternative_service) != | |
| 111 broken_alternative_service_map_.end(); | |
| 112 } | |
| 113 | |
| 114 bool BrokenAlternativeServices::WasAlternativeServiceRecentlyBroken( | |
| 115 const AlternativeService& alternative_service) { | |
| 116 if (alternative_service.protocol == kProtoUnknown) | |
| 117 return false; | |
|
Ryan Hamilton
2017/05/26 03:52:08
I suspect we don't need this since it's already fo
wangyix1
2017/05/27 01:20:10
Done.
| |
| 118 | |
| 119 return recently_broken_alternative_services_.Get(alternative_service) != | |
| 120 recently_broken_alternative_services_.end(); | |
| 121 } | |
| 122 | |
| 123 void BrokenAlternativeServices::ConfirmAlternativeService( | |
| 124 const AlternativeService& alternative_service) { | |
| 125 if (alternative_service.protocol == kProtoUnknown) | |
| 126 return; | |
| 127 | |
| 128 // Remove |alternative_service| from |alternative_service_list_| and | |
| 129 // |alternative_service_map_|. | |
| 130 auto map_it = broken_alternative_service_map_.find(alternative_service); | |
| 131 if (map_it != broken_alternative_service_map_.end()) { | |
| 132 broken_alternative_service_list_.erase(map_it->second); | |
| 133 broken_alternative_service_map_.erase(map_it); | |
| 134 } | |
| 135 | |
| 136 auto it = recently_broken_alternative_services_.Get(alternative_service); | |
| 137 if (it != recently_broken_alternative_services_.end()) { | |
| 138 recently_broken_alternative_services_.Erase(it); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 bool BrokenAlternativeServices ::AddToBrokenAlternativeServiceListAndMap( | |
|
Ryan Hamilton
2017/05/26 03:52:08
nit: no space before "::"
wangyix1
2017/05/27 01:20:08
Done.
| |
| 143 const AlternativeService& alternative_service, | |
| 144 base::TimeTicks expiration, | |
| 145 BrokenAlternativeServiceList::iterator* it) { | |
| 146 DCHECK(it); | |
| 147 | |
| 148 auto map_it = broken_alternative_service_map_.find(alternative_service); | |
| 149 if (map_it != broken_alternative_service_map_.end()) | |
| 150 return false; | |
| 151 | |
| 152 // Iterate from end of |broken_alternative_service_list_| to find where to | |
| 153 // insert it to keep the list sorted by expiration time. | |
| 154 auto list_it = broken_alternative_service_list_.end(); | |
|
Ryan Hamilton
2017/05/26 03:52:08
Is it safe to do -- on an end() iterator? I think
wangyix1
2017/05/27 01:20:09
The reason I used an iterator instead of reverse_i
Ryan Hamilton
2017/05/27 13:28:15
Ah, I see. Fwiw, reverse_iterator has a base() met
| |
| 155 while (list_it != broken_alternative_service_list_.begin()) { | |
| 156 --list_it; | |
| 157 if (list_it->expiration <= expiration) { | |
| 158 ++list_it; | |
| 159 break; | |
| 160 } | |
| 161 } | |
|
Ryan Hamilton
2017/05/26 03:52:08
Could std::lower_bound be used here?
wangyix1
2017/05/27 01:20:10
Looks like std::lower_bound was designed for conta
Ryan Hamilton
2017/05/27 13:28:15
Fair enough. Interestingly it appears to be merely
wangyix1
2017/05/30 21:18:17
Oh interesting. If it's linear, it should be fine
| |
| 162 | |
| 163 // Insert |alternative_service| into the list and the map | |
| 164 list_it = broken_alternative_service_list_.insert( | |
| 165 list_it, BrokenAltSvcExpireInfo(alternative_service, expiration)); | |
| 166 broken_alternative_service_map_.insert( | |
| 167 std::make_pair(alternative_service, list_it)); | |
| 168 | |
| 169 *it = list_it; | |
| 170 return true; | |
| 171 } | |
| 172 | |
| 173 void BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings() { | |
| 174 base::TimeTicks now = clock_->Now(); | |
| 175 ; | |
|
Ryan Hamilton
2017/05/26 03:52:07
nit: remove this?
wangyix1
2017/05/27 01:20:09
Done.
| |
| 176 while (!broken_alternative_service_list_.empty()) { | |
| 177 auto it = broken_alternative_service_list_.begin(); | |
| 178 if (now < it->expiration) { | |
| 179 break; | |
| 180 } | |
| 181 | |
| 182 const AlternativeService expired_alternative_service = | |
| 183 it->alternative_service; | |
| 184 broken_alternative_service_map_.erase(expired_alternative_service); | |
| 185 broken_alternative_service_list_.erase(it); | |
| 186 | |
| 187 delegate_->OnExpireBrokenAlternativeService(expired_alternative_service); | |
|
Ryan Hamilton
2017/05/26 03:52:08
not that it super matters, but since On...() takes
wangyix1
2017/05/27 01:20:09
Done.
| |
| 188 } | |
| 189 | |
| 190 if (!broken_alternative_service_list_.empty()) | |
| 191 ScheduleBrokenAlternateProtocolMappingsExpiration(); | |
| 192 } | |
| 193 | |
| 194 void BrokenAlternativeServices :: | |
| 195 ScheduleBrokenAlternateProtocolMappingsExpiration() { | |
| 196 DCHECK(!broken_alternative_service_list_.empty()); | |
| 197 base::TimeTicks now = clock_->Now(); | |
| 198 base::TimeTicks when = broken_alternative_service_list_.front().expiration; | |
| 199 base::TimeDelta delay = when > now ? when - now : base::TimeDelta(); | |
| 200 expiration_timer_.Stop(); | |
| 201 expiration_timer_.Start( | |
| 202 FROM_HERE, delay, | |
| 203 base::Bind( | |
| 204 &BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings, | |
| 205 weak_ptr_factory_.GetWeakPtr())); | |
| 206 } | |
| 207 | |
| 208 } // namespace net | |
| OLD | NEW |