summaryrefslogtreecommitdiffstats
path: root/net/url_request/url_request_throttler_entry.h
blob: 88ceb084854f8dbd67cc6114955c4c082d2bf4bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_URL_REQUEST_URL_REQUEST_THROTTLER_ENTRY_H_
#define NET_URL_REQUEST_URL_REQUEST_THROTTLER_ENTRY_H_
#pragma once

#include <queue>
#include <string>

#include "base/basictypes.h"
#include "net/base/backoff_entry.h"
#include "net/url_request/url_request_throttler_entry_interface.h"

namespace net {

class URLRequestThrottlerManager;

// URLRequestThrottlerEntry represents an entry of URLRequestThrottlerManager.
// It analyzes requests of a specific URL over some period of time, in order to
// deduce the back-off time for every request.
// The back-off algorithm consists of two parts. Firstly, exponential back-off
// is used when receiving 5XX server errors or malformed response bodies.
// The exponential back-off rule is enforced by URLRequestHttpJob. Any
// request sent during the back-off period will be cancelled.
// Secondly, a sliding window is used to count recent requests to a given
// destination and provide guidance (to the application level only) on whether
// too many requests have been sent and when a good time to send the next one
// would be. This is never used to deny requests at the network level.
class URLRequestThrottlerEntry : public URLRequestThrottlerEntryInterface {
 public:
  // Sliding window period.
  static const int kDefaultSlidingWindowPeriodMs;

  // Maximum number of requests allowed in sliding window period.
  static const int kDefaultMaxSendThreshold;

  // Number of initial errors to ignore before starting exponential back-off.
  static const int kDefaultNumErrorsToIgnore;

  // Initial delay for exponential back-off.
  static const int kDefaultInitialBackoffMs;

  // Factor by which the waiting time will be multiplied.
  static const double kDefaultMultiplyFactor;

  // Fuzzing percentage. ex: 10% will spread requests randomly
  // between 90%-100% of the calculated time.
  static const double kDefaultJitterFactor;

  // Maximum amount of time we are willing to delay our request.
  static const int kDefaultMaximumBackoffMs;

  // Time after which the entry is considered outdated.
  static const int kDefaultEntryLifetimeMs;

  // Name of the header that servers can use to ask clients to delay their
  // next request.
  static const char kRetryHeaderName[];

  // Name of the header that sites can use to opt out of exponential back-off
  // throttling.
  static const char kExponentialThrottlingHeader[];

  // Value for exponential throttling header that can be used to opt out of
  // exponential back-off throttling.
  static const char kExponentialThrottlingDisableValue[];

  // The manager object's lifetime must enclose the lifetime of this object.
  explicit URLRequestThrottlerEntry(URLRequestThrottlerManager* manager);

  // The life span of instances created with this constructor is set to
  // infinite, and the number of initial errors to ignore is set to 0.
  // It is only used by unit tests.
  URLRequestThrottlerEntry(URLRequestThrottlerManager* manager,
                           int sliding_window_period_ms,
                           int max_send_threshold,
                           int initial_backoff_ms,
                           double multiply_factor,
                           double jitter_factor,
                           int maximum_backoff_ms);

  // Used by the manager, returns true if the entry needs to be garbage
  // collected.
  bool IsEntryOutdated() const;

  // Causes this entry to never reject requests due to back-off.
  void DisableBackoffThrottling();

  // Causes this entry to NULL its manager pointer.
  void DetachManager();

  // Implementation of URLRequestThrottlerEntryInterface.
  virtual bool IsDuringExponentialBackoff() const;
  virtual int64 ReserveSendingTimeForNextRequest(
      const base::TimeTicks& earliest_time);
  virtual base::TimeTicks GetExponentialBackoffReleaseTime() const;
  virtual void UpdateWithResponse(
      const std::string& host,
      const URLRequestThrottlerHeaderInterface* response);
  virtual void ReceivedContentWasMalformed();

 protected:
  virtual ~URLRequestThrottlerEntry();

  void Initialize();

  // Equivalent to TimeTicks::Now(), virtual to be mockable for testing purpose.
  virtual base::TimeTicks GetTimeNow() const;

  // Used internally to increase release time following a retry-after header.
  void HandleCustomRetryAfter(const std::string& header_value);

  // Used internally to handle the opt-out header.
  void HandleThrottlingHeader(const std::string& header_value,
                              const std::string& host);

  // Retrieves the back-off entry object we're using. Used to enable a
  // unit testing seam for dependency injection in tests.
  virtual const BackoffEntry* GetBackoffEntry() const;
  virtual BackoffEntry* GetBackoffEntry();

  // Used by tests.
  base::TimeTicks sliding_window_release_time() const {
    return sliding_window_release_time_;
  }

  // Used by tests.
  void set_sliding_window_release_time(const base::TimeTicks& release_time) {
    sliding_window_release_time_ = release_time;
  }

  // Valid and immutable after construction time.
  BackoffEntry::Policy backoff_policy_;

 private:
  // Timestamp calculated by the sliding window algorithm for when we advise
  // clients the next request should be made, at the earliest. Advisory only,
  // not used to deny requests.
  base::TimeTicks sliding_window_release_time_;

  // A list of the recent send events. We use them to decide whether there are
  // too many requests sent in sliding window.
  std::queue<base::TimeTicks> send_log_;

  const base::TimeDelta sliding_window_period_;
  const int max_send_threshold_;

  // True if DisableBackoffThrottling() has been called on this object.
  bool is_backoff_disabled_;

  // Access it through GetBackoffEntry() to allow a unit test seam.
  BackoffEntry backoff_entry_;

  // Weak back-reference to the manager object managing us.
  URLRequestThrottlerManager* manager_;

  DISALLOW_COPY_AND_ASSIGN(URLRequestThrottlerEntry);
};

}  // namespace net

#endif  // NET_URL_REQUEST_URL_REQUEST_THROTTLER_ENTRY_H_