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