xref: /aosp_15_r20/external/cronet/net/http/broken_alternative_services.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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