blob: 95a093a9492e775d73993ea5097f7ab691b0a817 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/quic_stream_factory.h"
#include <ostream>
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/test_data_directory.h"
#include "net/cert/cert_verifier.h"
#include "net/cert/multi_log_ct_verifier.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_util.h"
#include "net/http/transport_security_state.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/proof_verifier_chromium.h"
#include "net/quic/crypto/properties_based_quic_server_info.h"
#include "net/quic/crypto/quic_crypto_client_config.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_server_info.h"
#include "net/quic/quic_client_promised_info.h"
#include "net/quic/quic_http_utils.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/mock_crypto_client_stream_factory.h"
#include "net/quic/test_tools/mock_random.h"
#include "net/quic/test_tools/quic_config_peer.h"
#include "net/quic/test_tools/quic_stream_factory_peer.h"
#include "net/quic/test_tools/quic_test_packet_maker.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/test_task_runner.h"
#include "net/socket/socket_test_util.h"
#include "net/spdy/spdy_session_test_util.h"
#include "net/spdy/spdy_test_utils.h"
#include "net/ssl/channel_id_service.h"
#include "net/ssl/default_channel_id_store.h"
#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using std::string;
using std::vector;
namespace net {
namespace test {
namespace {
enum DestinationType {
// In pooling tests with two requests for different origins to the same
// destination, the destination should be
SAME_AS_FIRST, // the same as the first origin,
SAME_AS_SECOND, // the same as the second origin, or
DIFFERENT, // different from both.
};
const char kDefaultServerHostName[] = "www.example.org";
const char kServer2HostName[] = "mail.example.org";
const char kServer3HostName[] = "docs.example.org";
const char kServer4HostName[] = "images.example.org";
const char kDifferentHostname[] = "different.example.com";
const int kDefaultServerPort = 443;
const char kDefaultUrl[] = "https://www.example.org/";
const char kServer2Url[] = "https://mail.example.org/";
const char kServer3Url[] = "https://docs.example.org/";
const char kServer4Url[] = "https://images.example.org/";
// Run QuicStreamFactoryTest instances with all value combinations of version
// and enable_connection_racting.
struct TestParams {
friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
os << "{ version: " << QuicVersionToString(p.version)
<< ", enable_connection_racing: "
<< (p.enable_connection_racing ? "true" : "false") << " }";
return os;
}
QuicVersion version;
bool enable_connection_racing;
};
vector<TestParams> GetTestParams() {
vector<TestParams> params;
QuicVersionVector all_supported_versions = QuicSupportedVersions();
for (const QuicVersion version : all_supported_versions) {
params.push_back(TestParams{version, false});
params.push_back(TestParams{version, true});
}
return params;
}
// Run QuicStreamFactoryWithDestinationTest instances with all value
// combinations of version, enable_connection_racting, and destination_type.
struct PoolingTestParams {
friend std::ostream& operator<<(std::ostream& os,
const PoolingTestParams& p) {
os << "{ version: " << QuicVersionToString(p.version)
<< ", enable_connection_racing: "
<< (p.enable_connection_racing ? "true" : "false")
<< ", destination_type: ";
switch (p.destination_type) {
case SAME_AS_FIRST:
os << "SAME_AS_FIRST";
break;
case SAME_AS_SECOND:
os << "SAME_AS_SECOND";
break;
case DIFFERENT:
os << "DIFFERENT";
break;
}
os << " }";
return os;
}
QuicVersion version;
bool enable_connection_racing;
DestinationType destination_type;
};
vector<PoolingTestParams> GetPoolingTestParams() {
vector<PoolingTestParams> params;
QuicVersionVector all_supported_versions = QuicSupportedVersions();
for (const QuicVersion version : all_supported_versions) {
params.push_back(PoolingTestParams{version, false, SAME_AS_FIRST});
params.push_back(PoolingTestParams{version, false, SAME_AS_SECOND});
params.push_back(PoolingTestParams{version, false, DIFFERENT});
params.push_back(PoolingTestParams{version, true, SAME_AS_FIRST});
params.push_back(PoolingTestParams{version, true, SAME_AS_SECOND});
params.push_back(PoolingTestParams{version, true, DIFFERENT});
}
return params;
}
} // namespace
class QuicHttpStreamPeer {
public:
static QuicChromiumClientSession* GetSession(QuicHttpStream* stream) {
return stream->session_.get();
}
};
class MockQuicServerInfo : public QuicServerInfo {
public:
explicit MockQuicServerInfo(const QuicServerId& server_id)
: QuicServerInfo(server_id) {}
~MockQuicServerInfo() override {}
void Start() override {}
int WaitForDataReady(const CompletionCallback& callback) override {
return ERR_IO_PENDING;
}
void ResetWaitForDataReadyCallback() override {}
void CancelWaitForDataReadyCallback() override {}
bool IsDataReady() override { return false; }
bool IsReadyToPersist() override { return false; }
void Persist() override {}
void OnExternalCacheHit() override {}
};
class MockQuicServerInfoFactory : public QuicServerInfoFactory {
public:
MockQuicServerInfoFactory() {}
~MockQuicServerInfoFactory() override {}
QuicServerInfo* GetForServer(const QuicServerId& server_id) override {
return new MockQuicServerInfo(server_id);
}
};
class MockNetworkChangeNotifier : public NetworkChangeNotifier {
public:
MockNetworkChangeNotifier() : force_network_handles_supported_(false) {}
ConnectionType GetCurrentConnectionType() const override {
return CONNECTION_UNKNOWN;
}
void ForceNetworkHandlesSupported() {
force_network_handles_supported_ = true;
}
bool AreNetworkHandlesCurrentlySupported() const override {
return force_network_handles_supported_;
}
void SetConnectedNetworksList(const NetworkList& network_list) {
connected_networks_ = network_list;
}
void GetCurrentConnectedNetworks(NetworkList* network_list) const override {
network_list->clear();
*network_list = connected_networks_;
}
void NotifyNetworkSoonToDisconnect(
NetworkChangeNotifier::NetworkHandle network) {
NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
NetworkChangeNotifier::SOON_TO_DISCONNECT, network);
// Spin the message loop so the notification is delivered.
base::MessageLoop::current()->RunUntilIdle();
}
void NotifyNetworkDisconnected(NetworkChangeNotifier::NetworkHandle network) {
NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
NetworkChangeNotifier::DISCONNECTED, network);
// Spin the message loop so the notification is delivered.
base::MessageLoop::current()->RunUntilIdle();
}
private:
bool force_network_handles_supported_;
NetworkChangeNotifier::NetworkList connected_networks_;
};
// Class to replace existing NetworkChangeNotifier singleton with a
// MockNetworkChangeNotifier for a test. To use, simply create a
// ScopedMockNetworkChangeNotifier object in the test.
class ScopedMockNetworkChangeNotifier {
public:
ScopedMockNetworkChangeNotifier()
: disable_network_change_notifier_for_tests_(
new NetworkChangeNotifier::DisableForTest()),
mock_network_change_notifier_(new MockNetworkChangeNotifier()) {}
MockNetworkChangeNotifier* mock_network_change_notifier() {
return mock_network_change_notifier_.get();
}
private:
std::unique_ptr<NetworkChangeNotifier::DisableForTest>
disable_network_change_notifier_for_tests_;
std::unique_ptr<MockNetworkChangeNotifier> mock_network_change_notifier_;
};
class QuicStreamFactoryTestBase {
protected:
QuicStreamFactoryTestBase(QuicVersion version, bool enable_connection_racing)
: random_generator_(0),
clock_(new MockClock()),
runner_(new TestTaskRunner(clock_)),
version_(version),
client_maker_(version_,
0,
clock_,
kDefaultServerHostName,
Perspective::IS_CLIENT),
server_maker_(version_,
0,
clock_,
kDefaultServerHostName,
Perspective::IS_SERVER),
cert_verifier_(CertVerifier::CreateDefault()),
channel_id_service_(
new ChannelIDService(new DefaultChannelIDStore(nullptr),
base::ThreadTaskRunnerHandle::Get())),
cert_transparency_verifier_(new MultiLogCTVerifier()),
scoped_mock_network_change_notifier_(nullptr),
factory_(nullptr),
host_port_pair_(kDefaultServerHostName, kDefaultServerPort),
url_(kDefaultUrl),
url2_(kServer2Url),
url3_(kServer3Url),
url4_(kServer4Url),
privacy_mode_(PRIVACY_MODE_DISABLED),
enable_port_selection_(true),
always_require_handshake_confirmation_(false),
disable_connection_pooling_(false),
load_server_info_timeout_srtt_multiplier_(0.0f),
enable_connection_racing_(enable_connection_racing),
enable_non_blocking_io_(true),
disable_disk_cache_(false),
prefer_aes_(false),
max_number_of_lossy_connections_(0),
packet_loss_threshold_(1.0f),
max_disabled_reasons_(3),
threshold_timeouts_with_open_streams_(2),
threshold_public_resets_post_handshake_(2),
receive_buffer_size_(0),
delay_tcp_race_(true),
close_sessions_on_ip_change_(false),
disable_quic_on_timeout_with_open_streams_(false),
idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds),
migrate_sessions_on_network_change_(false),
migrate_sessions_early_(false) {
clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
~QuicStreamFactoryTestBase() {
// If |factory_| was initialized, then it took over ownership of |clock_|.
// If |factory_| was not initialized, then |clock_| needs to be destroyed.
if (!factory_) {
delete clock_;
}
}
void Initialize() {
DCHECK(!factory_);
factory_.reset(new QuicStreamFactory(
net_log_.net_log(), &host_resolver_, &socket_factory_,
http_server_properties_.GetWeakPtr(), cert_verifier_.get(), nullptr,
channel_id_service_.get(), &transport_security_state_,
cert_transparency_verifier_.get(),
/*SocketPerformanceWatcherFactory*/ nullptr,
&crypto_client_stream_factory_, &random_generator_, clock_,
kDefaultMaxPacketSize, string(), SupportedVersions(version_),
enable_port_selection_, always_require_handshake_confirmation_,
disable_connection_pooling_, load_server_info_timeout_srtt_multiplier_,
enable_connection_racing_, enable_non_blocking_io_, disable_disk_cache_,
prefer_aes_, max_number_of_lossy_connections_, packet_loss_threshold_,
max_disabled_reasons_, threshold_timeouts_with_open_streams_,
threshold_public_resets_post_handshake_, receive_buffer_size_,
delay_tcp_race_, /*max_server_configs_stored_in_properties*/ 0,
close_sessions_on_ip_change_,
disable_quic_on_timeout_with_open_streams_,
idle_connection_timeout_seconds_, migrate_sessions_on_network_change_,
migrate_sessions_early_, QuicTagVector(),
/*enable_token_binding*/ false));
factory_->set_require_confirmation(false);
EXPECT_FALSE(factory_->has_quic_server_info_factory());
factory_->set_quic_server_info_factory(new MockQuicServerInfoFactory());
EXPECT_TRUE(factory_->has_quic_server_info_factory());
}
void InitializeConnectionMigrationTest(
NetworkChangeNotifier::NetworkList connected_networks) {
scoped_mock_network_change_notifier_.reset(
new ScopedMockNetworkChangeNotifier());
MockNetworkChangeNotifier* mock_ncn =
scoped_mock_network_change_notifier_->mock_network_change_notifier();
mock_ncn->ForceNetworkHandlesSupported();
mock_ncn->SetConnectedNetworksList(connected_networks);
migrate_sessions_on_network_change_ = true;
migrate_sessions_early_ = true;
Initialize();
}
bool HasActiveSession(const HostPortPair& host_port_pair) {
QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
return QuicStreamFactoryPeer::HasActiveSession(factory_.get(), server_id);
}
QuicChromiumClientSession* GetActiveSession(
const HostPortPair& host_port_pair) {
QuicServerId server_id(host_port_pair, PRIVACY_MODE_DISABLED);
return QuicStreamFactoryPeer::GetActiveSession(factory_.get(), server_id);
}
std::unique_ptr<QuicHttpStream> CreateFromSession(
const HostPortPair& host_port_pair) {
QuicChromiumClientSession* session = GetActiveSession(host_port_pair);
return QuicStreamFactoryPeer::CreateFromSession(factory_.get(), session);
}
int GetSourcePortForNewSession(const HostPortPair& destination) {
return GetSourcePortForNewSessionInner(destination, false);
}
int GetSourcePortForNewSessionAndGoAway(const HostPortPair& destination) {
return GetSourcePortForNewSessionInner(destination, true);
}
int GetSourcePortForNewSessionInner(const HostPortPair& destination,
bool goaway_received) {
// Should only be called if there is no active session for this destination.
EXPECT_FALSE(HasActiveSession(destination));
size_t socket_count = socket_factory_.udp_client_socket_ports().size();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(factory_.get());
GURL url("https://" + destination.host() + "/");
EXPECT_EQ(ERR_IO_PENDING,
request.Request(destination, privacy_mode_,
/*cert_verify_flags=*/0, url, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
stream.reset();
QuicChromiumClientSession* session = GetActiveSession(destination);
if (socket_count + 1 != socket_factory_.udp_client_socket_ports().size()) {
ADD_FAILURE();
return 0;
}
if (goaway_received) {
QuicGoAwayFrame goaway(QUIC_NO_ERROR, 1, "");
session->connection()->OnGoAwayFrame(goaway);
}
factory_->OnSessionClosed(session);
EXPECT_FALSE(HasActiveSession(destination));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
return socket_factory_.udp_client_socket_ports()[socket_count];
}
std::unique_ptr<QuicEncryptedPacket> ConstructClientConnectionClosePacket(
QuicPacketNumber num) {
return client_maker_.MakeConnectionClosePacket(num);
}
std::unique_ptr<QuicEncryptedPacket> ConstructClientRstPacket() {
QuicStreamId stream_id = kClientDataStreamId1;
return client_maker_.MakeRstPacket(
1, true, stream_id,
AdjustErrorForVersion(QUIC_RST_ACKNOWLEDGEMENT, version_));
}
static ProofVerifyDetailsChromium DefaultProofVerifyDetails() {
// Load a certificate that is valid for *.example.org
scoped_refptr<X509Certificate> test_cert(
ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
EXPECT_TRUE(test_cert.get());
ProofVerifyDetailsChromium verify_details;
verify_details.cert_verify_result.verified_cert = test_cert;
verify_details.cert_verify_result.is_issued_by_known_root = true;
return verify_details;
}
void NotifyIPAddressChanged() {
NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
// Spin the message loop so the notification is delivered.
base::MessageLoop::current()->RunUntilIdle();
}
std::unique_ptr<QuicEncryptedPacket> ConstructGetRequestPacket(
QuicPacketNumber packet_number,
QuicStreamId stream_id,
bool should_include_version,
bool fin) {
SpdyHeaderBlock headers =
client_maker_.GetRequestHeaders("GET", "https", "/");
SpdyPriority priority =
ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
size_t spdy_headers_frame_len;
return client_maker_.MakeRequestHeadersPacket(
packet_number, stream_id, should_include_version, fin, priority,
headers, &spdy_headers_frame_len);
}
std::unique_ptr<QuicEncryptedPacket> ConstructOkResponsePacket(
QuicPacketNumber packet_number,
QuicStreamId stream_id,
bool should_include_version,
bool fin) {
SpdyHeaderBlock headers = server_maker_.GetResponseHeaders("200 OK");
size_t spdy_headers_frame_len;
return server_maker_.MakeResponseHeadersPacket(
packet_number, stream_id, should_include_version, fin, headers,
&spdy_headers_frame_len);
}
MockHostResolver host_resolver_;
MockClientSocketFactory socket_factory_;
MockCryptoClientStreamFactory crypto_client_stream_factory_;
MockRandom random_generator_;
MockClock* clock_; // Owned by |factory_| once created.
scoped_refptr<TestTaskRunner> runner_;
QuicVersion version_;
QuicTestPacketMaker client_maker_;
QuicTestPacketMaker server_maker_;
HttpServerPropertiesImpl http_server_properties_;
std::unique_ptr<CertVerifier> cert_verifier_;
std::unique_ptr<ChannelIDService> channel_id_service_;
TransportSecurityState transport_security_state_;
std::unique_ptr<CTVerifier> cert_transparency_verifier_;
std::unique_ptr<ScopedMockNetworkChangeNotifier>
scoped_mock_network_change_notifier_;
std::unique_ptr<QuicStreamFactory> factory_;
HostPortPair host_port_pair_;
GURL url_;
GURL url2_;
GURL url3_;
GURL url4_;
PrivacyMode privacy_mode_;
BoundNetLog net_log_;
TestCompletionCallback callback_;
// Variables to configure QuicStreamFactory.
bool enable_port_selection_;
bool always_require_handshake_confirmation_;
bool disable_connection_pooling_;
double load_server_info_timeout_srtt_multiplier_;
bool enable_connection_racing_;
bool enable_non_blocking_io_;
bool disable_disk_cache_;
bool prefer_aes_;
int max_number_of_lossy_connections_;
double packet_loss_threshold_;
int max_disabled_reasons_;
int threshold_timeouts_with_open_streams_;
int threshold_public_resets_post_handshake_;
int receive_buffer_size_;
bool delay_tcp_race_;
bool close_sessions_on_ip_change_;
bool disable_quic_on_timeout_with_open_streams_;
int idle_connection_timeout_seconds_;
bool migrate_sessions_on_network_change_;
bool migrate_sessions_early_;
};
class QuicStreamFactoryTest : public QuicStreamFactoryTestBase,
public ::testing::TestWithParam<TestParams> {
protected:
QuicStreamFactoryTest()
: QuicStreamFactoryTestBase(GetParam().version,
GetParam().enable_connection_racing) {}
};
INSTANTIATE_TEST_CASE_P(Version,
QuicStreamFactoryTest,
::testing::ValuesIn(GetTestParams()));
TEST_P(QuicStreamFactoryTest, Create) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Will reset stream 3.
stream = CreateFromSession(host_port_pair_);
EXPECT_TRUE(stream.get());
// TODO(rtenneti): We should probably have a tests that HTTP and HTTPS result
// in streams on different sessions.
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
stream = request2.CreateStream(); // Will reset stream 5.
stream.reset(); // Will reset stream 7.
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateZeroRtt) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
crypto_client_stream_factory_.set_handshake_mode(
MockCryptoClientStream::ZERO_RTT);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
"192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateZeroRttPost) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
crypto_client_stream_factory_.set_handshake_mode(
MockCryptoClientStream::ZERO_RTT);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
"192.168.0.1", "");
QuicStreamRequest request(factory_.get());
// Posts require handshake confirmation, so this will return asynchronously.
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "POST", net_log_,
callback_.callback()));
// Confirm the handshake and verify that the stream is created.
crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
QuicSession::HANDSHAKE_CONFIRMED);
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, GoAway) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
session->OnGoAway(QuicGoAwayFrame());
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, GoAwayForConnectionMigrationWithPortOnly) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
session->OnGoAway(
QuicGoAwayFrame(QUIC_ERROR_MIGRATING_PORT, 0,
"peer connection migration due to port change only"));
NetErrorDetails details;
EXPECT_FALSE(details.quic_port_migration_detected);
session->PopulateNetErrorDetails(&details);
EXPECT_TRUE(details.quic_port_migration_detected);
details.quic_port_migration_detected = false;
stream->PopulateNetErrorDetails(&details);
EXPECT_TRUE(details.quic_port_migration_detected);
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, Pooling) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
HostPortPair server2(kServer2HostName, kDefaultServerPort);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
"192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_EQ(GetActiveSession(host_port_pair_), GetActiveSession(server2));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoPoolingIfDisabled) {
disable_connection_pooling_ = true;
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
HostPortPair server2(kServer2HostName, kDefaultServerPort);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
"192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_NE(GetActiveSession(host_port_pair_), GetActiveSession(server2));
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoPoolingAfterGoAway) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
HostPortPair server2(kServer2HostName, kDefaultServerPort);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
"192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
factory_->OnSessionGoingAway(GetActiveSession(host_port_pair_));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_FALSE(HasActiveSession(server2));
TestCompletionCallback callback3;
QuicStreamRequest request3(factory_.get());
EXPECT_EQ(OK, request3.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback3.callback()));
std::unique_ptr<QuicHttpStream> stream3 = request3.CreateStream();
EXPECT_TRUE(stream3.get());
EXPECT_TRUE(HasActiveSession(server2));
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, HttpsPooling) {
Initialize();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
HostPortPair server1(kDefaultServerHostName, 443);
HostPortPair server2(kServer2HostName, 443);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback_.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingIfDisabled) {
disable_connection_pooling_ = true;
Initialize();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
HostPortPair server1(kDefaultServerHostName, 443);
HostPortPair server2(kServer2HostName, 443);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback_.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, HttpsPoolingWithMatchingPins) {
Initialize();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
HostPortPair server1(kDefaultServerHostName, 443);
HostPortPair server2(kServer2HostName, 443);
uint8_t primary_pin = 1;
uint8_t backup_pin = 2;
test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
backup_pin);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
verify_details.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(primary_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback_.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_EQ(GetActiveSession(server1), GetActiveSession(server2));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithMatchingPinsIfDisabled) {
disable_connection_pooling_ = true;
Initialize();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
HostPortPair server1(kDefaultServerHostName, 443);
HostPortPair server2(kServer2HostName, 443);
uint8_t primary_pin = 1;
uint8_t backup_pin = 2;
test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
backup_pin);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
verify_details.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(primary_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback_.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, NoHttpsPoolingWithDifferentPins) {
Initialize();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data1(reads, arraysize(reads), nullptr, 0);
SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data1);
socket_factory_.AddSocketDataProvider(&socket_data2);
HostPortPair server1(kDefaultServerHostName, 443);
HostPortPair server2(kServer2HostName, 443);
uint8_t primary_pin = 1;
uint8_t backup_pin = 2;
uint8_t bad_pin = 3;
test::AddPin(&transport_security_state_, kServer2HostName, primary_pin,
backup_pin);
ProofVerifyDetailsChromium verify_details1 = DefaultProofVerifyDetails();
verify_details1.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(bad_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details1);
ProofVerifyDetailsChromium verify_details2 = DefaultProofVerifyDetails();
verify_details2.cert_verify_result.public_key_hashes.push_back(
test::GetTestHashValue(primary_pin));
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details2);
host_resolver_.set_synchronous_mode(true);
host_resolver_.rules()->AddIPLiteralRule(server1.host(), "192.168.0.1", "");
host_resolver_.rules()->AddIPLiteralRule(server2.host(), "192.168.0.1", "");
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(server1, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
TestCompletionCallback callback;
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(OK, request2.Request(server2, privacy_mode_,
/*cert_verify_flags=*/0, url2_, "GET",
net_log_, callback_.callback()));
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_NE(GetActiveSession(server1), GetActiveSession(server2));
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, Goaway) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
SequencedSocketData socket_data2(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Mark the session as going away. Ensure that while it is still alive
// that it is no longer active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
factory_->OnSessionGoingAway(session);
EXPECT_EQ(true,
QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
// Create a new request for the same destination and verify that a
// new session is created.
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_NE(session, GetActiveSession(host_port_pair_));
EXPECT_EQ(true,
QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
stream2.reset();
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, MaxOpenStream) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
QuicStreamId stream_id = kClientDataStreamId1;
std::unique_ptr<QuicEncryptedPacket> client_rst(
client_maker_.MakeRstPacket(1, true, stream_id, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(ASYNC, client_rst->data(), client_rst->length(), 0),
};
std::unique_ptr<QuicEncryptedPacket> server_rst(
server_maker_.MakeRstPacket(1, false, stream_id, QUIC_STREAM_CANCELLED));
MockRead reads[] = {
MockRead(ASYNC, server_rst->data(), server_rst->length(), 1),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
HttpRequestInfo request_info;
vector<QuicHttpStream*> streams;
// The MockCryptoClientStream sets max_open_streams to be
// kDefaultMaxStreamsPerConnection / 2.
for (size_t i = 0; i < kDefaultMaxStreamsPerConnection / 2; i++) {
QuicStreamRequest request(factory_.get());
int rv = request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback());
if (i == 0) {
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(OK, callback_.WaitForResult());
} else {
EXPECT_EQ(OK, rv);
}
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream);
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
streams.push_back(stream.release());
}
QuicStreamRequest request(factory_.get());
EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
CompletionCallback()));
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream);
EXPECT_EQ(ERR_IO_PENDING,
stream->InitializeStream(&request_info, DEFAULT_PRIORITY, net_log_,
callback_.callback()));
// Close the first stream.
streams.front()->Close(false);
// Trigger exchange of RSTs that in turn allow progress for the last
// stream.
EXPECT_EQ(OK, callback_.WaitForResult());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
// Force close of the connection to suppress the generation of RST
// packets when streams are torn down, which wouldn't be relevant to
// this test anyway.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
session->connection()->CloseConnection(QUIC_PUBLIC_RESET, "test",
ConnectionCloseBehavior::SILENT_CLOSE);
STLDeleteElements(&streams);
}
TEST_P(QuicStreamFactoryTest, ResolutionErrorInCreate) {
Initialize();
SequencedSocketData socket_data(nullptr, 0, nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
host_resolver_.rules()->AddSimulatedFailure(kDefaultServerHostName);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, ConnectErrorInCreate) {
Initialize();
MockConnect connect(SYNCHRONOUS, ERR_ADDRESS_IN_USE);
SequencedSocketData socket_data(nullptr, 0, nullptr, 0);
socket_data.set_connect_data(connect);
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(ERR_ADDRESS_IN_USE, callback_.WaitForResult());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CancelCreate) {
Initialize();
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
{
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
}
base::RunLoop().RunUntilIdle();
std::unique_ptr<QuicHttpStream> stream(CreateFromSession(host_port_pair_));
EXPECT_TRUE(stream.get());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, CreateConsistentEphemeralPort) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
// Sequentially connect to the default host, then another host, and then the
// default host. Verify that the default host gets a consistent ephemeral
// port, that is different from the other host's connection.
string other_server_name = kServer2HostName;
EXPECT_NE(kDefaultServerHostName, other_server_name);
HostPortPair host_port_pair2(other_server_name, kDefaultServerPort);
int original_port = GetSourcePortForNewSession(host_port_pair_);
EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair2));
EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
}
TEST_P(QuicStreamFactoryTest, GoAwayDisablesConsistentEphemeralPort) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
// Get a session to the host using the port suggester.
int original_port = GetSourcePortForNewSessionAndGoAway(host_port_pair_);
// Verify that the port is different after the goaway.
EXPECT_NE(original_port, GetSourcePortForNewSession(host_port_pair_));
// Since the previous session did not goaway we should see the original port.
EXPECT_EQ(original_port, GetSourcePortForNewSession(host_port_pair_));
}
TEST_P(QuicStreamFactoryTest, CloseAllSessions) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
vector<MockWrite> writes;
writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
SequencedSocketData socket_data(reads, arraysize(reads),
writes.empty() ? nullptr : &writes[0],
writes.size());
socket_factory_.AddSocketDataProvider(&socket_data);
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Close the session and verify that stream saw the error.
factory_->CloseAllSessions(ERR_INTERNET_DISCONNECTED, QUIC_INTERNAL_ERROR);
EXPECT_EQ(ERR_INTERNET_DISCONNECTED,
stream->ReadResponseHeaders(callback_.callback()));
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.CreateStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
close_sessions_on_ip_change_ = true;
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
vector<MockWrite> writes;
writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
SequencedSocketData socket_data(reads, arraysize(reads),
writes.empty() ? nullptr : &writes[0],
writes.size());
socket_factory_.AddSocketDataProvider(&socket_data);
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Change the IP address and verify that stream saw the error.
NotifyIPAddressChanged();
EXPECT_EQ(ERR_NETWORK_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_TRUE(factory_->require_confirmation());
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.CreateStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnect) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> request_packet(
ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(),
request_packet->length(), 1)};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.example.org/");
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Send GET request on stream.
HttpResponseInfo response;
HttpRequestHeaders request_headers;
EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
callback_.callback()));
// Set up second socket data provider that is used after migration.
// The response to the earlier request is read on this new socket.
std::unique_ptr<QuicEncryptedPacket> ping(
client_maker_.MakePingPacket(2, /*include_version=*/true));
MockWrite writes1[] = {
MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 0)};
std::unique_ptr<QuicEncryptedPacket> response_headers_packet(
ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
MockRead reads1[] = {MockRead(ASYNC, response_headers_packet->data(),
response_headers_packet->length(), 1),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1,
arraysize(writes1));
socket_factory_.AddSocketDataProvider(&socket_data1);
// Trigger connection migration. This should cause a PING frame
// to be emitted.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
// The session should now be marked as going away. Ensure that
// while it is still alive, it is no longer active.
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
// Verify that response headers on the migrated socket were delivered to the
// stream.
EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
EXPECT_EQ(200, response.headers->response_code());
// Create a new request for the same destination and verify that a
// new session is created.
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_TRUE(HasActiveSession(host_port_pair_));
QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
EXPECT_NE(session, new_session);
// On a DISCONNECTED notification, nothing happens to the migrated
// session, but the new session is closed since it has no open
// streams.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_EQ(1u, session->GetNumActiveStreams());
EXPECT_FALSE(
QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnected) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> request_packet(
ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(),
request_packet->length(), 1)};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.example.org/");
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Send GET request on stream.
HttpResponseInfo response_info;
HttpRequestHeaders request_headers;
EXPECT_EQ(OK, stream->SendRequest(request_headers, &response_info,
callback_.callback()));
// Set up second socket data provider that is used after migration.
std::unique_ptr<QuicEncryptedPacket> ping(
client_maker_.MakePingPacket(2, /*include_version=*/true));
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
3, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes1[] = {
MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 0)};
std::unique_ptr<QuicEncryptedPacket> response_packet(
ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
MockRead reads1[] = {
MockRead(ASYNC, response_packet->data(), response_packet->length(), 1),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1,
arraysize(writes1));
socket_factory_.AddSocketDataProvider(&socket_data1);
// Trigger connection migration. This should cause a PING frame
// to be emitted.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
// The session should now be marked as going away. Ensure that
// while it is still alive, it is no longer active.
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
// Create a new request for the same destination and verify that a
// new session is created.
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_NE(session, GetActiveSession(host_port_pair_));
EXPECT_EQ(true,
QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnectNoNetworks) {
NetworkChangeNotifier::NetworkList no_networks(0);
InitializeConnectionMigrationTest(no_networks);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
// Trigger connection migration. Since there are no networks
// to migrate to, this should cause the session to continue on the same
// socket, but be marked as going away.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNetworks) {
NetworkChangeNotifier::NetworkList no_networks(0);
InitializeConnectionMigrationTest(no_networks);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
MockWrite writes[] = {
MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there are no networks
// to migrate to, this should cause a RST_STREAM frame to be emitted
// and the session to be closed.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnectNoNewNetwork) {
InitializeConnectionMigrationTest({kDefaultNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there are no networks
// to migrate to, this should cause session to be continue but be marked as
// going away.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNewNetwork) {
InitializeConnectionMigrationTest({kDefaultNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
MockWrite writes[] = {
MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there are no networks
// to migrate to, this should cause a RST_STREAM frame to be emitted
// with QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest,
OnNetworkChangeSoonToDisconnectNonMigratableStream) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created, but marked as non-migratable.
HttpRequestInfo request_info;
request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there is a non-migratable stream,
// this should cause session to continue but be marked as going away.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest,
OnNetworkChangeSoonToDisconnectConnectionMigrationDisabled) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Set session config to have connection migration disabled.
QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
EXPECT_TRUE(session->config()->DisableConnectionMigration());
// Trigger connection migration. Since there is a non-migratable stream,
// this should cause session to continue but be marked as going away.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNonMigratableStream) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
MockWrite writes[] = {
MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created, but marked as non-migratable.
HttpRequestInfo request_info;
request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there is a non-migratable stream,
// this should cause a RST_STREAM frame to be emitted with
// QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest,
OnNetworkChangeDisconnectedConnectionMigrationDisabled) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT));
MockWrite writes[] = {
MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Set session config to have connection migration disabled.
QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
EXPECT_TRUE(session->config()->DisableConnectionMigration());
// Trigger connection migration. Since there is a non-migratable stream,
// this should cause a RST_STREAM frame to be emitted with
// QUIC_RST_ACKNOWLEDGEMENT error code, and the session will be closed.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeSoonToDisconnectNoOpenStreams) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0u);
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there are no active streams,
// the session will be closed.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoOpenStreams) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data(reads, arraysize(reads), nullptr, 0u);
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there are no active streams,
// the session will be closed.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, MigrateSessionEarly) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> request_packet(
ConstructGetRequestPacket(1, kClientDataStreamId1, true, true));
MockWrite writes[] = {MockWrite(SYNCHRONOUS, request_packet->data(),
request_packet->length(), 1)};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.example.org/");
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Send GET request on stream.
HttpResponseInfo response;
HttpRequestHeaders request_headers;
EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
callback_.callback()));
// Set up second socket data provider that is used after migration.
// The response to the earlier request is read on this new socket.
std::unique_ptr<QuicEncryptedPacket> ping(
client_maker_.MakePingPacket(2, /*include_version=*/true));
MockWrite writes1[] = {
MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 0)};
std::unique_ptr<QuicEncryptedPacket> response_headers_packet(
ConstructOkResponsePacket(1, kClientDataStreamId1, false, false));
MockRead reads1[] = {MockRead(ASYNC, response_headers_packet->data(),
response_headers_packet->length(), 1),
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
SequencedSocketData socket_data1(reads1, arraysize(reads1), writes1,
arraysize(writes1));
socket_factory_.AddSocketDataProvider(&socket_data1);
// Trigger early connection migration. This should cause a PING frame
// to be emitted.
session->OnPathDegrading();
// Run the message loop so that data queued in the new socket is read by the
// packet reader.
base::RunLoop().RunUntilIdle();
// The session should now be marked as going away. Ensure that
// while it is still alive, it is no longer active.
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
// Verify that response headers on the migrated socket were delivered to the
// stream.
EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
EXPECT_EQ(200, response.headers->response_code());
// Create a new request for the same destination and verify that a
// new session is created.
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream2 = request2.CreateStream();
EXPECT_TRUE(stream2.get());
EXPECT_TRUE(HasActiveSession(host_port_pair_));
QuicChromiumClientSession* new_session = GetActiveSession(host_port_pair_);
EXPECT_NE(session, new_session);
// On a SOON_TO_DISCONNECT notification, nothing happens to the
// migrated session, but the new session is closed since it has no
// open streams.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkSoonToDisconnect(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_EQ(1u, session->GetNumActiveStreams());
EXPECT_FALSE(
QuicStreamFactoryPeer::IsLiveSession(factory_.get(), new_session));
// On a DISCONNECTED notification, nothing happens to the migrated session.
scoped_mock_network_change_notifier_->mock_network_change_notifier()
->NotifyNetworkDisconnected(kDefaultNetworkForTests);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_EQ(1u, session->GetNumActiveStreams());
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data1.AllReadDataConsumed());
EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNoNewNetwork) {
InitializeConnectionMigrationTest({kDefaultNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there are no networks
// to migrate to, this should cause session to be continue but be marked as
// going away.
session->OnPathDegrading();
// Run the message loop so that data queued in the new socket is read by the
// packet reader.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyNonMigratableStream) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created, but marked as non-migratable.
HttpRequestInfo request_info;
request_info.load_flags |= LOAD_DISABLE_CONNECTION_MIGRATION;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Trigger connection migration. Since there is a non-migratable stream,
// this should cause session to be continue without migrating.
session->OnPathDegrading();
// Run the message loop so that data queued in the new socket is read by the
// packet reader.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyConnectionMigrationDisabled) {
InitializeConnectionMigrationTest(
{kDefaultNetworkForTests, kNewNetworkForTests});
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> client_rst(client_maker_.MakeRstPacket(
1, true, kClientDataStreamId1, QUIC_STREAM_CANCELLED));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, client_rst->data(), client_rst->length(), 1),
};
SequencedSocketData socket_data(reads, arraysize(reads), writes,
arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
// Create request and QuicHttpStream.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
EXPECT_TRUE(stream.get());
// Cause QUIC stream to be created.
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Ensure that session is alive and active.
QuicChromiumClientSession* session = GetActiveSession(host_port_pair_);
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
// Set session config to have connection migration disabled.
QuicConfigPeer::SetReceivedDisableConnectionMigration(session->config());
EXPECT_TRUE(session->config()->DisableConnectionMigration());
// Trigger connection migration. Since there is a non-migratable stream,
// this should cause session to be continue without migrating.
session->OnPathDegrading();
// Run the message loop so that data queued in the new socket is read by the
// packet reader.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_EQ(1u, session->GetNumActiveStreams());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnSSLConfigChanged) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
vector<MockWrite> writes;
writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
SequencedSocketData socket_data(reads, arraysize(reads),
writes.empty() ? nullptr : &writes[0],
writes.size());
socket_factory_.AddSocketDataProvider(&socket_data);
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
factory_->OnSSLConfigChanged();
EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_FALSE(factory_->require_confirmation());
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.CreateStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnCertAdded) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
vector<MockWrite> writes;
writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
SequencedSocketData socket_data(reads, arraysize(reads),
writes.empty() ? nullptr : &writes[0],
writes.size());
socket_factory_.AddSocketDataProvider(&socket_data);
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Add a cert and verify that stream saw the event.
factory_->OnCertAdded(nullptr);
EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_FALSE(factory_->require_confirmation());
// Now attempting to request a stream to the same origin should create
// a new session.
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
stream = request2.CreateStream();
stream.reset(); // Will reset stream 3.
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
TEST_P(QuicStreamFactoryTest, OnCACertChanged) {
Initialize();
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
std::unique_ptr<QuicEncryptedPacket> rst(ConstructClientRstPacket());
vector<MockWrite> writes;
writes.push_back(MockWrite(ASYNC, rst->data(), rst->length(), 1));
SequencedSocketData socket_data(reads, arraysize(reads),
writes.empty() ? nullptr : &writes[0],
writes.size());
socket_factory_.AddSocketDataProvider(&socket_data);
MockRead reads2[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
SequencedSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
socket_factory_.AddSocketDataProvider(&socket_data2);
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, privacy_mode_,
/*cert_verify_flags=*/0, url_, "GET", net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
HttpRequestInfo request_info;
EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
net_log_, CompletionCallback()));
// Change the CA cert and verify that stream saw the event.
factory_->OnCACertChanged(nullptr);
EXPECT_EQ(ERR_CERT_DATABASE_CHANGED,
stream->ReadResponseHeaders(callback_.callback()));
EXPECT_FALSE(factory_->require_confirmation());