• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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_HTTP_STREAM_POOL_H_
6 #define NET_HTTP_HTTP_STREAM_POOL_H_
7 
8 #include <map>
9 #include <memory>
10 #include <set>
11 
12 #include "base/containers/flat_set.h"
13 #include "base/containers/unique_ptr_adapters.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "net/base/completion_once_callback.h"
19 #include "net/base/net_export.h"
20 #include "net/base/network_anonymization_key.h"
21 #include "net/base/network_change_notifier.h"
22 #include "net/base/request_priority.h"
23 #include "net/http/alternative_service.h"
24 #include "net/http/http_stream_pool_request_info.h"
25 #include "net/http/http_stream_request.h"
26 #include "net/socket/next_proto.h"
27 #include "net/socket/ssl_client_socket.h"
28 #include "net/socket/stream_attempt.h"
29 #include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
30 #include "third_party/abseil-cpp/absl/types/variant.h"
31 
32 namespace net {
33 
34 class HttpStreamKey;
35 class HttpNetworkSession;
36 class NetLogWithSource;
37 
38 // Manages in-flight HTTP stream requests and maintains idle stream sockets.
39 // Restricts the number of streams open at a time. HttpStreams are grouped by
40 // HttpStreamKey.
41 //
42 // Currently only supports non-proxy streams.
43 class NET_EXPORT_PRIVATE HttpStreamPool
44     : public NetworkChangeNotifier::IPAddressObserver,
45       public SSLClientContext::Observer {
46  public:
47   // Indicates whether per pool/group limits should be respected or not.
48   enum class RespectLimits {
49     kRespect,
50     kIgnore,
51   };
52 
53   // Represents why a stream socket is closed.
54   // These values are persisted to logs. Entries should not be renumbered and
55   // numeric values should never be reused.
56   //
57   // LINT.IfChange(StreamCloseReason)
58   enum class StreamCloseReason {
59     kUnspecified = 0,
60     kCloseAllConnections = 1,
61     kIpAddressChanged = 2,
62     kSslConfigChanged = 3,
63     kCannotUseTcpBasedProtocols = 4,
64     kSpdySessionCreated = 5,
65     kQuicSessionCreated = 6,
66     kMaxValue = kQuicSessionCreated,
67   };
68   // LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:StreamCloseReason)
69 
70   // Observes events on the HttpStreamPool and may intercept preconnects. Used
71   // only for tests.
72   class NET_EXPORT_PRIVATE TestDelegate {
73    public:
74     virtual ~TestDelegate() = default;
75 
76     // Called when a stream is requested.
77     virtual void OnRequestStream(const HttpStreamKey& stream_key) = 0;
78 
79     // Called when a preconnect is requested. When returns a non-nullopt value,
80     // the preconnect completes with the value.
81     virtual std::optional<int> OnPreconnect(const HttpStreamKey& stream_key,
82                                             size_t num_streams) = 0;
83   };
84 
85   // Reasons for closing streams.
86   static constexpr std::string_view kIpAddressChanged = "IP address changed";
87   static constexpr std::string_view kSslConfigChanged =
88       "SSL configuration changed";
89   static constexpr std::string_view kIdleTimeLimitExpired =
90       "Idle time limit expired";
91   static constexpr std::string_view kSwitchingToHttp2 = "Switching to HTTP/2";
92   static constexpr std::string_view kSwitchingToHttp3 = "Switching to HTTP/3";
93   static constexpr std::string_view kRemoteSideClosedConnection =
94       "Remote side closed connection";
95   static constexpr std::string_view kDataReceivedUnexpectedly =
96       "Data received unexpectedly";
97   static constexpr std::string_view kClosedConnectionReturnedToPool =
98       "Connection was closed when it was returned to the pool";
99   static constexpr std::string_view kSocketGenerationOutOfDate =
100       "Socket generation out of date";
101   static constexpr std::string_view kExceededSocketLimits =
102       "Exceed socket pool/group limits";
103 
104   // The default maximum number of sockets per pool. The same as
105   // ClientSocketPoolManager::max_sockets_per_pool().
106   static constexpr size_t kDefaultMaxStreamSocketsPerPool = 256;
107 
108   // The default maximum number of socket per group. The same as
109   // ClientSocketPoolManager::max_sockets_per_group().
110   static constexpr size_t kDefaultMaxStreamSocketsPerGroup = 6;
111 
112   // FeatureParam names for setting per pool/group limits.
113   static constexpr std::string_view kMaxStreamSocketsPerPoolParamName =
114       "max_stream_per_pool";
115   static constexpr std::string_view kMaxStreamSocketsPerGroupParamName =
116       "max_stream_per_group";
117 
118   // FeatureParam name for enabling consistency checks.
119   static constexpr std::string_view kEnableConsistencyCheckParamName =
120       "enable_consistency_check";
121 
122   // The time to wait between connection attempts.
123   static constexpr base::TimeDelta kConnectionAttemptDelay =
124       base::Milliseconds(250);
125 
126   class NET_EXPORT_PRIVATE Job;
127   class NET_EXPORT_PRIVATE JobController;
128   class NET_EXPORT_PRIVATE Group;
129   class NET_EXPORT_PRIVATE AttemptManager;
130   class NET_EXPORT_PRIVATE QuicTask;
131 
132   explicit HttpStreamPool(HttpNetworkSession* http_network_session,
133                           bool cleanup_on_ip_address_change = true);
134 
135   HttpStreamPool(const HttpStreamPool&) = delete;
136   HttpStreamPool& operator=(const HttpStreamPool&) = delete;
137 
138   ~HttpStreamPool() override;
139 
140   // Called when the owner of `this`, which is an HttpNetworkSession, starts
141   // the process of being destroyed.
142   void OnShuttingDown();
143 
144   // Requests an HttpStream.
145   std::unique_ptr<HttpStreamRequest> RequestStream(
146       HttpStreamRequest::Delegate* delegate,
147       HttpStreamPoolRequestInfo request_info,
148       RequestPriority priority,
149       const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
150       bool enable_ip_based_pooling,
151       bool enable_alternative_services,
152       const NetLogWithSource& net_log);
153 
154   // Requests that enough connections/sessions for `num_streams` be opened.
155   // `callback` is only invoked when the return value is `ERR_IO_PENDING`.
156   int Preconnect(HttpStreamPoolRequestInfo request_info,
157                  size_t num_streams,
158                  CompletionOnceCallback callback);
159 
160   // Increments/Decrements the total number of idle streams in this pool.
161   void IncrementTotalIdleStreamCount();
162   void DecrementTotalIdleStreamCount();
163 
TotalIdleStreamCount()164   size_t TotalIdleStreamCount() { return total_idle_stream_count_; }
165 
166   // Increments/Decrements the total number of active streams this pool handed
167   // out.
168   void IncrementTotalHandedOutStreamCount();
169   void DecrementTotalHandedOutStreamCount();
170 
171   // Increments/Decrements the total number of connecting streams this pool.
172   void IncrementTotalConnectingStreamCount();
173   void DecrementTotalConnectingStreamCount(size_t amount = 1);
174 
TotalConnectingStreamCount()175   size_t TotalConnectingStreamCount() const {
176     return total_connecting_stream_count_;
177   }
178 
TotalActiveStreamCount()179   size_t TotalActiveStreamCount() const {
180     return total_handed_out_stream_count_ + total_idle_stream_count_ +
181            total_connecting_stream_count_;
182   }
183 
184   // Closes all streams in this pool and cancels all pending requests.
185   void FlushWithError(int error,
186                       StreamCloseReason attempt_cancel_reason,
187                       std::string_view net_log_close_reason_utf8);
188 
189   void CloseIdleStreams(std::string_view net_log_close_reason_utf8);
190 
ReachedMaxStreamLimit()191   bool ReachedMaxStreamLimit() const {
192     return TotalActiveStreamCount() >= max_stream_sockets_per_pool();
193   }
194 
195   // Return true if there is a request blocked on this pool.
196   bool IsPoolStalled();
197 
198   // NetworkChangeNotifier::IPAddressObserver methods:
199   void OnIPAddressChanged() override;
200 
201   // SSLClientContext::Observer methods.
202   void OnSSLConfigChanged(
203       SSLClientContext::SSLConfigChangeType change_type) override;
204   void OnSSLConfigForServersChanged(
205       const base::flat_set<HostPortPair>& servers) override;
206 
207   // Called when a group has completed.
208   void OnGroupComplete(Group* group);
209 
210   // Called when a JobController has completed.
211   void OnJobControllerComplete(JobController* job_controller);
212 
213   // Checks if there are any pending requests in groups and processes them. If
214   // `this` reached the maximum number of streams, it will try to close idle
215   // streams before processing pending requests.
216   void ProcessPendingRequestsInGroups();
217 
218   // Returns true when HTTP/1.1 is required for `destination`.
219   bool RequiresHTTP11(const url::SchemeHostPort& destination,
220                       const NetworkAnonymizationKey& network_anonymization_key);
221 
222   // Returns true when QUIC is broken for `destination`.
223   bool IsQuicBroken(const url::SchemeHostPort& destination,
224                     const NetworkAnonymizationKey& network_anonymization_key);
225 
226   // Returns true when QUIC can be used for `destination`.
227   bool CanUseQuic(const url::SchemeHostPort& destination,
228                   const NetworkAnonymizationKey& network_anonymization_key,
229                   bool enable_ip_based_pooling,
230                   bool enable_alternative_services);
231 
232   // Returns the first quic::ParsedQuicVersion that has been advertised in
233   // `alternative_service_info` and is supported, following the order of
234   // `alternative_service_info.advertised_versions()`. Returns
235   // quic::ParsedQuicVersion::Unsupported() when the alternative service is
236   // not QUIC or no mutually supported version is found.
237   quic::ParsedQuicVersion SelectQuicVersion(
238       const AlternativeServiceInfo& alternative_service_info);
239 
240   // Returns true when there is an existing QUIC session for `quic_session_key`.
241   bool CanUseExistingQuicSession(
242       const QuicSessionAliasKey& quic_session_alias_key,
243       bool enable_ip_based_pooling,
244       bool enable_alternative_services);
245 
246   // Retrieves information on the current state of the pool as a base::Value.
247   base::Value::Dict GetInfoAsValue() const;
248 
249   void SetDelegateForTesting(std::unique_ptr<TestDelegate> observer);
250 
251   Group& GetOrCreateGroupForTesting(const HttpStreamKey& stream_key);
252 
253   Group* GetGroupForTesting(const HttpStreamKey& stream_key);
254 
http_network_session()255   HttpNetworkSession* http_network_session() const {
256     return http_network_session_;
257   }
258 
stream_attempt_params()259   const StreamAttemptParams* stream_attempt_params() const {
260     return &stream_attempt_params_;
261   }
262 
max_stream_sockets_per_pool()263   size_t max_stream_sockets_per_pool() const {
264     return max_stream_sockets_per_pool_;
265   }
266 
max_stream_sockets_per_group()267   size_t max_stream_sockets_per_group() const {
268     return max_stream_sockets_per_group_;
269   }
270 
set_max_stream_sockets_per_pool_for_testing(size_t max_stream_sockets_per_pool)271   void set_max_stream_sockets_per_pool_for_testing(
272       size_t max_stream_sockets_per_pool) {
273     max_stream_sockets_per_pool_ = max_stream_sockets_per_pool;
274   }
275 
set_max_stream_sockets_per_group_for_testing(size_t max_stream_sockets_per_group)276   void set_max_stream_sockets_per_group_for_testing(
277       size_t max_stream_sockets_per_group) {
278     max_stream_sockets_per_group_ = max_stream_sockets_per_group;
279   }
280 
JobControllerCountForTesting()281   size_t JobControllerCountForTesting() const {
282     return job_controllers_.size();
283   }
284 
285  private:
286   Group& GetOrCreateGroup(
287       const HttpStreamKey& stream_key,
288       std::optional<QuicSessionAliasKey> quic_session_alias_key = std::nullopt);
289 
290   Group* GetGroup(const HttpStreamKey& stream_key);
291 
292   // Searches for a group that has the highest priority pending request and
293   // hasn't reached reach the `max_stream_socket_per_group()` limit. Returns
294   // nullptr if no such group is found.
295   Group* FindHighestStalledGroup();
296 
297   // Closes one idle stream from an arbitrary group. Returns true if it closed a
298   // stream.
299   bool CloseOneIdleStreamSocket();
300 
301   base::WeakPtr<SpdySession> FindAvailableSpdySession(
302       const HttpStreamKey& stream_key,
303       const SpdySessionKey& spdy_session_key,
304       bool enable_ip_based_pooling,
305       const NetLogWithSource& net_log = NetLogWithSource());
306 
307   void OnPreconnectComplete(JobController* job_controller,
308                             CompletionOnceCallback callback,
309                             int rv);
310 
311   // Periodically checks the total active/idle/handed-out streams are consistent
312   // with per-group streams. Only used when the kEnableConsistencyCheckParamName
313   // FeatureParam is enabled.
314   // TODO(crbug.com/346835898): Remove this when we stabilize the
315   // implementation.
316   void CheckConsistency();
317 
318   const raw_ptr<HttpNetworkSession> http_network_session_;
319 
320   // Set to true when this is in the process of being destructed. When true,
321   // don't process pending requests.
322   bool is_shutting_down_ = false;
323 
324   const StreamAttemptParams stream_attempt_params_;
325 
326   const bool cleanup_on_ip_address_change_;
327 
328   const NetLogWithSource net_log_;
329 
330   size_t max_stream_sockets_per_pool_;
331   size_t max_stream_sockets_per_group_;
332 
333   // The total number of active streams this pool handed out across all groups.
334   size_t total_handed_out_stream_count_ = 0;
335 
336   // The total number of idle streams in this pool.
337   size_t total_idle_stream_count_ = 0;
338 
339   // The total number of connecting streams in this pool.
340   size_t total_connecting_stream_count_ = 0;
341 
342   std::map<HttpStreamKey, std::unique_ptr<Group>> groups_;
343 
344   std::set<std::unique_ptr<JobController>, base::UniquePtrComparator>
345       job_controllers_;
346 
347   std::unique_ptr<TestDelegate> delegate_for_testing_;
348 
349   base::WeakPtrFactory<HttpStreamPool> weak_ptr_factory_{this};
350 };
351 
352 }  // namespace net
353 
354 #endif  // NET_HTTP_HTTP_STREAM_POOL_H_
355