下午六点多是什么时辰| 什么是伪娘| 柜姐是什么意思| 北京佑安医院擅长什么| 烤油边是什么| 蜻蜓点水是什么行为| 怀孕什么时候能测出来| 前羽念什么| 回执单是什么| 左眼皮跳是什么预兆| pt是什么单位| 腰膝酸软是什么症状| 心脏传导阻滞吃什么药| 什么猫好看| 夜猫子是什么意思| 酩酊是什么意思| 骨头属于什么垃圾| 脸部神经跳动吃什么药| 化干戈为玉帛是什么意思| 宝宝头爱出汗是什么原因| 九月十三号是什么星座| 五月七日是什么星座| 乙型肝炎核心抗体阳性是什么意思| 症结是什么意思| 银子为什么会变黑| 杏花什么季节开| 幽门螺旋杆菌吃什么药最好| 维生素c主治什么| 窥视是什么意思| 孝是什么| 工伤是什么意思| 肠胃感冒吃什么药最好| 吃什么可以生精最快| 硒片什么牌子好| 脑垂体在什么位置图片| 上海有什么好玩的地方旅游景点| 黄晓明和杨颖什么时候结婚的| 牙齿总是出血是什么原因| 知了猴有什么营养| 微博是什么意思| 怀孕十天左右有什么反应| 停车坐爱枫林晚的坐是什么意思| 痰栓是什么| 抑郁症挂什么科| 一失足成千古恨是什么意思| 屈打成招是什么意思| 莳字五行属什么| 脚心起水泡是什么病症| 迁坟有什么讲究和忌讳| 梦见炒菜是什么意思| 巾帼不让须眉是什么意思| 喉咙发炎吃什么水果好| 梦见吃饭是什么预兆| 桉字五行属什么| 石榴石一般什么价位| 电势是什么| 西瓜什么时候种植| 凌晨4点是什么时辰| 梦见别人搬家预示什么| 77属什么生肖| 三大产能营养素是什么| 红颜知己是什么| 象是什么结构| 什么什么有力| 吃大枣有什么好处| 脚底板痛什么原因| 男性尿道刺痛吃什么药| 亚马逊是什么| 脸上长痘挂什么科| 月经血量少是什么原因| 宝宝流鼻涕吃什么药| 伴手礼是什么| 你的脚步流浪在天涯是什么歌曲| 什么是静脉血栓| 做爱什么感觉| 焦糖色搭配什么颜色好看| 孕检nt主要检查什么| 血沉高是什么病| 常吃生花生有什么好处| 站姐是什么意思| 自慰什么意思| 阑尾炎可以吃什么水果| 宾格是什么| 为什么会牙痛| 周岁是什么意思| 用盐泡脚有什么好处| 皮肤容易过敏是什么原因| 病毒感染会有什么症状| 爵迹小说为什么不写了| 烧心是什么症状| 肾虚型脱发是什么样子| 春雨绵绵是什么生肖| 粘液阳性是什么意思| happy halloween是什么意思| 孙悟空叫什么名字| 新生儿一直哭闹是什么原因| 肌肉跳动是什么原因| 阁楼是什么意思| 淋巴细胞升高说明什么| 甲钴胺治什么病| 尿是红色的是什么原因| 手臂长痘痘是什么原因| 拉尿分叉是什么原因| 7777什么意思| 两票制指的是什么| 什么水果利尿效果最好| 维生素c是补什么的| 支付宝账号是什么| silk什么意思| 虎配什么生肖最好| 手指发痒是什么原因| ckd3期是什么意思| 大校是什么级别| 门牙旁边的牙齿叫什么| 青光眼是什么意思| 我们到底什么关系| 这叫什么| 张柏芝和谢霆锋为什么离婚| 白居易有什么之称| 女人脸色发黄吃什么补得最快| 打喷嚏是什么意思| 肛裂用什么药膏| 润月是什么意思| 48岁属什么| 白带豆腐渣用什么药| 安徽有什么土特产| 5月24日是什么星座| 口苦口干是什么原因引起的| 一夜白头是什么原因| 香草是什么| zv是什么品牌| 皮是什么结构| 胸导联低电压什么意思| 汗臭和狐臭有什么区别怎么辨别| 女孩名字带什么字好听| 为什么时间越来越快| 尿道炎吃什么药好得快| 中国最大的岛屿是什么| 多种维生素什么时候吃效果最好| 岗位性质指的是什么| 心肾两虚吃什么中成药| ak是什么意思| 嘴唇薄的男人面相代表什么意味| 狗代表什么数字| 散光是什么原因导致的| 黄菡和黄澜什么关系| 感冒发烧吃什么好| 宋字五行属什么| 298什么意思| 五月十日是什么星座| 术后引流管什么时间可以拔| 政法委是干什么的| 眉茶属于什么茶| 麻是什么植物| 狼吞虎咽是什么生肖| 移花接木的意思是什么| halloween是什么意思| 胃肠感冒什么症状| 脊椎和脊柱有什么区别| 眼睛红痒用什么眼药水| marisfrolg是什么牌子| 日进斗金是什么意思| 阅人无数什么意思| 阎维文什么军衔| 盆腔炎做什么检查| 鸡蛋壳薄是什么原因| kda是什么意思| 各位同仁用在什么场合| 罗姓男孩取什么名字好| 木指什么生肖| 两手发麻是什么原因| 嘴唇干燥是什么原因引起的| 属蛇和什么属相相冲| 什么行业最赚钱投资小| 做b超前需要注意什么| 33代表什么意思| 发量少适合什么发型| 股癣用什么药膏好得快| 双侧骶髂关节致密性骨炎是什么病| 接吻要注意什么| 脑缺血吃什么药| 脚气用什么| 省亲是什么意思| 母猫怀孕有什么症状| 丹参是什么样子| 喉咙痛可以吃什么水果| 眉州东坡是什么菜系| rock是什么意思| 喝绿茶对身体有什么好处| 北京有什么| 灰指甲有什么特效药可以治好| 舐犊是什么意思| 发烧吃什么药| 评头论足什么意思| 吴亦凡帅到什么程度| 嘴唇上长痘是什么原因| 物理学是什么| 包皮长挂什么科| 女性安全期是什么时候| 什么的花瓣| 产后42天复查挂什么科| 正觉是什么意思| 觉的部首是什么偏旁| 天王表属于什么档次| 为什么水能灭火| 智齿不拔有什么危害| 指甲软是什么原因| 甲亢什么不能吃| 鼻梁歪的男人说明什么| 国民党为什么会失败| 血液感染是什么病严重吗| 去医院检查是否怀孕挂什么科| 梗犬是什么意思| 梦见被狗追是什么意思| 什么是葡萄胎| 澳大利亚属于什么洲| 九秩是什么意思| 改编是什么意思| 喉咙有痰吐出来有血是什么原因| 心脏肿大是什么原因| 手足口病什么症状| 单飞是什么意思| 南京都有什么大学| 保持器是什么| 病案号是什么| 什么掌不能拍| 对酒当歌是什么生肖| 吃杏仁有什么好处| 什么原因导致阴虚| 血脂稠吃什么药最好| 小腿前侧肌肉叫什么| 执子之手与子偕老是什么意思| 哆啦a梦的寓意是什么| 唇红是什么原因| 业火是什么意思| 什么东西降火| 鸡胗是什么部位| 聚焦是什么意思| 阿贝数是什么意思| 外阴病变有什么症状| 小便解不出来是什么原因| 腹泻吃什么消炎药| 有什么笑话| 蒸鱼豉油是什么| 中间细胞百分比偏高是什么意思| 正规医院减肥挂什么科| 它是什么结构| 什么属于包皮过长| 什么都不怕| 三唑仑是什么药| 越南人说什么语言| 腱鞘炎是什么引起的| 什么叫青光眼| 为什么晚上不能扫地| 艾滋病有什么症状| 舛是什么意思| 眼底出血有什么症状| 视力突然模糊是什么原因引起的| 脸痒痒是什么原因| 泡饭为什么对胃不好| 250是什么意思| 黄花菜都凉了什么意思| 球蛋白偏高说明什么| 关节由什么组成| 百度
blob: 798e377352a28354d1cf42c374835a85e3bebab6 [file] [log] [blame]
// 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.
#include "net/http/http_stream_pool.h"
#include <algorithm>
#include <map>
#include <memory>
#include <ostream>
#include <set>
#include <string>
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial_params.h"
#include "base/notreached.h"
#include "base/task/sequenced_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "net/base/completion_once_callback.h"
#include "net/base/features.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
#include "net/base/network_anonymization_key.h"
#include "net/base/network_change_notifier.h"
#include "net/base/proxy_chain.h"
#include "net/base/request_priority.h"
#include "net/base/session_usage.h"
#include "net/http/alternative_service.h"
#include "net/http/http_network_session.h"
#include "net/http/http_stream_key.h"
#include "net/http/http_stream_pool_group.h"
#include "net/http/http_stream_pool_job_controller.h"
#include "net/http/http_stream_request.h"
#include "net/log/net_log_with_source.h"
#include "net/quic/quic_session_pool.h"
#include "net/socket/next_proto.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/stream_socket_close_reason.h"
#include "net/spdy/spdy_session.h"
#include "net/third_party/quiche/src/quiche/quic/core/quic_versions.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
namespace net {
namespace {
// Specifies how to handle unexpected states.
// TODO(crbug.com/346835898): Remove this when we stabilize the implementation.
enum class CheckConsistencyMode {
// Disable consistency checks.
kDisabled = 0,
// Logging only.
kLogging = 1,
// Use (D)CHECKs in addition to logging.
kStrict = 2,
};
constexpr base::FeatureParam<size_t> kHttpStreamPoolMaxStreamPerPool{
&features::kHappyEyeballsV3,
HttpStreamPool::kMaxStreamSocketsPerPoolParamName.data(),
HttpStreamPool::kDefaultMaxStreamSocketsPerPool};
constexpr base::FeatureParam<size_t> kHttpStreamPoolMaxStreamPerGroup{
&features::kHappyEyeballsV3,
HttpStreamPool::kMaxStreamSocketsPerGroupParamName.data(),
HttpStreamPool::kDefaultMaxStreamSocketsPerGroup};
constexpr base::FeatureParam<base::TimeDelta>
kHttpStreamPoolConnectionAttemptDelay{
&features::kHappyEyeballsV3,
HttpStreamPool::kConnectionAttemptDelayParamName.data(),
HttpStreamPool::kDefaultConnectionAttemptDelay};
constexpr base::FeatureParam<HttpStreamPool::TcpBasedAttemptDelayBehavior>
kTcpBasedAttemptDelayBehavior{
&features::kHappyEyeballsV3,
HttpStreamPool::kTcpBasedAttemptDelayBehaviorParamName.data(),
HttpStreamPool::TcpBasedAttemptDelayBehavior::
kStartTimerOnFirstQuicAttempt,
HttpStreamPool::kTcpBasedAttemptDelayBehaviorOptions};
constexpr base::FeatureParam<bool> kVerboseNetLog{
&features::kHappyEyeballsV3, HttpStreamPool::kVerboseNetLogParamName.data(),
false};
constexpr base::FeatureParam<CheckConsistencyMode>::Option
kCheckConsistencyModeOptions[] = {
{CheckConsistencyMode::kDisabled, "disabled"},
{CheckConsistencyMode::kLogging, "logging"},
{CheckConsistencyMode::kStrict, "strict"}};
constexpr base::FeatureParam<CheckConsistencyMode> kConsistencyCheck{
&features::kHappyEyeballsV3,
HttpStreamPool::kConsistencyCheckParamName.data(),
CheckConsistencyMode::kDisabled, &kCheckConsistencyModeOptions};
// Represents total stream counts in the pool. Only used for consistency check.
struct StreamCounts {
size_t handed_out = 0;
size_t idle = 0;
size_t connecting = 0;
auto operator<=>(const StreamCounts&) const = default;
base::Value::Dict ToValue() const {
base::Value::Dict dict;
dict.Set("handed_out", static_cast<int>(handed_out));
dict.Set("idle", static_cast<int>(idle));
dict.Set("connecting", static_cast<int>(connecting));
return dict;
}
};
std::ostream& operator<<(std::ostream& os, const StreamCounts& counts) {
return os << "{ handed_out: " << counts.handed_out
<< ", idle: " << counts.idle
<< ", connecting: " << counts.connecting << " }";
}
} // namespace
// static
base::TimeDelta HttpStreamPool::GetConnectionAttemptDelay() {
return kHttpStreamPoolConnectionAttemptDelay.Get();
}
// static
HttpStreamPool::TcpBasedAttemptDelayBehavior
HttpStreamPool::GetTcpBasedAttemptDelayBehavior() {
return kTcpBasedAttemptDelayBehavior.Get();
}
// static
bool HttpStreamPool::VerboseNetLog() {
return kVerboseNetLog.Get();
}
HttpStreamPool::HttpStreamPool(HttpNetworkSession* http_network_session,
bool cleanup_on_ip_address_change)
: http_network_session_(http_network_session),
stream_attempt_params_(
StreamAttemptParams::FromHttpNetworkSession(http_network_session_)),
cleanup_on_ip_address_change_(cleanup_on_ip_address_change),
net_log_(NetLogWithSource::Make(http_network_session_->net_log(),
NetLogSourceType::HTTP_STREAM_POOL)),
max_stream_sockets_per_pool_(kHttpStreamPoolMaxStreamPerPool.Get()),
// Ensure that the per-group limit is less than or equals to the per-pool
// limit.
max_stream_sockets_per_group_(
std::min(kHttpStreamPoolMaxStreamPerPool.Get(),
kHttpStreamPoolMaxStreamPerGroup.Get())) {
CHECK(http_network_session_);
if (cleanup_on_ip_address_change) {
NetworkChangeNotifier::AddIPAddressObserver(this);
}
http_network_session_->ssl_client_context()->AddObserver(this);
if (kConsistencyCheck.Get() != CheckConsistencyMode::kDisabled) {
CheckConsistency();
}
}
HttpStreamPool::~HttpStreamPool() {
http_network_session_->ssl_client_context()->RemoveObserver(this);
if (cleanup_on_ip_address_change_) {
NetworkChangeNotifier::RemoveIPAddressObserver(this);
}
}
void HttpStreamPool::OnShuttingDown() {
is_shutting_down_ = true;
}
void HttpStreamPool::HandleStreamRequest(
HttpStreamRequest* request,
HttpStreamRequest::Delegate* delegate,
HttpStreamPoolRequestInfo request_info,
RequestPriority priority,
const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
bool enable_ip_based_pooling_for_h2,
bool enable_alternative_services) {
auto controller = std::make_unique<JobController>(
this, std::move(request_info), priority, allowed_bad_certs,
enable_ip_based_pooling_for_h2, enable_alternative_services);
JobController* controller_raw_ptr = controller.get();
// Put `controller` into `job_controllers_` before calling HandleRequest() to
// make sure `job_controllers_` always contains `controller` when
// OnJobControllerComplete() is called.
job_controllers_.emplace(std::move(controller));
if (controller_raw_ptr->respect_limits() == RespectLimits::kIgnore) {
++limit_ignoring_job_controller_counts_;
}
controller_raw_ptr->HandleStreamRequest(request, delegate);
}
int HttpStreamPool::Preconnect(HttpStreamPoolRequestInfo request_info,
size_t num_streams,
CompletionOnceCallback callback) {
auto controller = std::make_unique<JobController>(
this, std::move(request_info), /*priority=*/RequestPriority::IDLE,
/*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>(),
/*enable_ip_based_pooling_for_h2=*/true,
/*enable_alternative_services=*/true);
JobController* controller_raw_ptr = controller.get();
CHECK_EQ(controller_raw_ptr->respect_limits(), RespectLimits::kRespect);
// SAFETY: Using base::Unretained() is safe because `this` owns `controller`.
int rv = controller_raw_ptr->Preconnect(
num_streams, base::BindOnce(&HttpStreamPool::OnPreconnectComplete,
base::Unretained(this), controller_raw_ptr,
std::move(callback)));
// Preconnect() doesn't invoke the callback when it completes synchronously.
// Put `controller` into `job_controllers_` only when the method doesn't
// complete synchronously.
if (rv == ERR_IO_PENDING) {
job_controllers_.emplace(std::move(controller));
}
return rv;
}
bool HttpStreamPool::EnsureTotalActiveStreamCountBelowLimit() const {
if (limit_ignoring_job_controller_counts_ > 0) {
return true;
}
return TotalActiveStreamCount() < max_stream_sockets_per_pool_;
}
void HttpStreamPool::IncrementTotalIdleStreamCount() {
CHECK(EnsureTotalActiveStreamCountBelowLimit());
++total_idle_stream_count_;
TRACE_COUNTER("net.stream", "HttpStreamPoolTotalIdleStreams",
total_idle_stream_count_);
}
void HttpStreamPool::DecrementTotalIdleStreamCount() {
CHECK_GT(total_idle_stream_count_, 0u);
--total_idle_stream_count_;
TRACE_COUNTER("net.stream", "HttpStreamPoolTotalIdleStreams",
total_idle_stream_count_);
}
void HttpStreamPool::IncrementTotalHandedOutStreamCount() {
CHECK(EnsureTotalActiveStreamCountBelowLimit());
++total_handed_out_stream_count_;
TRACE_COUNTER("net.stream", "HttpStreamPoolTotalHandedOutStreams",
total_handed_out_stream_count_);
}
void HttpStreamPool::DecrementTotalHandedOutStreamCount() {
CHECK_GT(total_handed_out_stream_count_, 0u);
--total_handed_out_stream_count_;
TRACE_COUNTER("net.stream", "HttpStreamPoolTotalHandedOutStreams",
total_handed_out_stream_count_);
}
void HttpStreamPool::IncrementTotalConnectingStreamCount() {
CHECK(EnsureTotalActiveStreamCountBelowLimit());
++total_connecting_stream_count_;
TRACE_COUNTER("net.stream", "HttpStreamPoolTotalConnectingStreams",
total_connecting_stream_count_);
}
void HttpStreamPool::DecrementTotalConnectingStreamCount(size_t amount) {
CHECK_GE(total_connecting_stream_count_, amount);
total_connecting_stream_count_ -= amount;
TRACE_COUNTER("net.stream", "HttpStreamPoolTotalConnectingStreams",
total_connecting_stream_count_);
}
void HttpStreamPool::OnIPAddressChanged() {
CHECK(cleanup_on_ip_address_change_);
for (const auto& group : groups_) {
group.second->FlushWithError(ERR_NETWORK_CHANGED,
StreamSocketCloseReason::kIpAddressChanged,
kIpAddressChanged);
}
}
void HttpStreamPool::OnSSLConfigChanged(
SSLClientContext::SSLConfigChangeType change_type) {
for (const auto& group : groups_) {
group.second->Refresh(kSslConfigChanged,
StreamSocketCloseReason::kSslConfigChanged);
}
ProcessPendingRequestsInGroups();
}
void HttpStreamPool::OnSSLConfigForServersChanged(
const base::flat_set<HostPortPair>& servers) {
for (const auto& group : groups_) {
if (GURL::SchemeIsCryptographic(group.first.destination().scheme()) &&
servers.contains(
HostPortPair::FromSchemeHostPort(group.first.destination()))) {
group.second->Refresh(kSslConfigChanged,
StreamSocketCloseReason::kSslConfigChanged);
}
}
ProcessPendingRequestsInGroups();
}
void HttpStreamPool::OnGroupComplete(Group* group) {
auto it = groups_.find(group->stream_key());
CHECK(it != groups_.end());
groups_.erase(it);
}
void HttpStreamPool::OnJobControllerComplete(JobController* job_controller) {
if (job_controller->respect_limits() == RespectLimits::kIgnore) {
CHECK_GT(limit_ignoring_job_controller_counts_, 0u);
--limit_ignoring_job_controller_counts_;
}
auto it = job_controllers_.find(job_controller);
CHECK(it != job_controllers_.end());
job_controllers_.erase(it);
CHECK_GE(job_controllers_.size(), limit_ignoring_job_controller_counts_);
}
void HttpStreamPool::FlushWithError(
int error,
StreamSocketCloseReason attempt_cancel_reason,
std::string_view net_log_close_reason_utf8) {
for (auto& group : groups_) {
group.second->FlushWithError(error, attempt_cancel_reason,
net_log_close_reason_utf8);
}
}
void HttpStreamPool::CloseIdleStreams(
std::string_view net_log_close_reason_utf8) {
for (auto& group : groups_) {
group.second->CloseIdleStreams(net_log_close_reason_utf8);
}
}
bool HttpStreamPool::IsPoolStalled() {
if (!ReachedMaxStreamLimit()) {
return false;
}
return FindHighestStalledGroup() != nullptr;
}
void HttpStreamPool::ProcessPendingRequestsInGroups() {
if (is_shutting_down_) {
return;
}
// Loop until there is nothing more to do.
while (true) {
Group* group = FindHighestStalledGroup();
if (!group) {
return;
}
if (ReachedMaxStreamLimit()) {
if (!CloseOneIdleStreamSocket()) {
return;
}
}
group->ProcessPendingRequest();
}
}
bool HttpStreamPool::RequiresHTTP11(
const url::SchemeHostPort& destination,
const NetworkAnonymizationKey& network_anonymization_key) {
return http_network_session()->http_server_properties()->RequiresHTTP11(
destination, network_anonymization_key);
}
bool HttpStreamPool::IsQuicBroken(
const url::SchemeHostPort& destination,
const NetworkAnonymizationKey& network_anonymization_key) {
return http_network_session()
->http_server_properties()
->IsAlternativeServiceBroken(
AlternativeService(NextProto::kProtoQUIC,
HostPortPair::FromSchemeHostPort(destination)),
network_anonymization_key);
}
bool HttpStreamPool::CanUseQuic(
const url::SchemeHostPort& destination,
const NetworkAnonymizationKey& network_anonymization_key,
bool enable_alternative_services) {
if (http_network_session()->ShouldForceQuic(destination, ProxyInfo::Direct(),
/*is_websocket=*/false)) {
return true;
}
return http_network_session()->IsQuicEnabled() &&
enable_alternative_services &&
GURL::SchemeIsCryptographic(destination.scheme()) &&
!RequiresHTTP11(destination, network_anonymization_key) &&
!IsQuicBroken(destination, network_anonymization_key);
}
quic::ParsedQuicVersion HttpStreamPool::SelectQuicVersion(
const AlternativeServiceInfo& alternative_service_info) {
if (alternative_service_info.protocol() != NextProto::kProtoQUIC) {
return quic::ParsedQuicVersion::Unsupported();
}
return http_network_session()->context().quic_context->SelectQuicVersion(
alternative_service_info.advertised_versions());
}
bool HttpStreamPool::CanUseExistingQuicSession(
const QuicSessionAliasKey& quic_session_alias_key,
bool enable_alternative_services) {
const url::SchemeHostPort& destination = quic_session_alias_key.destination();
return destination.IsValid() &&
CanUseQuic(
destination,
quic_session_alias_key.session_key().network_anonymization_key(),
enable_alternative_services) &&
http_network_session()->quic_session_pool()->CanUseExistingSession(
quic_session_alias_key.session_key(), destination);
}
CompletionOnceCallback HttpStreamPool::GetAltSvcQuicPreconnectCallback() {
if (alt_svc_quic_preconnect_callback_for_testing_) {
return std::move(alt_svc_quic_preconnect_callback_for_testing_);
}
return base::DoNothing();
}
void HttpStreamPool::SetDelegateForTesting(
std::unique_ptr<TestDelegate> delegate) {
delegate_for_testing_ = std::move(delegate);
}
base::Value::Dict HttpStreamPool::GetInfoAsValue() const {
// Using "socket" instead of "stream" for compatibility with ClientSocketPool.
// These fields are used by some tests.
base::Value::Dict dict;
dict.Set("handed_out_socket_count",
static_cast<int>(total_handed_out_stream_count_));
dict.Set("connecting_socket_count",
static_cast<int>(total_connecting_stream_count_));
dict.Set("idle_socket_count", static_cast<int>(total_idle_stream_count_));
dict.Set("max_socket_count", static_cast<int>(max_stream_sockets_per_pool_));
dict.Set("max_sockets_per_group",
static_cast<int>(max_stream_sockets_per_group_));
base::Value::Dict group_dicts;
for (const auto& [key, group] : groups_) {
group_dicts.Set(key.ToString(), group->GetInfoAsValue());
}
if (!group_dicts.empty()) {
dict.Set("groups", std::move(group_dicts));
}
base::Value::List job_controller_list;
for (const auto& job_controller : job_controllers_) {
job_controller_list.Append(job_controller->GetInfoAsValue());
}
if (!job_controller_list.empty()) {
dict.Set("job_controllers", std::move(job_controller_list));
}
return dict;
}
HttpStreamPool::Group& HttpStreamPool::GetOrCreateGroupForTesting(
const HttpStreamKey& stream_key) {
return GetOrCreateGroup(stream_key);
}
HttpStreamPool::Group* HttpStreamPool::GetGroupForTesting(
const HttpStreamKey& stream_key) {
return GetGroup(stream_key);
}
HttpStreamPool::Group& HttpStreamPool::GetOrCreateGroup(
const HttpStreamKey& stream_key,
std::optional<QuicSessionAliasKey> quic_session_alias_key) {
auto it = groups_.find(stream_key);
if (it == groups_.end()) {
it = groups_.try_emplace(
it, stream_key,
std::make_unique<Group>(this, stream_key, quic_session_alias_key));
}
return *it->second;
}
HttpStreamPool::Group* HttpStreamPool::GetGroup(
const HttpStreamKey& stream_key) {
auto it = groups_.find(stream_key);
return it == groups_.end() ? nullptr : it->second.get();
}
HttpStreamPool::Group* HttpStreamPool::FindHighestStalledGroup() {
Group* highest_stalled_group = nullptr;
std::optional<RequestPriority> highest_priority;
for (const auto& group : groups_) {
std::optional<RequestPriority> priority =
group.second->GetPriorityIfStalledByPoolLimit();
if (!priority) {
continue;
}
if (!highest_priority || *priority > *highest_priority) {
highest_priority = priority;
highest_stalled_group = group.second.get();
}
}
return highest_stalled_group;
}
bool HttpStreamPool::CloseOneIdleStreamSocket() {
if (total_idle_stream_count_ == 0) {
return false;
}
for (auto& group : groups_) {
if (group.second->CloseOneIdleStreamSocket()) {
return true;
}
}
NOTREACHED();
}
base::WeakPtr<SpdySession> HttpStreamPool::FindAvailableSpdySession(
const HttpStreamKey& stream_key,
const SpdySessionKey& spdy_session_key,
bool enable_ip_based_pooling_for_h2,
const NetLogWithSource& net_log) {
if (!GURL::SchemeIsCryptographic(stream_key.destination().scheme())) {
return nullptr;
}
base::WeakPtr<SpdySession> spdy_session =
http_network_session()->spdy_session_pool()->FindAvailableSession(
spdy_session_key, enable_ip_based_pooling_for_h2,
/*is_websocket=*/false, net_log);
if (spdy_session) {
CHECK(!RequiresHTTP11(stream_key.destination(),
stream_key.network_anonymization_key()));
}
return spdy_session;
}
void HttpStreamPool::OnPreconnectComplete(JobController* job_controller,
CompletionOnceCallback callback,
int rv) {
OnJobControllerComplete(job_controller);
std::move(callback).Run(rv);
}
void HttpStreamPool::CheckConsistency() {
CHECK(kConsistencyCheck.Get() != CheckConsistencyMode::kDisabled);
const bool is_strict =
kConsistencyCheck.Get() == CheckConsistencyMode::kStrict;
const StreamCounts pool_total_counts = {
.handed_out = total_handed_out_stream_count_,
.idle = total_idle_stream_count_,
.connecting = total_connecting_stream_count_};
if (groups_.empty()) {
VLOG_IF(1, pool_total_counts == StreamCounts())
<< "Total stream counts are not zero: " << pool_total_counts;
} else {
StreamCounts groups_total_counts;
base::Value::Dict groups;
for (const auto& [key, group] : groups_) {
groups_total_counts.handed_out += group->HandedOutStreamSocketCount();
groups_total_counts.idle += group->IdleStreamSocketCount();
groups_total_counts.connecting += group->ConnectingStreamSocketCount();
groups.Set(key.ToString(), group->GetInfoAsValue());
if (is_strict) {
CHECK(!group->CanComplete()) << key.ToString();
}
}
const bool ok = pool_total_counts == groups_total_counts;
NetLogEventType event_type =
ok ? NetLogEventType::HTTP_STREAM_POOL_CONSISTENCY_CHECK_OK
: NetLogEventType::HTTP_STREAM_POOL_CONSISTENCY_CHECK_FAIL;
net_log_.AddEvent(event_type, [&] {
base::Value::Dict dict;
dict.Set("pool_total_counts", pool_total_counts.ToValue());
dict.Set("groups_total_counts", groups_total_counts.ToValue());
dict.Set("groups", std::move(groups));
return dict;
});
if (is_strict) {
CHECK(ok) << "Stream counts mismatch: pool=" << pool_total_counts
<< ", groups=" << groups_total_counts;
} else {
VLOG_IF(1, !ok) << "Stream counts mismatch: pool=" << pool_total_counts
<< ", groups=" << groups_total_counts;
}
}
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&HttpStreamPool::CheckConsistency,
weak_ptr_factory_.GetWeakPtr()),
base::Seconds(3));
}
} // namespace net
tap什么意思 吃什么补胶原蛋白 游泳要带什么东西 容易出汗什么原因 自怨自艾什么意思
2019属什么生肖 脑瘫是什么意思 祖宗是什么意思 舌尖长溃疡是什么原因 琼脂是什么东西
无锡机场叫什么名字 用白醋泡脚有什么好处 鸡蛋炒什么菜谱大全 梦到头发长长了是什么意思 梦见建房子是什么预兆
炸腮有什么症状 肺结核通过什么途径传染 检查前列腺做什么检查 女性乳房痒是什么原因 顾虑是什么意思
利率是什么hcv8jop1ns1r.cn 私事是什么意思hcv8jop1ns3r.cn 梅毒螺旋体抗体是什么意思hcv9jop3ns6r.cn 经常梦遗是什么原因shenchushe.com 什么是耐药性hcv9jop5ns2r.cn
女性什么时候最容易怀孕hcv7jop7ns1r.cn 头晕需要做什么检查hcv8jop9ns2r.cn 来大姨妈吃什么对身体好jasonfriends.com 金达莱花是什么花jinxinzhichuang.com 脊椎炎什么症状hcv8jop6ns0r.cn
什么是丹毒hcv8jop9ns6r.cn 水上漂是什么意思hcv7jop6ns0r.cn 什么叫公租房hcv9jop4ns8r.cn 左眼老是跳是什么原因hcv9jop6ns7r.cn 清洁度iv是什么意思hcv8jop7ns1r.cn
唠嗑是什么意思hcv9jop0ns2r.cn 阿昔洛韦片治什么病hcv8jop3ns5r.cn 胃痛吃什么食物hcv8jop3ns0r.cn 补铁的药什么时候吃最好hcv9jop7ns4r.cn 04年属猴的是什么命hcv8jop3ns1r.cn
百度