#include "net/socket/transport_client_socket_pool.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "net/base/completion_once_callback.h"
#include "net/base/features.h"
#include "net/base/ip_endpoint.h"
#include "net/base/load_timing_info.h"
#include "net/base/load_timing_info_test_util.h"
#include "net/base/net_errors.h"
#include "net/base/privacy_mode.h"
#include "net/base/proxy_server.h"
#include "net/base/proxy_string_util.h"
#include "net/base/schemeful_site.h"
#include "net/base/test_completion_callback.h"
#include "net/cert/ct_policy_enforcer.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/dns/mock_host_resolver.h"
#include "net/dns/public/secure_dns_policy.h"
#include "net/http/http_network_session.h"
#include "net/http/http_proxy_connect_job.h"
#include "net/http/transport_security_state.h"
#include "net/log/net_log.h"
#include "net/log/net_log_with_source.h"
#include "net/log/test_net_log.h"
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/connect_job.h"
#include "net/socket/socket_tag.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/socks_connect_job.h"
#include "net/socket/ssl_connect_job.h"
#include "net/socket/stream_socket.h"
#include "net/socket/transport_client_socket_pool.h"
#include "net/socket/transport_client_socket_pool_test_util.h"
#include "net/socket/transport_connect_job.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/ssl/ssl_config_service.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/gtest_util.h"
#include "net/test/test_with_task_environment.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
#include "url/url_constants.h"
using net::test::IsError;
using net::test::IsOk;
namespace net {
namespace {
const int kMaxSockets = 32;
const int kMaxSocketsPerGroup = 6;
constexpr base::TimeDelta kUnusedIdleSocketTimeout = base::Seconds(10);
const RequestPriority kDefaultPriority = LOW;
class SOCKS5MockData {
public:
explicit SOCKS5MockData(IoMode mode) {
writes_ = std::make_unique<MockWrite[]>(2);
writes_[0] =
MockWrite(mode, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength);
writes_[1] = MockWrite(mode, kSOCKS5OkRequest, kSOCKS5OkRequestLength);
reads_ = std::make_unique<MockRead[]>(2);
reads_[0] =
MockRead(mode, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength);
reads_[1] = MockRead(mode, kSOCKS5OkResponse, kSOCKS5OkResponseLength);
data_ = std::make_unique<StaticSocketDataProvider>(
base::make_span(reads_.get(), 2u), base::make_span(writes_.get(), 2u));
}
SocketDataProvider* data_provider() { return data_.get(); }
private:
std::unique_ptr<StaticSocketDataProvider> data_;
std::unique_ptr<MockWrite[]> writes_;
std::unique_ptr<MockRead[]> reads_;
};
class TransportClientSocketPoolTest : public ::testing::Test,
public WithTaskEnvironment {
public:
TransportClientSocketPoolTest(const TransportClientSocketPoolTest&) = delete;
TransportClientSocketPoolTest& operator=(
const TransportClientSocketPoolTest&) = delete;
protected:
explicit TransportClientSocketPoolTest(
base::test::TaskEnvironment::TimeSource time_source =
base::test::TaskEnvironment::TimeSource::DEFAULT)
: WithTaskEnvironment(time_source),
connect_backup_jobs_enabled_(
TransportClientSocketPool::set_connect_backup_jobs_enabled(true)),
group_id_(url::SchemeHostPort(url::kHttpScheme, "www.google.com", 80),
PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow),
params_(ClientSocketPool::SocketParams::CreateForHttpForTesting()),
client_socket_factory_(NetLog::Get()) {
std::unique_ptr<MockCertVerifier> cert_verifier =
std::make_unique<MockCertVerifier>();
cert_verifier->set_default_result(OK);
session_deps_.cert_verifier = std::move(cert_verifier);
http_network_session_ =
SpdySessionDependencies::SpdyCreateSession(&session_deps_);
common_connect_job_params_ = std::make_unique<CommonConnectJobParams>(
http_network_session_->CreateCommonConnectJobParams());
common_connect_job_params_->client_socket_factory = &client_socket_factory_;
pool_ = std::make_unique<TransportClientSocketPool>(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyServer::Direct(), false ,
common_connect_job_params_.get());
tagging_common_connect_job_params_ =
std::make_unique<CommonConnectJobParams>(
http_network_session_->CreateCommonConnectJobParams());
tagging_common_connect_job_params_->client_socket_factory =
&tagging_client_socket_factory_;
tagging_pool_ = std::make_unique<TransportClientSocketPool>(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyServer::Direct(), false ,
tagging_common_connect_job_params_.get());
common_connect_job_params_for_real_sockets_ =
std::make_unique<CommonConnectJobParams>(
http_network_session_->CreateCommonConnectJobParams());
common_connect_job_params_for_real_sockets_->client_socket_factory =
ClientSocketFactory::GetDefaultFactory();
pool_for_real_sockets_ = std::make_unique<TransportClientSocketPool>(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyServer::Direct(), false ,
common_connect_job_params_for_real_sockets_.get());
}
~TransportClientSocketPoolTest() override {
TransportClientSocketPool::set_connect_backup_jobs_enabled(
connect_backup_jobs_enabled_);
}
int StartRequest(const std::string& host_name, RequestPriority priority) {
ClientSocketPool::GroupId group_id(
url::SchemeHostPort(url::kHttpScheme, host_name, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
return test_base_.StartRequestUsingPool(
pool_.get(), group_id, priority,
ClientSocketPool::RespectLimits::ENABLED,
ClientSocketPool::SocketParams::CreateForHttpForTesting());
}
int GetOrderOfRequest(size_t index) {
return test_base_.GetOrderOfRequest(index);
}
bool ReleaseOneConnection(ClientSocketPoolTest::KeepAlive keep_alive) {
return test_base_.ReleaseOneConnection(keep_alive);
}
void ReleaseAllConnections(ClientSocketPoolTest::KeepAlive keep_alive) {
test_base_.ReleaseAllConnections(keep_alive);
}
std::vector<std::unique_ptr<TestSocketRequest>>* requests() {
return test_base_.requests();
}
size_t completion_count() const { return test_base_.completion_count(); }
bool connect_backup_jobs_enabled_;
const ClientSocketPool::GroupId group_id_;
scoped_refptr<ClientSocketPool::SocketParams> params_;
MockTransportClientSocketFactory client_socket_factory_;
MockTaggingClientSocketFactory tagging_client_socket_factory_;
SpdySessionDependencies session_deps_;
std::unique_ptr<HttpNetworkSession> http_network_session_;
std::unique_ptr<CommonConnectJobParams> common_connect_job_params_;
std::unique_ptr<TransportClientSocketPool> pool_;
std::unique_ptr<CommonConnectJobParams> tagging_common_connect_job_params_;
std::unique_ptr<TransportClientSocketPool> tagging_pool_;
std::unique_ptr<CommonConnectJobParams>
common_connect_job_params_for_real_sockets_;
std::unique_ptr<TransportClientSocketPool> pool_for_real_sockets_;
ClientSocketPoolTest test_base_;
};
TEST_F(TransportClientSocketPoolTest, Basic) {
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv =
handle.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoConnectedNotReused(handle);
EXPECT_EQ(0u, handle.connection_attempts().size());
}
TEST_F(TransportClientSocketPoolTest, SetResolvePriorityOnInit) {
for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) {
RequestPriority priority = static_cast<RequestPriority>(i);
TestCompletionCallback callback;
ClientSocketHandle handle;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_,
absl::nullopt , priority,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource()));
EXPECT_EQ(priority, session_deps_.host_resolver->last_request_priority());
}
}
TEST_F(TransportClientSocketPoolTest, SetSecureDnsPolicy) {
for (auto secure_dns_policy :
{SecureDnsPolicy::kAllow, SecureDnsPolicy::kDisable}) {
TestCompletionCallback callback;
ClientSocketHandle handle;
ClientSocketPool::GroupId group_id(
url::SchemeHostPort(url::kHttpScheme, "www.google.com", 80),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
secure_dns_policy);
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource()));
EXPECT_EQ(secure_dns_policy,
session_deps_.host_resolver->last_secure_dns_policy());
}
}
TEST_F(TransportClientSocketPoolTest, ReprioritizeRequests) {
session_deps_.host_resolver->set_ondemand_mode(true);
TestCompletionCallback callback1;
ClientSocketHandle handle1;
int rv1 =
handle1.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv1, IsError(ERR_IO_PENDING));
TestCompletionCallback callback2;
ClientSocketHandle handle2;
int rv2 = handle2.Init(
group_id_, params_, absl::nullopt , HIGHEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv2, IsError(ERR_IO_PENDING));
TestCompletionCallback callback3;
ClientSocketHandle handle3;
int rv3 = handle3.Init(
group_id_, params_, absl::nullopt , LOWEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback3.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv3, IsError(ERR_IO_PENDING));
TestCompletionCallback callback4;
ClientSocketHandle handle4;
int rv4 = handle4.Init(
group_id_, params_, absl::nullopt , MEDIUM,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback4.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv4, IsError(ERR_IO_PENDING));
TestCompletionCallback callback5;
ClientSocketHandle handle5;
int rv5 = handle5.Init(
group_id_, params_, absl::nullopt , HIGHEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback5.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv5, IsError(ERR_IO_PENDING));
TestCompletionCallback callback6;
ClientSocketHandle handle6;
int rv6 =
handle6.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback6.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv6, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(2));
EXPECT_EQ(LOWEST, session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(MEDIUM, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(6));
TestCompletionCallback callback7;
ClientSocketHandle handle7;
int rv7 = handle7.Init(
group_id_, params_, absl::nullopt , HIGHEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback7.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv7, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(2));
EXPECT_EQ(HIGHEST,
session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(MEDIUM, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(6));
TestCompletionCallback callback8;
ClientSocketHandle handle8;
int rv8 = handle8.Init(
group_id_, params_, absl::nullopt , HIGHEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback8.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv8, IsError(ERR_IO_PENDING));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(2));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(MEDIUM, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(HIGHEST,
session_deps_.host_resolver->request_priority(6));
session_deps_.host_resolver->ResolveNow(2);
EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_TRUE(handle2.is_initialized());
EXPECT_TRUE(handle2.socket());
handle2.Reset();
EXPECT_THAT(callback5.WaitForResult(), IsOk());
EXPECT_TRUE(handle5.is_initialized());
EXPECT_TRUE(handle5.socket());
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(MEDIUM, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(LOW,
session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(6));
handle7.Reset();
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(LOWEST,
session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(MEDIUM, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(6));
pool_->SetPriority(group_id_, &handle4, LOWEST);
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(LOWEST, session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(LOWEST,
session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(6));
pool_->SetPriority(group_id_, &handle3, MEDIUM);
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
EXPECT_EQ(MEDIUM,
session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(LOWEST, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(HIGHEST, session_deps_.host_resolver->request_priority(6));
session_deps_.host_resolver->ResolveNow(1);
EXPECT_THAT(callback8.WaitForResult(), IsOk());
EXPECT_TRUE(handle8.is_initialized());
EXPECT_TRUE(handle8.socket());
EXPECT_EQ(MEDIUM, session_deps_.host_resolver->request_priority(3));
EXPECT_EQ(LOWEST, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(LOW,
session_deps_.host_resolver->request_priority(6));
session_deps_.host_resolver->ResolveNow(3);
EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_TRUE(handle3.is_initialized());
EXPECT_TRUE(handle3.socket());
EXPECT_EQ(LOWEST, session_deps_.host_resolver->request_priority(4));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(5));
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(6));
session_deps_.host_resolver->ResolveAllPending();
EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(handle1.is_initialized());
EXPECT_TRUE(handle1.socket());
EXPECT_THAT(callback4.WaitForResult(), IsOk());
EXPECT_TRUE(handle4.is_initialized());
EXPECT_TRUE(handle4.socket());
EXPECT_THAT(callback6.WaitForResult(), IsOk());
EXPECT_TRUE(handle6.is_initialized());
EXPECT_TRUE(handle6.socket());
}
TEST_F(TransportClientSocketPoolTest, RequestIgnoringLimitsIsReprioritized) {
TransportClientSocketPool pool(
kMaxSockets, 1, kUnusedIdleSocketTimeout, ProxyServer::Direct(),
false , common_connect_job_params_.get());
TestCompletionCallback callback1;
ClientSocketHandle handle1;
int rv1 = handle1.Init(
group_id_, params_, absl::nullopt ,
MAXIMUM_PRIORITY, SocketTag(), ClientSocketPool::RespectLimits::DISABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(), &pool,
NetLogWithSource());
EXPECT_THAT(rv1, IsError(ERR_IO_PENDING));
EXPECT_EQ(MAXIMUM_PRIORITY, session_deps_.host_resolver->request_priority(1));
TestCompletionCallback callback2;
ClientSocketHandle handle2;
int rv2 =
handle2.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
&pool, NetLogWithSource());
EXPECT_THAT(rv2, IsError(ERR_IO_PENDING));
handle1.Reset();
EXPECT_EQ(LOW, session_deps_.host_resolver->request_priority(1));
}
TEST_F(TransportClientSocketPoolTest, InitHostResolutionFailure) {
session_deps_.host_resolver->rules()->AddSimulatedTimeoutFailure(
group_id_.destination().host());
TestCompletionCallback callback;
ClientSocketHandle handle;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()));
EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
EXPECT_THAT(handle.resolve_error_info().error, IsError(ERR_DNS_TIMED_OUT));
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_TRUE(handle.connection_attempts()[0].endpoint.address().empty());
EXPECT_THAT(handle.connection_attempts()[0].result,
IsError(ERR_NAME_NOT_RESOLVED));
}
TEST_F(TransportClientSocketPoolTest, InitConnectionFailure) {
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::Type::kFailing);
TestCompletionCallback callback;
ClientSocketHandle handle;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()));
EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_EQ("127.0.0.1:80",
handle.connection_attempts()[0].endpoint.ToString());
EXPECT_THAT(handle.connection_attempts()[0].result,
IsError(ERR_CONNECTION_FAILED));
session_deps_.host_resolver->set_synchronous_mode(true);
EXPECT_EQ(
ERR_CONNECTION_FAILED,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()));
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_EQ("127.0.0.1:80",
handle.connection_attempts()[0].endpoint.ToString());
EXPECT_THAT(handle.connection_attempts()[0].result,
IsError(ERR_CONNECTION_FAILED));
}
TEST_F(TransportClientSocketPoolTest, PendingRequests) {
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
session_deps_.host_resolver->set_synchronous_mode(true);
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count());
EXPECT_EQ(11U, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
EXPECT_EQ(3, GetOrderOfRequest(3));
EXPECT_EQ(4, GetOrderOfRequest(4));
EXPECT_EQ(5, GetOrderOfRequest(5));
EXPECT_EQ(6, GetOrderOfRequest(6));
EXPECT_EQ(7, GetOrderOfRequest(7));
EXPECT_EQ(14, GetOrderOfRequest(8));
EXPECT_EQ(15, GetOrderOfRequest(9));
EXPECT_EQ(10, GetOrderOfRequest(10));
EXPECT_EQ(13, GetOrderOfRequest(11));
EXPECT_EQ(8, GetOrderOfRequest(12));
EXPECT_EQ(16, GetOrderOfRequest(13));
EXPECT_EQ(11, GetOrderOfRequest(14));
EXPECT_EQ(12, GetOrderOfRequest(15));
EXPECT_EQ(9, GetOrderOfRequest(16));
EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(17));
}
TEST_F(TransportClientSocketPoolTest, PendingRequests_NoKeepAlive) {
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
session_deps_.host_resolver->set_synchronous_mode(true);
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
EXPECT_THAT((*requests())[6]->WaitForResult(), IsOk());
EXPECT_THAT((*requests())[7]->WaitForResult(), IsOk());
EXPECT_THAT((*requests())[8]->WaitForResult(), IsOk());
EXPECT_THAT((*requests())[9]->WaitForResult(), IsOk());
EXPECT_THAT((*requests())[10]->WaitForResult(), IsOk());
EXPECT_EQ(static_cast<int>(requests()->size()),
client_socket_factory_.allocation_count());
EXPECT_EQ(6U, completion_count());
}
TEST_F(TransportClientSocketPoolTest, CancelRequestClearGroup) {
TestCompletionCallback callback;
ClientSocketHandle handle;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()));
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, TwoRequestsCancelOne) {
ClientSocketHandle handle;
TestCompletionCallback callback;
ClientSocketHandle handle2;
TestCompletionCallback callback2;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()));
EXPECT_EQ(
ERR_IO_PENDING,
handle2.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource()));
handle.Reset();
EXPECT_THAT(callback2.WaitForResult(), IsOk());
handle2.Reset();
}
TEST_F(TransportClientSocketPoolTest, ConnectCancelConnect) {
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::Type::kPending);
ClientSocketHandle handle;
TestCompletionCallback callback;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()));
handle.Reset();
TestCompletionCallback callback2;
EXPECT_EQ(
ERR_IO_PENDING,
handle.Init(group_id_, params_, absl::nullopt ,
kDefaultPriority, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource()));
session_deps_.host_resolver->set_synchronous_mode(true);
EXPECT_THAT(callback2.WaitForResult(), IsOk());
EXPECT_FALSE(callback.have_result());
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, CancelRequest) {
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT((*requests())[0]->WaitForResult(), IsOk());
session_deps_.host_resolver->set_synchronous_mode(true);
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsOk());
EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", MEDIUM), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", HIGHEST), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOW), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", LOWEST), IsError(ERR_IO_PENDING));
size_t index_to_cancel = kMaxSocketsPerGroup + 2;
EXPECT_FALSE((*requests())[index_to_cancel]->handle()->is_initialized());
(*requests())[index_to_cancel]->handle()->Reset();
ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
EXPECT_EQ(kMaxSocketsPerGroup,
client_socket_factory_.allocation_count());
EXPECT_EQ(requests()->size() - kMaxSocketsPerGroup, completion_count());
EXPECT_EQ(1, GetOrderOfRequest(1));
EXPECT_EQ(2, GetOrderOfRequest(2));
EXPECT_EQ(3, GetOrderOfRequest(3));
EXPECT_EQ(4, GetOrderOfRequest(4));
EXPECT_EQ(5, GetOrderOfRequest(5));
EXPECT_EQ(6, GetOrderOfRequest(6));
EXPECT_EQ(14, GetOrderOfRequest(7));
EXPECT_EQ(7, GetOrderOfRequest(8));
EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound,
GetOrderOfRequest(9));
EXPECT_EQ(9, GetOrderOfRequest(10));
EXPECT_EQ(10, GetOrderOfRequest(11));
EXPECT_EQ(11, GetOrderOfRequest(12));
EXPECT_EQ(8, GetOrderOfRequest(13));
EXPECT_EQ(12, GetOrderOfRequest(14));
EXPECT_EQ(13, GetOrderOfRequest(15));
EXPECT_EQ(15, GetOrderOfRequest(16));
EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(17));
}
class RequestSocketCallback : public TestCompletionCallbackBase {
public:
RequestSocketCallback(
const ClientSocketPool::GroupId& group_id,
scoped_refptr<ClientSocketPool::SocketParams> socket_params,
ClientSocketHandle* handle,
TransportClientSocketPool* pool)
: group_id_(group_id),
socket_params_(socket_params),
handle_(handle),
pool_(pool) {}
RequestSocketCallback(const RequestSocketCallback&) = delete;
RequestSocketCallback& operator=(const RequestSocketCallback&) = delete;
~RequestSocketCallback() override = default;
CompletionOnceCallback callback() {
return base::BindOnce(&RequestSocketCallback::OnComplete,
base::Unretained(this));
}
private:
void OnComplete(int result) {
SetResult(result);
ASSERT_THAT(result, IsOk());
if (!within_callback_) {
handle_->socket()->Disconnect();
handle_->Reset();
base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
within_callback_ = true;
int rv = handle_->Init(
group_id_, socket_params_, absl::nullopt ,
LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback(), ClientSocketPool::ProxyAuthCallback(), pool_,
NetLogWithSource());
EXPECT_THAT(rv, IsOk());
}
}
const ClientSocketPool::GroupId group_id_;
scoped_refptr<ClientSocketPool::SocketParams> socket_params_;
const raw_ptr<ClientSocketHandle> handle_;
const raw_ptr<TransportClientSocketPool> pool_;
bool within_callback_ = false;
};
TEST_F(TransportClientSocketPoolTest, RequestTwice) {
ClientSocketHandle handle;
RequestSocketCallback callback(group_id_, params_, &handle, pool_.get());
int rv =
handle.Init(group_id_, params_, absl::nullopt ,
LOWEST, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
session_deps_.host_resolver->set_synchronous_mode(true);
EXPECT_THAT(callback.WaitForResult(), IsOk());
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, CancelActiveRequestWithPendingRequests) {
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::Type::kPending);
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
ASSERT_LE(kMaxSocketsPerGroup, static_cast<int>(requests()->size()));
for (int i = 0; i < kMaxSocketsPerGroup; i++)
(*requests())[i]->handle()->Reset();
for (size_t i = kMaxSocketsPerGroup; i < requests()->size(); ++i) {
EXPECT_THAT((*requests())[i]->WaitForResult(), IsOk());
(*requests())[i]->handle()->Reset();
}
EXPECT_EQ(requests()->size() - kMaxSocketsPerGroup, completion_count());
}
TEST_F(TransportClientSocketPoolTest, FailingActiveRequestWithPendingRequests) {
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::Type::kPendingFailing);
const int kNumRequests = 2 * kMaxSocketsPerGroup + 1;
ASSERT_LE(kNumRequests, kMaxSockets);
for (int i = 0; i < kNumRequests; i++)
EXPECT_THAT(StartRequest("a", kDefaultPriority), IsError(ERR_IO_PENDING));
for (int i = 0; i < kNumRequests; i++)
EXPECT_THAT((*requests())[i]->WaitForResult(),
IsError(ERR_CONNECTION_FAILED));
}
TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) {
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv =
handle.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
TestLoadTimingInfoConnectedNotReused(handle);
handle.Reset();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool_->IdleSocketCount());
rv = handle.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_EQ(0, pool_->IdleSocketCount());
TestLoadTimingInfoConnectedReused(handle);
}
TEST_F(TransportClientSocketPoolTest, CloseIdleSocketsOnIPAddressChange) {
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv =
handle.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
handle.Reset();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool_->IdleSocketCount());
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, pool_->IdleSocketCount());
}
TEST(TransportClientSocketPoolStandaloneTest, DontCleanupOnIPAddressChange) {
base::test::SingleThreadTaskEnvironment task_environment;
std::unique_ptr<MockCertVerifier> cert_verifier =
std::make_unique<MockCertVerifier>();
SpdySessionDependencies session_deps;
session_deps.cert_verifier = std::move(cert_verifier);
std::unique_ptr<HttpNetworkSession> http_network_session =
SpdySessionDependencies::SpdyCreateSession(&session_deps);
auto common_connect_job_params = std::make_unique<CommonConnectJobParams>(
http_network_session->CreateCommonConnectJobParams());
MockTransportClientSocketFactory client_socket_factory(NetLog::Get());
common_connect_job_params->client_socket_factory = &client_socket_factory;
scoped_refptr<ClientSocketPool::SocketParams> params(
ClientSocketPool::SocketParams::CreateForHttpForTesting());
auto pool = std::make_unique<TransportClientSocketPool>(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyServer::Direct(), false ,
common_connect_job_params.get(),
false );
const ClientSocketPool::GroupId group_id(
url::SchemeHostPort(url::kHttpScheme, "www.google.com", 80),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv =
handle.Init(group_id, params, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
handle.Reset();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool->IdleSocketCount());
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool->IdleSocketCount());
}
TEST_F(TransportClientSocketPoolTest, SSLCertError) {
StaticSocketDataProvider data;
tagging_client_socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, ERR_CERT_COMMON_NAME_INVALID);
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl);
const url::SchemeHostPort kEndpoint(url::kHttpsScheme, "ssl.server.test",
443);
auto ssl_config_for_origin = std::make_unique<SSLConfig>();
ssl_config_for_origin->alpn_protos = {kProtoHTTP2, kProtoHTTP11};
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::move(ssl_config_for_origin),
nullptr);
ClientSocketHandle handle;
TestCompletionCallback callback;
int rv =
handle.Init(ClientSocketPool::GroupId(
kEndpoint, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow),
socket_params, absl::nullopt ,
MEDIUM, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
tagging_pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CERT_COMMON_NAME_INVALID));
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
}
namespace {
class TransportClientSocketPoolSSLConfigChangeTest
: public TransportClientSocketPoolTest,
public ::testing::WithParamInterface<
SSLClientContext::SSLConfigChangeType> {
public:
void SimulateChange() {
switch (GetParam()) {
case SSLClientContext::SSLConfigChangeType::kSSLConfigChanged:
session_deps_.ssl_config_service->NotifySSLContextConfigChange();
break;
case SSLClientContext::SSLConfigChangeType::kCertDatabaseChanged:
pool_->OnSSLConfigChanged(GetParam());
break;
case SSLClientContext::SSLConfigChangeType::kCertVerifierChanged:
session_deps_.cert_verifier->SimulateOnCertVerifierChanged();
break;
}
}
const char* ExpectedMessage() {
switch (GetParam()) {
case SSLClientContext::SSLConfigChangeType::kSSLConfigChanged:
return TransportClientSocketPool::kNetworkChanged;
case SSLClientContext::SSLConfigChangeType::kCertDatabaseChanged:
return TransportClientSocketPool::kCertDatabaseChanged;
case SSLClientContext::SSLConfigChangeType::kCertVerifierChanged:
return TransportClientSocketPool::kCertVerifierChanged;
}
}
};
}
TEST_P(TransportClientSocketPoolSSLConfigChangeTest, GracefulConfigChange) {
{
TestCompletionCallback callback;
ClientSocketHandle handle1;
int rv =
handle1.Init(group_id_, params_, absl::nullopt,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle1.is_initialized());
EXPECT_FALSE(handle1.socket());
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle1.is_initialized());
EXPECT_TRUE(handle1.socket());
EXPECT_EQ(0, handle1.group_generation());
EXPECT_EQ(0, pool_->IdleSocketCount());
handle1.Reset();
}
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool_->IdleSocketCount());
ClientSocketHandle handle2;
{
ClientSocketPool::GroupId group_id2(
url::SchemeHostPort(url::kHttpScheme, "bar.example.com", 80),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
TestCompletionCallback callback;
int rv =
handle2.Init(group_id2, params_, absl::nullopt,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle2.is_initialized());
EXPECT_FALSE(handle2.socket());
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle2.is_initialized());
EXPECT_TRUE(handle2.socket());
EXPECT_EQ(0, handle2.group_generation());
}
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool_->IdleSocketCount());
ClientSocketPool::GroupId group_id3(
url::SchemeHostPort(url::kHttpScheme, "foo.example.com", 80),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
TestCompletionCallback callback3;
ClientSocketHandle handle3;
int rv =
handle3.Init(group_id3, params_, absl::nullopt,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback3.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle3.is_initialized());
EXPECT_FALSE(handle3.socket());
RecordingNetLogObserver net_log_observer;
SimulateChange();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, pool_->IdleSocketCount());
auto events = net_log_observer.GetEntriesWithType(
NetLogEventType::SOCKET_POOL_CLOSING_SOCKET);
ASSERT_EQ(events.size(), 1u);
std::string* reason = events[0].params.FindString("reason");
ASSERT_TRUE(reason);
EXPECT_EQ(*reason, ExpectedMessage());
EXPECT_THAT(callback3.WaitForResult(), IsOk());
EXPECT_TRUE(handle3.is_initialized());
EXPECT_TRUE(handle3.socket());
EXPECT_EQ(1, handle3.group_generation());
handle2.Reset();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, pool_->IdleSocketCount());
handle3.Reset();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, pool_->IdleSocketCount());
}
INSTANTIATE_TEST_SUITE_P(
All,
TransportClientSocketPoolSSLConfigChangeTest,
testing::Values(
SSLClientContext::SSLConfigChangeType::kSSLConfigChanged,
SSLClientContext::SSLConfigChangeType::kCertDatabaseChanged,
SSLClientContext::SSLConfigChangeType::kCertVerifierChanged));
TEST_F(TransportClientSocketPoolTest, BackupSocketConnect) {
MockTransportClientSocketFactory::Rule rules1[] = {
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kStalled),
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kSynchronous),
};
MockTransportClientSocketFactory::Rule rules2[] = {
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kDelayed),
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kStalled),
};
base::span<const MockTransportClientSocketFactory::Rule> cases[2] = {rules1,
rules2};
for (auto rules : cases) {
client_socket_factory_.SetRules(rules);
EXPECT_EQ(0, pool_->IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv = handle.Init(
group_id_, params_, absl::nullopt , LOW,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
base::RunLoop().RunUntilIdle();
base::PlatformThread::Sleep(
base::Milliseconds(ClientSocketPool::kMaxConnectRetryIntervalMs + 50));
base::RunLoop().RunUntilIdle();
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
EXPECT_EQ(0, pool_->IdleSocketCount());
handle.Reset();
pool_->FlushWithError(ERR_NETWORK_CHANGED, "Network changed");
}
}
TEST_F(TransportClientSocketPoolTest, BackupSocketCancel) {
client_socket_factory_.set_default_client_socket_type(
MockTransportClientSocketFactory::Type::kStalled);
enum { CANCEL_BEFORE_WAIT, CANCEL_AFTER_WAIT };
for (int index = CANCEL_BEFORE_WAIT; index < CANCEL_AFTER_WAIT; ++index) {
EXPECT_EQ(0, pool_->IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv = handle.Init(
group_id_, params_, absl::nullopt , LOW,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
base::RunLoop().RunUntilIdle();
if (index == CANCEL_AFTER_WAIT) {
base::PlatformThread::Sleep(
base::Milliseconds(ClientSocketPool::kMaxConnectRetryIntervalMs));
}
base::RunLoop().RunUntilIdle();
handle.Reset();
EXPECT_FALSE(callback.have_result());
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_EQ(0, pool_->IdleSocketCount());
}
}
TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterStall) {
MockTransportClientSocketFactory::Rule rules[] = {
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kStalled),
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kFailing),
};
client_socket_factory_.SetRules(rules);
EXPECT_EQ(0, pool_->IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv =
handle.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
base::RunLoop().RunUntilIdle();
base::PlatformThread::Sleep(
base::Milliseconds(ClientSocketPool::kMaxConnectRetryIntervalMs));
session_deps_.host_resolver->set_synchronous_mode(true);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_THAT(handle.connection_attempts()[0].result,
IsError(ERR_CONNECTION_FAILED));
EXPECT_EQ(0, pool_->IdleSocketCount());
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, BackupSocketFailAfterDelay) {
MockTransportClientSocketFactory::Rule rules[] = {
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kDelayed),
MockTransportClientSocketFactory::Rule(
MockTransportClientSocketFactory::Type::kFailing),
};
client_socket_factory_.SetRules(rules);
client_socket_factory_.set_delay(base::Seconds(5));
EXPECT_EQ(0, pool_->IdleSocketCount());
TestCompletionCallback callback;
ClientSocketHandle handle;
int rv =
handle.Init(group_id_, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
base::RunLoop().RunUntilIdle();
base::PlatformThread::Sleep(
base::Milliseconds(ClientSocketPool::kMaxConnectRetryIntervalMs));
session_deps_.host_resolver->set_synchronous_mode(true);
base::RunLoop().RunUntilIdle();
EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
ASSERT_EQ(1u, handle.connection_attempts().size());
EXPECT_THAT(handle.connection_attempts()[0].result,
IsError(ERR_CONNECTION_FAILED));
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, SOCKS) {
const url::SchemeHostPort kDestination(url::kHttpScheme, "host", 80);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer("socks5://foopy",
ProxyServer::SCHEME_HTTP ),
false , tagging_common_connect_job_params_.get());
for (IoMode socket_io_mode : {SYNCHRONOUS, ASYNC}) {
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr );
SOCKS5MockData data(socket_io_mode);
data.data_provider()->set_connect_data(MockConnect(socket_io_mode, OK));
tagging_client_socket_factory_.AddSocketDataProvider(data.data_provider());
ClientSocketHandle handle;
TestCompletionCallback callback;
int rv = handle.Init(
ClientSocketPool::GroupId(
kDestination, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow),
socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(data.data_provider()->AllReadDataConsumed());
EXPECT_TRUE(data.data_provider()->AllWriteDataConsumed());
}
}
TEST_F(TransportClientSocketPoolTest, SpdyOneConnectJobTwoRequestsError) {
const url::SchemeHostPort kEndpoint(url::kHttpsScheme,
"unresolvable.host.name", 443);
session_deps_.host_resolver->set_synchronous_mode(true);
TransportClientSocketPool pool(
1, 1, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer("https://unresolvable.proxy.name",
ProxyServer::SCHEME_HTTP ),
false , tagging_common_connect_job_params_.get());
SpdyTestUtil spdy_util;
spdy::SpdySerializedFrame connect(spdy_util.ConstructSpdyConnect(
nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair::FromSchemeHostPort(kEndpoint)));
MockWrite writes[] = {
CreateMockWrite(connect, 0, ASYNC),
MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 2),
};
MockRead reads[] = {
MockRead(ASYNC, ERR_FAILED, 1),
};
SequencedSocketData socket_data(MockConnect(SYNCHRONOUS, OK), reads, writes);
tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
SSLSocketDataProvider ssl_data(SYNCHRONOUS, OK);
ssl_data.next_proto = kProtoHTTP2;
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data);
SequencedSocketData socket_data2(
MockConnect(SYNCHRONOUS, ERR_CONNECTION_TIMED_OUT),
base::span<const MockRead>(), base::span<const MockWrite>());
tagging_client_socket_factory_.AddSocketDataProvider(&socket_data2);
SSLSocketDataProvider ssl_data2(SYNCHRONOUS, OK);
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data2);
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::make_unique<SSLConfig>() ,
std::make_unique<SSLConfig>() );
ClientSocketPool::GroupId group_id(
kEndpoint, PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
TestCompletionCallback callback1;
ClientSocketHandle handle1;
int rv1 = handle1.Init(
group_id, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, HIGHEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(), &pool,
NetLogWithSource());
ASSERT_THAT(rv1, IsError(ERR_IO_PENDING));
TestCompletionCallback callback2;
ClientSocketHandle handle2;
int rv2 = handle2.Init(
group_id, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOWEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(), &pool,
NetLogWithSource());
ASSERT_THAT(rv2, IsError(ERR_IO_PENDING));
ASSERT_THAT(callback1.WaitForResult(), IsError(ERR_FAILED));
ASSERT_THAT(callback2.WaitForResult(), IsError(ERR_PROXY_CONNECTION_FAILED));
}
TEST_F(TransportClientSocketPoolTest, SpdyAuthOneConnectJobTwoRequests) {
const url::SchemeHostPort kEndpoint(url::kHttpsScheme,
"unresolvable.host.name", 443);
const HostPortPair kProxy("unresolvable.proxy.name", 443);
session_deps_.host_resolver->set_synchronous_mode(true);
TransportClientSocketPool pool(
1, 1, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer("https://unresolvable.proxy.name",
ProxyServer::SCHEME_HTTP ),
false , tagging_common_connect_job_params_.get());
SpdyTestUtil spdy_util;
spdy::SpdySerializedFrame connect(spdy_util.ConstructSpdyConnect(
nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
HostPortPair::FromSchemeHostPort(kEndpoint)));
MockWrite writes[] = {
CreateMockWrite(connect, 0, ASYNC),
MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 4),
};
const char kAuthStatus[] = "407";
const char* const kAuthChallenge[] = {
"proxy-authenticate",
"NTLM",
};
spdy::SpdySerializedFrame connect_auth_resp(spdy_util.ConstructSpdyReplyError(
kAuthStatus, kAuthChallenge, std::size(kAuthChallenge) / 2, 1));
spdy::SpdySerializedFrame reset(
spdy_util.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
MockRead reads[] = {
CreateMockRead(connect_auth_resp, 1, ASYNC),
CreateMockRead(reset, 2, SYNCHRONOUS),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
};
SequencedSocketData socket_data(MockConnect(SYNCHRONOUS, OK), reads, writes);
tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
SSLSocketDataProvider ssl_data(SYNCHRONOUS, OK);
ssl_data.next_proto = kProtoHTTP2;
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data);
SequencedSocketData socket_data2(
MockConnect(SYNCHRONOUS, ERR_CONNECTION_TIMED_OUT),
base::span<const MockRead>(), base::span<const MockWrite>());
tagging_client_socket_factory_.AddSocketDataProvider(&socket_data2);
SSLSocketDataProvider ssl_data2(SYNCHRONOUS, OK);
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data2);
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::make_unique<SSLConfig>() ,
std::make_unique<SSLConfig>() );
ClientSocketPool::GroupId group_id(
kEndpoint, PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
TestCompletionCallback callback1;
ClientSocketHandle handle1;
base::RunLoop run_loop;
int rv1 = handle1.Init(group_id, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS,
HIGHEST, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(),
base::BindLambdaForTesting(
[&](const HttpResponseInfo& response,
HttpAuthController* auth_controller,
base::OnceClosure restart_with_auth_callback) {
run_loop.Quit();
}),
&pool, NetLogWithSource());
ASSERT_THAT(rv1, IsError(ERR_IO_PENDING));
TestCompletionCallback callback2;
ClientSocketHandle handle2;
int rv2 = handle2.Init(
group_id, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOWEST,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(), &pool,
NetLogWithSource());
ASSERT_THAT(rv2, IsError(ERR_IO_PENDING));
run_loop.Run();
}
TEST_F(TransportClientSocketPoolTest, HttpTunnelSetupRedirect) {
const url::SchemeHostPort kEndpoint(url::kHttpsScheme, "host.test", 443);
const std::string kRedirectTarget = "https://some.other.host.test/";
const std::string kResponseText =
"HTTP/1.1 302 Found\r\n"
"Location: " +
kRedirectTarget +
"\r\n"
"Set-Cookie: foo=bar\r\n"
"\r\n";
for (IoMode io_mode : {SYNCHRONOUS, ASYNC}) {
SCOPED_TRACE(io_mode);
session_deps_.host_resolver->set_synchronous_mode(io_mode == SYNCHRONOUS);
for (bool use_https_proxy : {false, true}) {
SCOPED_TRACE(use_https_proxy);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer(
use_https_proxy ? "https://proxy.test" : "http://proxy.test",
ProxyServer::SCHEME_HTTP ),
false ,
tagging_common_connect_job_params_.get());
MockWrite writes[] = {
MockWrite(ASYNC, 0,
"CONNECT host.test:443 HTTP/1.1\r\n"
"Host: host.test:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n"),
};
MockRead reads[] = {
MockRead(ASYNC, 1, kResponseText.c_str()),
};
SequencedSocketData data(reads, writes);
tagging_client_socket_factory_.AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(ASYNC, OK);
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl);
ClientSocketHandle handle;
TestCompletionCallback callback;
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::make_unique<SSLConfig>() ,
std::make_unique<SSLConfig>() );
int rv = handle.Init(
ClientSocketPool::GroupId(
kEndpoint, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow),
socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool,
NetLogWithSource());
rv = callback.GetResult(rv);
EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
EXPECT_FALSE(handle.is_initialized());
}
}
}
TEST_F(TransportClientSocketPoolTest, NetworkAnonymizationKey) {
const SchemefulSite kSite(GURL("https://foo.test/"));
const auto kNetworkAnonymizationKey =
NetworkAnonymizationKey::CreateSameSite(kSite);
const char kHost[] = "bar.test";
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPartitionConnectionsByNetworkIsolationKey,
features::kSplitHostCacheByNetworkIsolationKey},
{});
session_deps_.host_resolver->set_ondemand_mode(true);
TransportClientSocketPool::GroupId group_id(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle;
TestCompletionCallback callback;
EXPECT_THAT(
handle.Init(group_id,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()),
IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kHost, session_deps_.host_resolver->request_host(1));
EXPECT_EQ(kNetworkAnonymizationKey,
session_deps_.host_resolver->request_network_anonymization_key(1));
}
TEST_F(TransportClientSocketPoolTest, NetworkIsolationKeySsl) {
const SchemefulSite kSite(GURL("https://foo.test/"));
const auto kNetworkAnonymizationKey =
NetworkAnonymizationKey::CreateSameSite(kSite);
const char kHost[] = "bar.test";
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPartitionConnectionsByNetworkIsolationKey,
features::kSplitHostCacheByNetworkIsolationKey},
{});
session_deps_.host_resolver->set_ondemand_mode(true);
TransportClientSocketPool::GroupId group_id(
url::SchemeHostPort(url::kHttpsScheme, kHost, 443),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey,
SecureDnsPolicy::kAllow);
auto ssl_config_for_origin = std::make_unique<SSLConfig>();
ssl_config_for_origin->alpn_protos = {kProtoHTTP2, kProtoHTTP11};
ClientSocketHandle handle;
TestCompletionCallback callback;
EXPECT_THAT(
handle.Init(group_id,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::move(ssl_config_for_origin),
nullptr),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_.get(),
NetLogWithSource()),
IsError(ERR_IO_PENDING));
ASSERT_EQ(1u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kHost, session_deps_.host_resolver->request_host(1));
EXPECT_EQ(kNetworkAnonymizationKey,
session_deps_.host_resolver->request_network_anonymization_key(1));
}
TEST_F(TransportClientSocketPoolTest, NetworkIsolationKeyHttpProxy) {
const SchemefulSite kSite1(GURL("https://foo.test/"));
const auto kNetworkAnonymizationKey1 =
NetworkAnonymizationKey::CreateSameSite(kSite1);
const SchemefulSite kSite2(GURL("https://bar.test/"));
const auto kNetworkAnonymizationKey2 =
NetworkAnonymizationKey::CreateSameSite(kSite2);
const char kHost[] = "bar.test";
const ProxyServer kProxyServer = ProxyUriToProxyServer(
"http://proxy.test", ProxyServer::SCHEME_HTTP );
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPartitionConnectionsByNetworkIsolationKey,
features::kSplitHostCacheByNetworkIsolationKey},
{});
session_deps_.host_resolver->set_ondemand_mode(true);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout, kProxyServer,
false , tagging_common_connect_job_params_.get());
TransportClientSocketPool::GroupId group_id1(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey1,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle1;
TestCompletionCallback callback1;
EXPECT_THAT(
handle1.Init(group_id1,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
TransportClientSocketPool::GroupId group_id2(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey2,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle2;
TestCompletionCallback callback2;
EXPECT_THAT(
handle2.Init(group_id2,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
ASSERT_EQ(2u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(1));
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(2));
EXPECT_TRUE(session_deps_.host_resolver->request_network_anonymization_key(1)
.IsTransient());
EXPECT_EQ(session_deps_.host_resolver->request_network_anonymization_key(1),
session_deps_.host_resolver->request_network_anonymization_key(2));
}
TEST_F(TransportClientSocketPoolTest, NetworkIsolationKeyHttpsProxy) {
const SchemefulSite kSite1(GURL("https://foo.test/"));
const auto kNetworkAnonymizationKey1 =
NetworkAnonymizationKey::CreateSameSite(kSite1);
const SchemefulSite kSite2(GURL("https://bar.test/"));
const auto kNetworkAnonymizationKey2 =
NetworkAnonymizationKey::CreateSameSite(kSite2);
const char kHost[] = "bar.test";
const ProxyServer kProxyServer = ProxyUriToProxyServer(
"https://proxy.test", ProxyServer::SCHEME_HTTP );
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPartitionConnectionsByNetworkIsolationKey,
features::kSplitHostCacheByNetworkIsolationKey},
{});
session_deps_.host_resolver->set_ondemand_mode(true);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout, kProxyServer,
false , tagging_common_connect_job_params_.get());
TransportClientSocketPool::GroupId group_id1(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey1,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle1;
TestCompletionCallback callback1;
EXPECT_THAT(handle1.Init(
group_id1,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
std::make_unique<SSLConfig>() ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
TransportClientSocketPool::GroupId group_id2(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey2,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle2;
TestCompletionCallback callback2;
EXPECT_THAT(handle2.Init(
group_id2,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
std::make_unique<SSLConfig>() ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
ASSERT_EQ(2u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(1));
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(2));
EXPECT_TRUE(session_deps_.host_resolver->request_network_anonymization_key(1)
.IsTransient());
EXPECT_EQ(session_deps_.host_resolver->request_network_anonymization_key(1),
session_deps_.host_resolver->request_network_anonymization_key(2));
}
TEST_F(TransportClientSocketPoolTest, NetworkIsolationKeySocks4Proxy) {
const SchemefulSite kSite1(GURL("https://foo.test/"));
const auto kNetworkAnonymizationKey1 =
NetworkAnonymizationKey::CreateSameSite(kSite1);
const SchemefulSite kSite2(GURL("https://bar.test/"));
const auto kNetworkAnonymizationKey2 =
NetworkAnonymizationKey::CreateSameSite(kSite2);
const char kHost[] = "bar.test";
const ProxyServer kProxyServer = ProxyUriToProxyServer(
"socks4://proxy.test", ProxyServer::SCHEME_HTTP );
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPartitionConnectionsByNetworkIsolationKey,
features::kSplitHostCacheByNetworkIsolationKey},
{});
session_deps_.host_resolver->set_ondemand_mode(true);
StaticSocketDataProvider data1;
data1.set_connect_data(MockConnect(SYNCHRONOUS, OK));
tagging_client_socket_factory_.AddSocketDataProvider(&data1);
StaticSocketDataProvider data2;
data2.set_connect_data(MockConnect(SYNCHRONOUS, OK));
tagging_client_socket_factory_.AddSocketDataProvider(&data2);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout, kProxyServer,
false , tagging_common_connect_job_params_.get());
TransportClientSocketPool::GroupId group_id1(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey1,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle1;
TestCompletionCallback callback1;
EXPECT_THAT(
handle1.Init(group_id1,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
TransportClientSocketPool::GroupId group_id2(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey2,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle2;
TestCompletionCallback callback2;
EXPECT_THAT(
handle2.Init(group_id2,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
ASSERT_EQ(2u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(1));
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(2));
EXPECT_TRUE(session_deps_.host_resolver->request_network_anonymization_key(1)
.IsTransient());
EXPECT_EQ(session_deps_.host_resolver->request_network_anonymization_key(1),
session_deps_.host_resolver->request_network_anonymization_key(2));
session_deps_.host_resolver->ResolveNow(1);
session_deps_.host_resolver->ResolveNow(2);
ASSERT_EQ(4u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kHost, session_deps_.host_resolver->request_host(3));
EXPECT_EQ(kNetworkAnonymizationKey1,
session_deps_.host_resolver->request_network_anonymization_key(3));
EXPECT_EQ(kHost, session_deps_.host_resolver->request_host(4));
EXPECT_EQ(kNetworkAnonymizationKey2,
session_deps_.host_resolver->request_network_anonymization_key(4));
}
TEST_F(TransportClientSocketPoolTest, NetworkIsolationKeySocks5Proxy) {
const SchemefulSite kSite1(GURL("https://foo.test/"));
const auto kNetworkAnonymizationKey1 =
NetworkAnonymizationKey::CreateSameSite(kSite1);
const SchemefulSite kSite2(GURL("https://bar.test/"));
const auto kNetworkAnonymizationKey2 =
NetworkAnonymizationKey::CreateSameSite(kSite2);
const char kHost[] = "bar.test";
const ProxyServer kProxyServer = ProxyUriToProxyServer(
"socks5://proxy.test", ProxyServer::SCHEME_HTTP );
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPartitionConnectionsByNetworkIsolationKey,
features::kSplitHostCacheByNetworkIsolationKey},
{});
session_deps_.host_resolver->set_ondemand_mode(true);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout, kProxyServer,
false , tagging_common_connect_job_params_.get());
TransportClientSocketPool::GroupId group_id1(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey1,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle1;
TestCompletionCallback callback1;
EXPECT_THAT(
handle1.Init(group_id1,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
TransportClientSocketPool::GroupId group_id2(
url::SchemeHostPort(url::kHttpScheme, kHost, 80),
PrivacyMode::PRIVACY_MODE_DISABLED, kNetworkAnonymizationKey2,
SecureDnsPolicy::kAllow);
ClientSocketHandle handle2;
TestCompletionCallback callback2;
EXPECT_THAT(
handle2.Init(group_id2,
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr ),
TRAFFIC_ANNOTATION_FOR_TESTS, LOW, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource()),
IsError(ERR_IO_PENDING));
ASSERT_EQ(2u, session_deps_.host_resolver->last_id());
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(1));
EXPECT_EQ(kProxyServer.host_port_pair().host(),
session_deps_.host_resolver->request_host(2));
EXPECT_TRUE(session_deps_.host_resolver->request_network_anonymization_key(1)
.IsTransient());
EXPECT_EQ(session_deps_.host_resolver->request_network_anonymization_key(1),
session_deps_.host_resolver->request_network_anonymization_key(2));
}
TEST_F(TransportClientSocketPoolTest, HasActiveSocket) {
const url::SchemeHostPort kEndpoint1(url::kHttpScheme, "host1.test", 80);
const url::SchemeHostPort kEndpoint2(url::kHttpScheme, "host2.test", 80);
ClientSocketHandle handle;
ClientSocketPool::GroupId group_id1(
kEndpoint1, PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
ClientSocketPool::GroupId group_id2(
kEndpoint2, PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
EXPECT_FALSE(pool_->HasActiveSocket(group_id1));
TestCompletionCallback callback1;
int rv1 =
handle.Init(group_id1, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback1.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv1, IsError(ERR_IO_PENDING));
EXPECT_TRUE(pool_->HasActiveSocket(group_id1));
EXPECT_FALSE(handle.is_initialized());
EXPECT_FALSE(handle.socket());
EXPECT_THAT(callback1.WaitForResult(), IsOk());
EXPECT_TRUE(pool_->HasActiveSocket(group_id1));
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
handle.Reset();
EXPECT_TRUE(pool_->HasActiveSocket(group_id1));
EXPECT_EQ(1, pool_->IdleSocketCount());
EXPECT_FALSE(pool_->HasActiveSocket(group_id2));
TestCompletionCallback callback2;
int rv2 =
handle.Init(group_id2, params_, absl::nullopt ,
LOW, SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_.get(), NetLogWithSource());
EXPECT_THAT(rv2, IsError(ERR_IO_PENDING));
EXPECT_TRUE(pool_->HasActiveSocket(group_id2));
EXPECT_TRUE(pool_->HasActiveSocket(group_id2));
pool_->FlushWithError(ERR_NETWORK_CHANGED, "Network changed");
EXPECT_FALSE(pool_->HasActiveSocket(group_id1));
EXPECT_FALSE(pool_->HasActiveSocket(group_id2));
}
#if BUILDFLAG(IS_ANDROID)
TEST_F(TransportClientSocketPoolTest, Tag) {
if (!CanGetTaggedBytes()) {
DVLOG(0) << "Skipping test - GetTaggedBytes unsupported.";
return;
}
EmbeddedTestServer test_server;
test_server.AddDefaultHandlers(base::FilePath());
ASSERT_TRUE(test_server.Start());
ClientSocketHandle handle;
int32_t tag_val1 = 0x12345678;
SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
int32_t tag_val2 = 0x87654321;
SocketTag tag2(getuid(), tag_val2);
uint64_t old_traffic = GetTaggedBytes(tag_val1);
const ClientSocketPool::GroupId kGroupId(
url::SchemeHostPort(test_server.base_url()),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
scoped_refptr<ClientSocketPool::SocketParams> params =
ClientSocketPool::SocketParams::CreateForHttpForTesting();
TestCompletionCallback callback;
int rv =
handle.Init(kGroupId, params, absl::nullopt ,
LOW, tag1, ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic);
StreamSocket* socket = handle.socket();
handle.Reset();
old_traffic = GetTaggedBytes(tag_val2);
rv = handle.Init(kGroupId, params, absl::nullopt ,
LOW, tag2, ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(handle.socket(), socket);
const char kRequest[] = "GET / HTTP/1.0\n\n";
scoped_refptr<IOBuffer> write_buffer =
base::MakeRefCounted<StringIOBuffer>(kRequest);
rv =
handle.socket()->Write(write_buffer.get(), strlen(kRequest),
callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv));
EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
handle.socket()->Disconnect();
handle.Reset();
TestCompletionCallback callback2;
rv = handle.Init(kGroupId, params, absl::nullopt ,
LOW, tag1, ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv;
handle.Reset();
rv = handle.Init(kGroupId, params, absl::nullopt ,
LOW, tag2, ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
old_traffic = GetTaggedBytes(tag_val2);
rv =
handle.socket()->Write(write_buffer.get(), strlen(kRequest),
callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv));
EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
handle.socket()->Disconnect();
handle.Reset();
rv = handle.Init(kGroupId, params, absl::nullopt ,
LOW, tag1, ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsOk());
handle.socket()->Disconnect();
handle.Reset();
ClientSocketHandle handle_high_pri;
TestCompletionCallback callback_high_pri;
rv = handle.Init(kGroupId, params, absl::nullopt ,
LOW, tag1, ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv;
int rv_high_pri = handle_high_pri.Init(
kGroupId, params, absl::nullopt , HIGHEST, tag2,
ClientSocketPool::RespectLimits::ENABLED, callback_high_pri.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_for_real_sockets_.get(),
NetLogWithSource());
EXPECT_THAT(callback_high_pri.GetResult(rv_high_pri), IsOk());
EXPECT_TRUE(handle_high_pri.socket());
EXPECT_TRUE(handle_high_pri.socket()->IsConnected());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
old_traffic = GetTaggedBytes(tag_val2);
rv = handle_high_pri.socket()->Write(write_buffer.get(), strlen(kRequest),
callback.callback(),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv));
EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
old_traffic = GetTaggedBytes(tag_val1);
rv =
handle.socket()->Write(write_buffer.get(), strlen(kRequest),
callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv));
EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic);
}
TEST_F(TransportClientSocketPoolTest, TagSOCKSProxy) {
session_deps_.host_resolver->set_synchronous_mode(true);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer("socks5://proxy",
ProxyServer::SCHEME_HTTP ),
false , tagging_common_connect_job_params_.get());
SocketTag tag1(SocketTag::UNSET_UID, 0x12345678);
SocketTag tag2(getuid(), 0x87654321);
const url::SchemeHostPort kDestination(url::kHttpScheme, "host", 80);
const ClientSocketPool::GroupId kGroupId(
kDestination, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow);
scoped_refptr<ClientSocketPool::SocketParams> socks_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr );
SOCKS5MockData data_sync(SYNCHRONOUS);
data_sync.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS, OK));
tagging_client_socket_factory_.AddSocketDataProvider(
data_sync.data_provider());
ClientSocketHandle handle;
int rv = handle.Init(
kGroupId, socks_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag1,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag1);
EXPECT_TRUE(tagging_client_socket_factory_.GetLastProducedTCPSocket()
->tagged_before_connected());
StreamSocket* socket = handle.socket();
handle.Reset();
rv = handle.Init(
kGroupId, socks_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(handle.socket(), socket);
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag2);
handle.socket()->Disconnect();
handle.Reset();
SOCKS5MockData data_async(ASYNC);
tagging_client_socket_factory_.AddSocketDataProvider(
data_async.data_provider());
TestCompletionCallback callback;
rv = handle.Init(kGroupId, socks_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW,
tag1, ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
&proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.is_initialized());
EXPECT_TRUE(handle.socket());
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag1);
EXPECT_TRUE(tagging_client_socket_factory_.GetLastProducedTCPSocket()
->tagged_before_connected());
socket = handle.socket();
handle.Reset();
rv = handle.Init(
kGroupId, socks_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(handle.socket(), socket);
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag2);
}
TEST_F(TransportClientSocketPoolTest, TagSSLDirect) {
if (!CanGetTaggedBytes()) {
DVLOG(0) << "Skipping test - GetTaggedBytes unsupported.";
return;
}
EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, SSLServerConfig());
test_server.AddDefaultHandlers(base::FilePath());
ASSERT_TRUE(test_server.Start());
TestCompletionCallback callback;
ClientSocketHandle handle;
int32_t tag_val1 = 0x12345678;
SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
int32_t tag_val2 = 0x87654321;
SocketTag tag2(getuid(), tag_val2);
const ClientSocketPool::GroupId kGroupId(
url::SchemeHostPort(test_server.base_url()),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
auto ssl_config_for_origin = std::make_unique<SSLConfig>();
ssl_config_for_origin->alpn_protos = {kProtoHTTP2, kProtoHTTP11};
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::move(ssl_config_for_origin),
nullptr);
uint64_t old_traffic = GetTaggedBytes(tag_val1);
int rv = handle.Init(
kGroupId, socket_params, absl::nullopt , LOW,
tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_for_real_sockets_.get(),
NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_GT(GetTaggedBytes(tag_val1), old_traffic);
StreamSocket* socket = handle.socket();
handle.Reset();
old_traffic = GetTaggedBytes(tag_val2);
TestCompletionCallback callback2;
rv = handle.Init(kGroupId, socket_params,
absl::nullopt , LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(handle.socket(), socket);
const char kRequest[] = "GET / HTTP/1.1\r\n\r\n";
scoped_refptr<IOBuffer> write_buffer =
base::MakeRefCounted<StringIOBuffer>(kRequest);
rv =
handle.socket()->Write(write_buffer.get(), strlen(kRequest),
callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv));
scoped_refptr<IOBufferWithSize> read_buffer =
base::MakeRefCounted<IOBufferWithSize>(1);
rv = handle.socket()->Read(read_buffer.get(), read_buffer->size(),
callback.callback());
EXPECT_EQ(read_buffer->size(), callback.GetResult(rv));
EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
handle.socket()->Disconnect();
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, TagSSLDirectTwoSockets) {
if (!CanGetTaggedBytes()) {
DVLOG(0) << "Skipping test - GetTaggedBytes unsupported.";
return;
}
EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, SSLServerConfig());
test_server.AddDefaultHandlers(base::FilePath());
ASSERT_TRUE(test_server.Start());
ClientSocketHandle handle;
int32_t tag_val1 = 0x12345678;
SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
int32_t tag_val2 = 0x87654321;
SocketTag tag2(getuid(), tag_val2);
const ClientSocketPool::GroupId kGroupId(
url::SchemeHostPort(test_server.base_url()),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
auto ssl_config_for_origin = std::make_unique<SSLConfig>();
ssl_config_for_origin->alpn_protos = {kProtoHTTP2, kProtoHTTP11};
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::move(ssl_config_for_origin),
nullptr);
TestCompletionCallback callback;
int rv = handle.Init(
kGroupId, socket_params, absl::nullopt , LOW,
tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_for_real_sockets_.get(),
NetLogWithSource());
EXPECT_TRUE(rv == OK || rv == ERR_IO_PENDING) << "Result: " << rv;
handle.Reset();
TestCompletionCallback callback2;
rv = handle.Init(kGroupId, socket_params,
absl::nullopt , LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED,
callback2.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(callback2.GetResult(rv), IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
uint64_t old_traffic = GetTaggedBytes(tag_val2);
const char kRequest[] = "GET / HTTP/1.1\r\n\r\n";
scoped_refptr<IOBuffer> write_buffer =
base::MakeRefCounted<StringIOBuffer>(kRequest);
rv = handle.socket()->Write(write_buffer.get(), strlen(kRequest),
callback2.callback(),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback2.GetResult(rv));
scoped_refptr<IOBufferWithSize> read_buffer =
base::MakeRefCounted<IOBufferWithSize>(1);
rv = handle.socket()->Read(read_buffer.get(), read_buffer->size(),
callback2.callback());
EXPECT_EQ(read_buffer->size(), callback2.GetResult(rv));
EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
}
TEST_F(TransportClientSocketPoolTest, TagSSLDirectTwoSocketsFullPool) {
if (!CanGetTaggedBytes()) {
DVLOG(0) << "Skipping test - GetTaggedBytes unsupported.";
return;
}
EmbeddedTestServer test_server(net::EmbeddedTestServer::TYPE_HTTPS);
test_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, SSLServerConfig());
test_server.AddDefaultHandlers(base::FilePath());
ASSERT_TRUE(test_server.Start());
TestCompletionCallback callback;
ClientSocketHandle handle;
int32_t tag_val1 = 0x12345678;
SocketTag tag1(SocketTag::UNSET_UID, tag_val1);
int32_t tag_val2 = 0x87654321;
SocketTag tag2(getuid(), tag_val2);
const ClientSocketPool::GroupId kGroupId(
url::SchemeHostPort(test_server.base_url()),
PrivacyMode::PRIVACY_MODE_DISABLED, NetworkAnonymizationKey(),
SecureDnsPolicy::kAllow);
auto ssl_config_for_origin = std::make_unique<SSLConfig>();
ssl_config_for_origin->alpn_protos = {kProtoHTTP2, kProtoHTTP11};
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::move(ssl_config_for_origin),
nullptr);
ClientSocketHandle tcp_handles[kMaxSocketsPerGroup];
int rv;
for (auto& tcp_handle : tcp_handles) {
rv = tcp_handle.Init(
kGroupId, socket_params, absl::nullopt , LOW,
tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_for_real_sockets_.get(),
NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_TRUE(tcp_handle.socket());
EXPECT_TRUE(tcp_handle.socket()->IsConnected());
}
ClientSocketHandle handle_to_be_canceled;
rv = handle_to_be_canceled.Init(
kGroupId, socket_params, absl::nullopt , LOW,
tag1, ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(), pool_for_real_sockets_.get(),
NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
rv = handle.Init(kGroupId, socket_params,
absl::nullopt , LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
pool_for_real_sockets_.get(), NetLogWithSource());
EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
handle_to_be_canceled.Reset();
tcp_handles[0].socket()->Disconnect();
tcp_handles[0].Reset();
EXPECT_THAT(callback.WaitForResult(), IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
uint64_t old_traffic = GetTaggedBytes(tag_val2);
const char kRequest[] = "GET / HTTP/1.1\r\n\r\n";
scoped_refptr<IOBuffer> write_buffer =
base::MakeRefCounted<StringIOBuffer>(kRequest);
rv =
handle.socket()->Write(write_buffer.get(), strlen(kRequest),
callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(static_cast<int>(strlen(kRequest)), callback.GetResult(rv));
scoped_refptr<IOBufferWithSize> read_buffer =
base::MakeRefCounted<IOBufferWithSize>(1);
EXPECT_EQ(handle.socket()->Read(read_buffer.get(), read_buffer->size(),
callback.callback()),
ERR_IO_PENDING);
EXPECT_THAT(callback.WaitForResult(), read_buffer->size());
EXPECT_GT(GetTaggedBytes(tag_val2), old_traffic);
}
TEST_F(TransportClientSocketPoolTest, TagHttpProxyNoTunnel) {
SocketTag tag1(SocketTag::UNSET_UID, 0x12345678);
SocketTag tag2(getuid(), 0x87654321);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer("http://proxy",
ProxyServer::SCHEME_HTTP ),
false , tagging_common_connect_job_params_.get());
session_deps_.host_resolver->set_synchronous_mode(true);
SequencedSocketData socket_data;
socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
const url::SchemeHostPort kDestination(url::kHttpScheme, "www.google.com",
80);
const ClientSocketPool::GroupId kGroupId(
kDestination, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow);
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr );
ClientSocketHandle handle;
int rv = handle.Init(
kGroupId, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag1,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
ASSERT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag1);
EXPECT_TRUE(tagging_client_socket_factory_.GetLastProducedTCPSocket()
->tagged_before_connected());
StreamSocket* socket = handle.socket();
handle.Reset();
rv = handle.Init(
kGroupId, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(handle.socket(), socket);
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag2);
handle.socket()->Disconnect();
handle.Reset();
}
TEST_F(TransportClientSocketPoolTest, TagHttpProxyTunnel) {
SocketTag tag1(SocketTag::UNSET_UID, 0x12345678);
SocketTag tag2(getuid(), 0x87654321);
TransportClientSocketPool proxy_pool(
kMaxSockets, kMaxSocketsPerGroup, kUnusedIdleSocketTimeout,
ProxyUriToProxyServer("http://proxy",
ProxyServer::SCHEME_HTTP ),
false , tagging_common_connect_job_params_.get());
session_deps_.host_resolver->set_synchronous_mode(true);
std::string request =
"CONNECT www.google.com:443 HTTP/1.1\r\n"
"Host: www.google.com:443\r\n"
"Proxy-Connection: keep-alive\r\n\r\n";
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, 0, request.c_str()),
};
MockRead reads[] = {
MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
};
SequencedSocketData socket_data(MockConnect(SYNCHRONOUS, OK), reads, writes);
tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
SSLSocketDataProvider ssl_data(SYNCHRONOUS, OK);
tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data);
const url::SchemeHostPort kDestination(url::kHttpsScheme, "www.google.com",
443);
const ClientSocketPool::GroupId kGroupId(
kDestination, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow);
auto ssl_config_for_origin = std::make_unique<SSLConfig>();
ssl_config_for_origin->alpn_protos = {kProtoHTTP2, kProtoHTTP11};
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
std::move(ssl_config_for_origin),
nullptr);
ClientSocketHandle handle;
int rv = handle.Init(
kGroupId, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag1,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.is_initialized());
ASSERT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag1);
EXPECT_TRUE(tagging_client_socket_factory_.GetLastProducedTCPSocket()
->tagged_before_connected());
StreamSocket* socket = handle.socket();
handle.Reset();
rv = handle.Init(
kGroupId, socket_params, TRAFFIC_ANNOTATION_FOR_TESTS, LOW, tag2,
ClientSocketPool::RespectLimits::ENABLED, CompletionOnceCallback(),
ClientSocketPool::ProxyAuthCallback(), &proxy_pool, NetLogWithSource());
EXPECT_THAT(rv, IsOk());
EXPECT_TRUE(handle.socket());
EXPECT_TRUE(handle.socket()->IsConnected());
EXPECT_EQ(handle.socket(), socket);
EXPECT_EQ(tagging_client_socket_factory_.GetLastProducedTCPSocket()->tag(),
tag2);
handle.socket()->Disconnect();
handle.Reset();
}
#endif
class TransportClientSocketPoolMockNowSourceTest
: public TransportClientSocketPoolTest {
public:
TransportClientSocketPoolMockNowSourceTest(
const TransportClientSocketPoolMockNowSourceTest&) = delete;
TransportClientSocketPoolMockNowSourceTest& operator=(
const TransportClientSocketPoolMockNowSourceTest&) = delete;
protected:
TransportClientSocketPoolMockNowSourceTest()
: TransportClientSocketPoolTest(
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
};
TEST_F(TransportClientSocketPoolMockNowSourceTest, IdleUnusedSocketTimeout) {
const url::SchemeHostPort kSchemeHostPort1(url::kHttpScheme, "www.foo.com",
80);
const url::SchemeHostPort kSchemeHostPort2(url::kHttpScheme, "www.bar.com",
80);
const struct {
bool use_first_socket;
int fast_forward_seconds;
int unused_idle_socket_timeout_seconds;
bool expect_idle_socket;
} kTests[] = {
{false, 0, 0, false},
{false, 9, 10, true},
{false, 11, 10, false},
{false, 19, 20, true},
{false, 21, 20, false},
{true, 0, 0, true},
{true, 9, 10, true},
{true, 11, 10, true},
{true, 19, 20, true},
{true, 21, 20, true},
};
for (const auto& test : kTests) {
SpdySessionDependencies session_deps(
ConfiguredProxyResolutionService::CreateDirect());
std::unique_ptr<HttpNetworkSession> session(
SpdySessionDependencies::SpdyCreateSession(&session_deps));
base::test::ScopedFeatureList scoped_feature_list_;
std::map<std::string, std::string> parameters;
parameters["unused_idle_socket_timeout_seconds"] =
base::NumberToString(test.unused_idle_socket_timeout_seconds);
scoped_feature_list_.InitAndEnableFeatureWithParameters(
net::features::kNetUnusedIdleSocketTimeout, parameters);
const char kWriteData[] = "1";
const MockWrite kWrites[] = {MockWrite(SYNCHRONOUS, kWriteData)};
SequencedSocketData provider_socket_1(MockConnect(ASYNC, OK),
base::span<MockRead>(), kWrites);
{
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr );
session_deps.socket_factory->AddSocketDataProvider(&provider_socket_1);
ClientSocketHandle connection;
TestCompletionCallback callback;
int rv = connection.Init(
ClientSocketPool::GroupId(
kSchemeHostPort1, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow),
ClientSocketPool::SocketParams::CreateForHttpForTesting(),
absl::nullopt , MEDIUM, SocketTag(),
ClientSocketPool::RespectLimits::ENABLED, callback.callback(),
ClientSocketPool::ProxyAuthCallback(),
session->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
ProxyServer::Direct()),
NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
EXPECT_FALSE(connection.socket()->WasEverUsed());
if (test.use_first_socket) {
auto write_buffer = base::MakeRefCounted<StringIOBuffer>(kWriteData);
TestCompletionCallback write_callback;
rv = connection.socket()->Write(
write_buffer.get(), write_buffer->size(), write_callback.callback(),
TRAFFIC_ANNOTATION_FOR_TESTS);
EXPECT_EQ(rv, 1);
EXPECT_TRUE(connection.socket()->WasEverUsed());
}
}
EXPECT_EQ(1, session
->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
ProxyServer::Direct())
->IdleSocketCount());
FastForwardBy(base::Seconds(test.fast_forward_seconds));
{
scoped_refptr<ClientSocketPool::SocketParams> socket_params =
base::MakeRefCounted<ClientSocketPool::SocketParams>(
nullptr ,
nullptr );
SequencedSocketData provider_socket_2(MockConnect(ASYNC, OK),
base::span<MockRead>(),
base::span<MockWrite>());
session_deps.socket_factory->AddSocketDataProvider(&provider_socket_2);
ClientSocketHandle connection;
TestCompletionCallback callback;
int rv = connection.Init(
ClientSocketPool::GroupId(
kSchemeHostPort2, PrivacyMode::PRIVACY_MODE_DISABLED,
NetworkAnonymizationKey(), SecureDnsPolicy::kAllow),
socket_params, absl::nullopt , MEDIUM,
SocketTag(), ClientSocketPool::RespectLimits::ENABLED,
callback.callback(), ClientSocketPool::ProxyAuthCallback(),
session->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
ProxyServer::Direct()),
NetLogWithSource());
EXPECT_THAT(callback.GetResult(rv), IsOk());
connection.socket()->Disconnect();
}
EXPECT_EQ(test.expect_idle_socket ? 1 : 0,
session
->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
ProxyServer::Direct())
->IdleSocketCount());
}
}
}
}