• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
163       absl::optional<base::TimeDelta> initial_delay,
164       absl::optional<bool> exponential_backoff_on_initial_delay);
165 
166   const BrokenAlternativeServiceList& broken_alternative_service_list() const;
167 
168   const RecentlyBrokenAlternativeServices&
169   recently_broken_alternative_services() const;
170 
171  private:
172   // TODO (wangyix): modify HttpServerProperties unit tests so this friendness
173   // is no longer required.
174   friend class HttpServerPropertiesPeer;
175 
176   struct AlternativeServiceHash {
operatorAlternativeServiceHash177     size_t operator()(const net::AlternativeService& entry) const {
178       return entry.protocol ^ std::hash<std::string>()(entry.host) ^ entry.port;
179     }
180   };
181 
182   typedef std::map<BrokenAlternativeService,
183                    BrokenAlternativeServiceList::iterator>
184       BrokenMap;
185 
186   // Helper method that marks |broken_alternative_service| as broken until
187   // an expiration delay (determined by how many consecutive times it's been
188   // marked broken before). After the delay, it will be in the recently broken
189   // state.
190   void MarkBrokenImpl(
191       const BrokenAlternativeService& broken_alternative_service);
192 
193   // Inserts |broken_alternative_service| and its |expiration| time into
194   // |broken_alternative_service_list_| and |broken_alternative_service_map_|.
195   // |it| is the position in |broken_alternative_service_list_| where it was
196   // inserted.
197   bool AddToBrokenListAndMap(
198       const BrokenAlternativeService& broken_alternative_service,
199       base::TimeTicks expiration,
200       BrokenAlternativeServiceList::iterator* it);
201 
202   void ExpireBrokenAlternateProtocolMappings();
203   void ScheduleBrokenAlternateProtocolMappingsExpiration();
204 
205   raw_ptr<Delegate> delegate_;            // Unowned
206   raw_ptr<const base::TickClock> clock_;  // Unowned
207 
208   // List of <broken alt svc, expiration time> pairs sorted by expiration time.
209   BrokenAlternativeServiceList broken_alternative_service_list_;
210   // A map from broken alt-svcs to their iterator pointing to that alt-svc's
211   // position in |broken_alternative_service_list_|.
212   BrokenMap broken_alternative_service_map_;
213   // A set of broken alternative services on the current default
214   // network. This will be cleared every time the default network changes.
215   std::set<BrokenAlternativeService>
216       broken_alternative_services_on_default_network_;
217 
218   // Maps broken alternative services to how many times they've been marked
219   // broken.
220   RecentlyBrokenAlternativeServices recently_broken_alternative_services_;
221 
222   // Used for scheduling the task that expires the brokenness of alternative
223   // services.
224   base::OneShotTimer expiration_timer_;
225 
226   // Delay for the 1st time alternative service is marked broken.
227   base::TimeDelta initial_delay_;
228 
229   // If true, the delay for broken alternative service =
230   // initial_delay_for_broken_alternative_service * (1 << broken_count).
231   // Otherwise, the delay would be initial_delay_for_broken_alternative_service,
232   // 5min, 10min.. and so on.
233   bool exponential_backoff_on_initial_delay_ = true;
234 
235   base::WeakPtrFactory<BrokenAlternativeServices> weak_ptr_factory_{this};
236 };
237 
238 }  // namespace net
239 
240 #endif  // NET_HTTP_BROKEN_ALTERNATIVE_SERVICES_H_
241