summaryrefslogtreecommitdiff
path: root/chromium/services/network/websocket_throttler.h
blob: 0226aacce0c9eb4bdeab5760799dc26de0154901 (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
// Copyright 2018 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 SERVICES_NETWORK_WEBSOCKET_THROTTLER_H_
#define SERVICES_NETWORK_WEBSOCKET_THROTTLER_H_

#include <stdint.h>
#include <map>
#include <memory>

#include "base/component_export.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "base/timer/timer.h"

namespace network {

// WebSocketPerProcessThrottler provies a throttling functionality per
// renderer process. See https://goo.gl/tldFNn.
class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocketPerProcessThrottler final {
 public:
  // A PendingConnection represents a connection that has not finished a
  // handshake.
  //
  // Destroying a PendingConnection whose OnCompleteHandshake has not been
  // called represents a handshake failure (including going away during
  // handshake).
  class COMPONENT_EXPORT(NETWORK_SERVICE) PendingConnection final {
   public:
    // |throttler| cannot be null.
    explicit PendingConnection(
        base::WeakPtr<WebSocketPerProcessThrottler> throttler);
    PendingConnection(PendingConnection&& other);
    ~PendingConnection();

    // Called when the hansdhake finishes sucessfully.
    void OnCompleteHandshake();

   private:
    base::WeakPtr<WebSocketPerProcessThrottler> throttler_;

    DISALLOW_COPY_AND_ASSIGN(PendingConnection);
  };

  WebSocketPerProcessThrottler();
  ~WebSocketPerProcessThrottler();

  // Returns if there are too many pending connections.
  bool HasTooManyPendingConnections() const {
    return num_pending_connections_ >= kMaxPendingWebSocketConnections;
  }

  // Returns the delay which should be used to throttle opening websocket
  // connections.
  base::TimeDelta CalculateDelay() const;

  // Issues an object which represents a pending connection.
  PendingConnection IssuePendingConnectionTracker();

  // Returns true if this throttler is clean, i.e., we can restore the internal
  // state by simply creating a new object.
  bool IsClean() const;

  // Copies the succeeded / failed counters for the current period to the
  // ones for the previous period, and zeroes them.
  void Roll();

  int64_t num_pending_connections() const { return num_pending_connections_; }
  int64_t num_current_succeeded_connections() const {
    return num_current_succeeded_connections_;
  }
  int64_t num_previous_succeeded_connections() const {
    return num_previous_succeeded_connections_;
  }
  int64_t num_current_failed_connections() const {
    return num_current_failed_connections_;
  }
  int64_t num_previous_failed_connections() const {
    return num_previous_failed_connections_;
  }

 private:
  // The current number of pending connections.
  int num_pending_connections_ = 0;

  // The number of handshakes that failed in the clurrent and previous time
  // period.
  int64_t num_current_succeeded_connections_ = 0;
  int64_t num_previous_succeeded_connections_ = 0;

  // The number of handshakes that succeeded in the current and previous time
  // period.
  int64_t num_current_failed_connections_ = 0;
  int64_t num_previous_failed_connections_ = 0;

  static constexpr int kMaxPendingWebSocketConnections = 255;

  base::WeakPtrFactory<WebSocketPerProcessThrottler> weak_factory_{this};

  DISALLOW_COPY_AND_ASSIGN(WebSocketPerProcessThrottler);
};

// This class is for throttling WebSocket connections. WebSocketThrottler is
// a set of per-renderer throttlers.
class COMPONENT_EXPORT(NETWORK_SERVICE) WebSocketThrottler final {
 public:
  using PendingConnection = WebSocketPerProcessThrottler::PendingConnection;

  WebSocketThrottler();
  ~WebSocketThrottler();

  // Returns true if there are too many pending connections for |process_id|.
  bool HasTooManyPendingConnections(int process_id) const;

  // Calculates connection delay for |process_id|.
  base::TimeDelta CalculateDelay(int process_id) const;

  // Returns a pending connection for |process_id|. This function can be called
  // only when |HasTooManyPendingConnections(process_id)| is false. May return
  // |base::nullopt| if |process_id| is not throttled.
  base::Optional<PendingConnection> IssuePendingConnectionTracker(
      int process_id);

  size_t GetSizeForTesting() const { return per_process_throttlers_.size(); }

 private:
  void OnTimer();

  std::map<int, std::unique_ptr<WebSocketPerProcessThrottler>>
      per_process_throttlers_;
  base::RepeatingTimer throttling_period_timer_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketThrottler);
};

}  // namespace network

#endif  // SERVICES_NETWORK_WEBSOCKET_THROTTLER_H_