1 // Copyright 2017 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_HTTP_BROKEN_ALTERNATIVE_SERVICES_H_ 6 #define NET_HTTP_BROKEN_ALTERNATIVE_SERVICES_H_ 7 8 #include <list> 9 #include <set> 10 11 #include "base/containers/lru_cache.h" 12 #include "base/memory/raw_ptr.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/time/time.h" 15 #include "base/timer/timer.h" 16 #include "net/base/network_anonymization_key.h" 17 #include "net/http/alternative_service.h" 18 19 namespace base { 20 class TickClock; 21 } 22 23 namespace net { 24 25 // Contains information about a broken alternative service, and the context in 26 // which it's known to be broken. 27 struct NET_EXPORT_PRIVATE BrokenAlternativeService { 28 // If |use_network_anonymization_key| is false, |network_anonymization_key| is 29 // ignored, and an empty NetworkAnonymizationKey is used instead. 30 BrokenAlternativeService( 31 const AlternativeService& alternative_service, 32 const NetworkAnonymizationKey& network_anonymization_key, 33 bool use_network_anonymization_key); 34 35 ~BrokenAlternativeService(); 36 37 bool operator<(const BrokenAlternativeService& other) const; 38 39 AlternativeService alternative_service; 40 41 // The context in which the alternative service is known to be broken in. Used 42 // to avoid cross-NetworkAnonymizationKey communication. 43 NetworkAnonymizationKey network_anonymization_key; 44 }; 45 46 // Stores broken alternative services and when their brokenness expires. 47 typedef std::list<std::pair<BrokenAlternativeService, base::TimeTicks>> 48 BrokenAlternativeServiceList; 49 50 // Stores how many times an alternative service has been marked broken. 51 class RecentlyBrokenAlternativeServices 52 : public base::LRUCache<BrokenAlternativeService, int> { 53 public: RecentlyBrokenAlternativeServices(int max_recently_broken_alternative_service_entries)54 explicit RecentlyBrokenAlternativeServices( 55 int max_recently_broken_alternative_service_entries) 56 : base::LRUCache<BrokenAlternativeService, int>( 57 max_recently_broken_alternative_service_entries) {} 58 }; 59 60 // This class tracks HTTP alternative services that have been marked as broken. 61 // The brokenness of an alt-svc will expire after some time according to an 62 // exponential back-off formula: each time an alt-svc is marked broken, the 63 // expiration delay will be some constant multiple of its previous expiration 64 // delay. This prevents broken alt-svcs from being retried too often by the 65 // network stack. 66 // 67 // Intended solely for use by HttpServerProperties. 68 class NET_EXPORT_PRIVATE BrokenAlternativeServices { 69 public: 70 // Delegate to be used by owner so it can be notified when the brokenness of 71 // an AlternativeService expires. 72 class NET_EXPORT Delegate { 73 public: 74 // Called when a broken alternative service's expiration time is reached. 75 virtual void OnExpireBrokenAlternativeService( 76 const AlternativeService& expired_alternative_service, 77 const NetworkAnonymizationKey& network_anonymization_key) = 0; 78 virtual ~Delegate() = default; 79 }; 80 81 // |delegate| will be notified when a broken alternative service expires. It 82 // must not be null. 83 // |clock| is used for setting expiration times and scheduling the 84 // expiration of broken alternative services. It must not be null. 85 // |delegate| and |clock| are both unowned and must outlive this. 86 BrokenAlternativeServices(int max_recently_broken_alternative_service_entries, 87 Delegate* delegate, 88 const base::TickClock* clock); 89 90 BrokenAlternativeServices(const BrokenAlternativeServices&) = delete; 91 void operator=(const BrokenAlternativeServices&) = delete; 92 93 ~BrokenAlternativeServices(); 94 95 // Clears all broken and recently-broken alternative services (i.e. mark all 96 // as not broken nor recently-broken). 97 void Clear(); 98 99 // Marks |broken_alternative_service| as broken until an expiration delay 100 // (determined by how many consecutive times it's been marked broken before). 101 // After the delay, it will be in the recently broken state. However, when the 102 // default network changes, the service will immediately be in the working 103 // state. 104 void MarkBrokenUntilDefaultNetworkChanges( 105 const BrokenAlternativeService& broken_alternative_service); 106 107 // Marks |broken_alternative_service| as broken until an expiration delay 108 // (determined by how many consecutive times it's been marked broken before). 109 // After the delay, it will be in the recently broken state. When the default 110 // network changes, the brokenness state of this service remains unchanged. 111 void MarkBroken(const BrokenAlternativeService& broken_alternative_service); 112 113 // Marks |broken_alternative_service| as recently broken. Being recently 114 // broken will cause WasAlternativeServiceRecentlyBroken(alternative_service, 115 // network_anonymization_key) to return true until 116 // Confirm(alternative_service, network_anonymization_key) is called. 117 void MarkRecentlyBroken( 118 const BrokenAlternativeService& broken_alternative_service); 119 120 // Returns true if the alternative service is considered broken. 121 bool IsBroken( 122 const BrokenAlternativeService& broken_alternative_service) const; 123 124 // If the alternative service is considered broken, returns true and sets 125 // |brokenness_expiration| to the expiration time for that service. 126 // Returns false otherwise. 127 bool IsBroken(const BrokenAlternativeService& broken_alternative_service, 128 base::TimeTicks* brokenness_expiration) const; 129 130 // Returns true if MarkRecentlyBroken(alternative_service) 131 // or MarkBroken(alternative_service) has been called and 132 // Confirm(alternative_service) has not been called 133 // afterwards (even if brokenness of |alternative_service| has expired). 134 bool WasRecentlyBroken( 135 const BrokenAlternativeService& broken_alternative_service); 136 137 // Changes the alternative service to be considered as working. 138 void Confirm(const BrokenAlternativeService& broken_alternative_service); 139 140 // Clears all alternative services which were marked as broken until the 141 // default network changed, those services will now be considered working. 142 // Returns true if there was any broken alternative service affected by this 143 // network change. 144 bool OnDefaultNetworkChanged(); 145 146 // Sets broken and recently broken alternative services. 147 // |broken_alternative_service_list|, |recently_broken_alternative_services| 148 // must not be nullptr. 149 // 150 // If a broken/recently-broken alt svc that's being added is already stored, 151 // the stored expiration/broken-count for that alt svc will be overwritten 152 // with the new value. 153 void SetBrokenAndRecentlyBrokenAlternativeServices( 154 std::unique_ptr<BrokenAlternativeServiceList> 155 broken_alternative_service_list, 156 std::unique_ptr<RecentlyBrokenAlternativeServices> 157 recently_broken_alternative_services); 158 159 // If values are present, sets initial_delay_ and 160 // exponential_backoff_on_initial_delay_ which are used to calculate delay of 161 // broken alternative services. 162 void SetDelayParams(std::optional<base::TimeDelta> initial_delay, 163 std::optional<bool> exponential_backoff_on_initial_delay); 164 165 const BrokenAlternativeServiceList& broken_alternative_service_list() const; 166 167 const RecentlyBrokenAlternativeServices& 168 recently_broken_alternative_services() const; 169 170 private: 171 // TODO (wangyix): modify HttpServerProperties unit tests so this friendness 172 // is no longer required. 173 friend class HttpServerPropertiesPeer; 174 175 struct AlternativeServiceHash { operatorAlternativeServiceHash176 size_t operator()(const net::AlternativeService& entry) const { 177 return entry.protocol ^ std::hash<std::string>()(entry.host) ^ entry.port; 178 } 179 }; 180 181 typedef std::map<BrokenAlternativeService, 182 BrokenAlternativeServiceList::iterator> 183 BrokenMap; 184 185 // Helper method that marks |broken_alternative_service| as broken until 186 // an expiration delay (determined by how many consecutive times it's been 187 // marked broken before). After the delay, it will be in the recently broken 188 // state. 189 void MarkBrokenImpl( 190 const BrokenAlternativeService& broken_alternative_service); 191 192 // Inserts |broken_alternative_service| and its |expiration| time into 193 // |broken_alternative_service_list_| and |broken_alternative_service_map_|. 194 // |it| is the position in |broken_alternative_service_list_| where it was 195 // inserted. 196 bool AddToBrokenListAndMap( 197 const BrokenAlternativeService& broken_alternative_service, 198 base::TimeTicks expiration, 199 BrokenAlternativeServiceList::iterator* it); 200 201 void ExpireBrokenAlternateProtocolMappings(); 202 void ScheduleBrokenAlternateProtocolMappingsExpiration(); 203 204 raw_ptr<Delegate> delegate_; // Unowned 205 raw_ptr<const base::TickClock> clock_; // Unowned 206 207 // List of <broken alt svc, expiration time> pairs sorted by expiration time. 208 BrokenAlternativeServiceList broken_alternative_service_list_; 209 // A map from broken alt-svcs to their iterator pointing to that alt-svc's 210 // position in |broken_alternative_service_list_|. 211 BrokenMap broken_alternative_service_map_; 212 // A set of broken alternative services on the current default 213 // network. This will be cleared every time the default network changes. 214 std::set<BrokenAlternativeService> 215 broken_alternative_services_on_default_network_; 216 217 // Maps broken alternative services to how many times they've been marked 218 // broken. 219 RecentlyBrokenAlternativeServices recently_broken_alternative_services_; 220 221 // Used for scheduling the task that expires the brokenness of alternative 222 // services. 223 base::OneShotTimer expiration_timer_; 224 225 // Delay for the 1st time alternative service is marked broken. 226 base::TimeDelta initial_delay_; 227 228 // If true, the delay for broken alternative service = 229 // initial_delay_for_broken_alternative_service * (1 << broken_count). 230 // Otherwise, the delay would be initial_delay_for_broken_alternative_service, 231 // 5min, 10min.. and so on. 232 bool exponential_backoff_on_initial_delay_ = true; 233 234 base::WeakPtrFactory<BrokenAlternativeServices> weak_ptr_factory_{this}; 235 }; 236 237 } // namespace net 238 239 #endif // NET_HTTP_BROKEN_ALTERNATIVE_SERVICES_H_ 240