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 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_HTTP_HTTP_STREAM_POOL_GROUP_H_
#define NET_HTTP_HTTP_STREAM_POOL_GROUP_H_
#include <list>
#include <memory>
#include <string_view>
#include <vector>
#include "base/containers/unique_ptr_adapters.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "net/base/load_timing_info.h"
#include "net/base/net_export.h"
#include "net/http/http_stream_key.h"
#include "net/http/http_stream_pool.h"
#include "net/http/http_stream_pool_job.h"
#include "net/http/http_stream_request.h"
#include "net/quic/quic_session_alias_key.h"
#include "net/socket/stream_socket_close_reason.h"
#include "net/socket/stream_socket_handle.h"
#include "net/spdy/spdy_session_key.h"
#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
#include "url/scheme_host_port.h"
namespace net {
class HttpNetworkSession;
class HttpStream;
class HttpStreamPoolHandle;
class StreamSocket;
// Maintains active/idle text-based HTTP streams. If new streams are needed,
// creates an HttpStreamPool::AttemptManager and starts connection attempts for
// streams.
//
// When an active AttemptManager starts shutting down (e.g. the AttemptManager
// fails), creates a new AttemptManager for subsequent stream requests (Jobs).
// AttemptManagers need to outlive all associated Jobs. Keeps shutting down
// AttemptManager(s) until these are ready to destroy.
//
// Owned by an HttpStreamPool, keyed by HttpStreamKey. Destroyed when all
// streams associated with this group are completed.
class HttpStreamPool::Group {
public:
// The same timeout as ClientSocketPool::used_idle_socket_timeout().
static constexpr base::TimeDelta kUsedIdleStreamSocketTimeout =
base::Seconds(300);
// The same timeout as
// ClientSocketPoolManager::unused_idle_socket_timeout().
static constexpr base::TimeDelta kUnusedIdleStreamSocketTimeout =
base::Seconds(60);
Group(HttpStreamPool* pool,
HttpStreamKey stream_key,
std::optional<QuicSessionAliasKey> quic_session_alias_key);
Group(const Group&) = delete;
Group& operator=(const Group&) = delete;
~Group();
const HttpStreamKey& stream_key() const { return stream_key_; }
const SpdySessionKey& spdy_session_key() const { return spdy_session_key_; }
const QuicSessionAliasKey& quic_session_alias_key() const {
return quic_session_alias_key_;
}
HttpStreamPool* pool() { return pool_; }
const HttpStreamPool* pool() const { return pool_; }
HttpNetworkSession* http_network_session() const {
return pool_->http_network_session();
}
// TODO(crbug.com/416088643): Rename to `active_attempt_manager()`.
AttemptManager* attempt_manager() const { return attempt_manager_.get(); }
size_t ShuttingDownAttemptManagerCount() const {
return shutting_down_attempt_managers_.size();
}
const NetLogWithSource& net_log() { return net_log_; }
bool force_quic() const { return force_quic_; }
// Creates a Job to attempt connection(s). We have separate methods for
// creating and starting a Job to ensure that the owner of the Job can
// properly manage the lifetime of the Job, even when StartJob() synchronously
// calls one of the delegate's methods.
std::unique_ptr<Job> CreateJob(Job::Delegate* delegate,
quic::ParsedQuicVersion quic_version,
NextProto expected_protocol,
const NetLogWithSource& request_net_log);
// Called when `job` is going to be destroyed.
void OnJobComplete(Job* job);
// Creates an HttpStreamPoolHandle from `socket`. Call sites must ensure that
// the number of active streams do not exceed the global/per-group limits.
std::unique_ptr<HttpStreamPoolHandle> CreateHandle(
std::unique_ptr<StreamSocket> socket,
StreamSocketHandle::SocketReuseType reuse_type,
LoadTimingInfo::ConnectTiming connect_timing);
// Creates a text-based HttpStream from `socket`. Call sites must ensure that
// the number of active streams do not exceed the global/per-group limits.
// `socket` must not be negotiated to use HTTP/2.
std::unique_ptr<HttpStream> CreateTextBasedStream(
std::unique_ptr<StreamSocket> socket,
StreamSocketHandle::SocketReuseType reuse_type,
LoadTimingInfo::ConnectTiming connect_timing);
// Releases a StreamSocket that was used to create a text-based HttpStream.
void ReleaseStreamSocket(std::unique_ptr<StreamSocket> socket,
int64_t generation);
// Adds `socket` as an idle StreamSocket for text-based HttpStream. Call sites
// must ensure that the number of idle streams do not exceed the global/per-
// group limits.
// `socket` must not be negotiated to use HTTP/2.
void AddIdleStreamSocket(std::unique_ptr<StreamSocket> socket);
// Retrieves an existing idle StreamSocket. Returns nullptr when there is no
// idle stream.
std::unique_ptr<StreamSocket> GetIdleStreamSocket();
// Tries to process a pending request.
void ProcessPendingRequest();
// Closes one idle stream socket. Returns true if it closed a stream. Called
// when the pool reached the stream count limit.
bool CloseOneIdleStreamSocket();
// Returns the number of handed out streams.
size_t HandedOutStreamSocketCount() const { return handed_out_stream_count_; }
// Returns the number of idle streams.
size_t IdleStreamSocketCount() const { return idle_stream_sockets_.size(); }
// Returns the number of connecting streams.
size_t ConnectingStreamSocketCount() const;
// Returns the number of active streams.
size_t ActiveStreamSocketCount() const;
// True when the number of active streams reached the group limit.
bool ReachedMaxStreamLimit() const;
// Returns the highest pending request priority if the group is stalled due to
// the per-pool limit, not the per-group limit.
std::optional<RequestPriority> GetPriorityIfStalledByPoolLimit() const;
// Closes all streams in this group and cancels all pending requests.
void FlushWithError(int error,
StreamSocketCloseReason attempt_cancel_reason,
std::string_view net_log_close_reason_utf8);
// Increments the generation of this group. Closes idle streams. Streams
// handed out before this increment won't be reused. Cancels in-flight
// connection attempts.
void Refresh(std::string_view net_log_close_reason_utf8,
StreamSocketCloseReason cancel_reason);
void CloseIdleStreams(std::string_view net_log_close_reason_utf8);
// Cancels all on-going jobs.
void CancelJobs(int error);
// Create an AttemptManager if needed.
AttemptManager* EnsureAttemptManager();
// Called when the active AttemptManager is shutting down.
void OnAttemptManagerShuttingDown(AttemptManager* attempt_manager);
// Called when an AttemptManager has completed.
void OnAttemptManagerComplete(AttemptManager* attempt_manager);
// Retrieves information on the current state of the group as a base::Value.
base::Value::Dict GetInfoAsValue() const;
// Returns true when `this` can be deleted.
// TODO(crbug.com/346835898): This is public for consistency checks. Make this
// private once we stabilize the implementation.
bool CanComplete() const;
void CleanupTimedoutIdleStreamSocketsForTesting();
private:
FRIEND_TEST_ALL_PREFIXES(HttpStreamPoolGroupTest, ComparePausedJobSet);
struct IdleStreamSocket {
IdleStreamSocket(std::unique_ptr<StreamSocket> stream_socket,
base::TimeTicks start_time);
~IdleStreamSocket();
IdleStreamSocket(const IdleStreamSocket&) = delete;
IdleStreamSocket& operator=(const IdleStreamSocket&) = delete;
std::unique_ptr<StreamSocket> stream_socket;
base::TimeTicks time_became_idle;
};
enum class CleanupMode {
// Clean up only timed out idle streams.
kTimeoutOnly,
// Clean up all idle streams.
kForce,
};
static base::expected<void, std::string_view> IsIdleStreamSocketUsable(
const IdleStreamSocket& idle);
void CleanupIdleStreamSockets(CleanupMode mode,
std::string_view net_log_close_reason_utf8);
void MaybeComplete();
// Posts a task to call MaybeComplete() later.
void MaybeCompleteLater();
const raw_ptr<HttpStreamPool> pool_;
const HttpStreamKey stream_key_;
const SpdySessionKey spdy_session_key_;
const QuicSessionAliasKey quic_session_alias_key_;
const NetLogWithSource net_log_;
const bool force_quic_;
size_t handed_out_stream_count_ = 0;
int64_t generation_ = 0;
std::list<IdleStreamSocket> idle_stream_sockets_;
std::unique_ptr<AttemptManager> attempt_manager_;
// Keeps AttemptManagers that are shutting down.
std::set<std::unique_ptr<AttemptManager>, base::UniquePtrComparator>
shutting_down_attempt_managers_;
base::WeakPtrFactory<Group> weak_ptr_factory_{this};
};
} // namespace net
#endif // NET_HTTP_HTTP_STREAM_POOL_GROUP_H_
|