Commit 247d632e authored by Zhongyi Shi's avatar Zhongyi Shi Committed by Commit Bot

Do not apply connection migration on packet write error if handshake is not confirmed.

Bug: 790547
Change-Id: I68d3afb4a8bce843eee9e3b5456ed3103c7d2914
Reviewed-on: https://chromium-review.googlesource.com/1147545Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Commit-Queue: Zhongyi Shi <zhongyi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577442}
parent 8248ac8a
...@@ -1601,13 +1601,17 @@ void QuicChromiumClientSession::OnConnectivityProbeReceived( ...@@ -1601,13 +1601,17 @@ void QuicChromiumClientSession::OnConnectivityProbeReceived(
int QuicChromiumClientSession::HandleWriteError( int QuicChromiumClientSession::HandleWriteError(
int error_code, int error_code,
scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet) { scoped_refptr<QuicChromiumPacketWriter::ReusableIOBuffer> packet) {
current_connection_migration_cause_ = ON_WRITE_ERROR;
LogHandshakeStatusOnConnectionMigrationSignal();
base::UmaHistogramSparse("Net.QuicSession.WriteError", -error_code); base::UmaHistogramSparse("Net.QuicSession.WriteError", -error_code);
if (IsCryptoHandshakeConfirmed()) { if (IsCryptoHandshakeConfirmed()) {
base::UmaHistogramSparse("Net.QuicSession.WriteError.HandshakeConfirmed", base::UmaHistogramSparse("Net.QuicSession.WriteError.HandshakeConfirmed",
-error_code); -error_code);
} }
if (error_code == ERR_MSG_TOO_BIG || stream_factory_ == nullptr || if (error_code == ERR_MSG_TOO_BIG || stream_factory_ == nullptr ||
!migrate_session_on_network_change_v2_) { !migrate_session_on_network_change_v2_ || !IsCryptoHandshakeConfirmed()) {
return error_code; return error_code;
} }
...@@ -1655,7 +1659,7 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError( ...@@ -1655,7 +1659,7 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError(
// Close the connection if migration failed. Do not cause a // Close the connection if migration failed. Do not cause a
// connection close packet to be sent since socket may be borked. // connection close packet to be sent since socket may be borked.
connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR, connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
"Write and subsequent migration failed", "Write error with nulled stream factory",
quic::ConnectionCloseBehavior::SILENT_CLOSE); quic::ConnectionCloseBehavior::SILENT_CLOSE);
return; return;
} }
...@@ -1666,13 +1670,11 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError( ...@@ -1666,13 +1670,11 @@ void QuicChromiumClientSession::MigrateSessionOnWriteError(
// Close the connection if migration failed. Do not cause a // Close the connection if migration failed. Do not cause a
// connection close packet to be sent since socket may be borked. // connection close packet to be sent since socket may be borked.
connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR, connection()->CloseConnection(quic::QUIC_PACKET_WRITE_ERROR,
"Write and subsequent migration failed", "Write error for non-migratable session",
quic::ConnectionCloseBehavior::SILENT_CLOSE); quic::ConnectionCloseBehavior::SILENT_CLOSE);
return; return;
} }
LogHandshakeStatusOnConnectionMigrationSignal();
NetworkChangeNotifier::NetworkHandle new_network = NetworkChangeNotifier::NetworkHandle new_network =
stream_factory_->FindAlternateNetwork( stream_factory_->FindAlternateNetwork(
GetDefaultSocket()->GetBoundNetwork()); GetDefaultSocket()->GetBoundNetwork());
......
...@@ -4375,6 +4375,72 @@ TEST_P(QuicStreamFactoryTest, MigrateBackToDefaultPostMigrationOnWriteError) { ...@@ -4375,6 +4375,72 @@ TEST_P(QuicStreamFactoryTest, MigrateBackToDefaultPostMigrationOnWriteError) {
EXPECT_TRUE(quic_data3.AllWriteDataConsumed()); EXPECT_TRUE(quic_data3.AllWriteDataConsumed());
} }
// Test that connection will be closed with PACKET_WRITE_ERROR if a write error
// is triggered before handshake is confirmed and connection migration is turned
// on.
TEST_P(QuicStreamFactoryTest, MigrationOnWriteErrorBeforeHandshakeConfirmed) {
InitializeConnectionMigrationV2Test(
{kDefaultNetworkForTests, kNewNetworkForTests});
// Use unmocked crypto stream to do crypto connect.
crypto_client_stream_factory_.set_handshake_mode(
quic::MockCryptoClientStream::USE_DEFAULT_CRYPTO_STREAM);
MockQuicData socket_data;
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
// Trigger PACKET_WRITE_ERROR when sending packets in crypto connect.
socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE);
socket_data.AddSocketDataToFactory(socket_factory_.get());
// Create request, should fail after the write of the CHLO fails.
QuicStreamRequest request(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request.Request(host_port_pair_, version_, privacy_mode_,
DEFAULT_PRIORITY, SocketTag(),
/*cert_verify_flags=*/0, url_, net_log_,
&net_error_details_, callback_.callback()));
EXPECT_EQ(ERR_QUIC_HANDSHAKE_FAILED, callback_.WaitForResult());
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_));
// Verify new requests can be sent normally.
crypto_client_stream_factory_.set_handshake_mode(
quic::MockCryptoClientStream::COLD_START);
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
MockQuicData socket_data2;
socket_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
socket_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket());
socket_data2.AddSocketDataToFactory(socket_factory_.get());
QuicStreamRequest request2(factory_.get());
EXPECT_EQ(ERR_IO_PENDING,
request2.Request(host_port_pair_, version_, privacy_mode_,
DEFAULT_PRIORITY, SocketTag(),
/*cert_verify_flags=*/0, url_, net_log_,
&net_error_details_, callback_.callback()));
EXPECT_FALSE(HasActiveSession(host_port_pair_));
EXPECT_TRUE(HasActiveJob(host_port_pair_, privacy_mode_));
// Run the message loop to complete host resolution.
base::RunLoop().RunUntilIdle();
// Complete handshake. QuicStreamFactory::Job should complete and succeed.
crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
quic::QuicSession::HANDSHAKE_CONFIRMED);
EXPECT_THAT(callback_.WaitForResult(), IsOk());
EXPECT_TRUE(HasActiveSession(host_port_pair_));
EXPECT_FALSE(HasActiveJob(host_port_pair_, privacy_mode_));
// Create QuicHttpStream.
std::unique_ptr<HttpStream> stream = CreateStream(&request2);
EXPECT_TRUE(stream.get());
stream.reset();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
EXPECT_TRUE(socket_data2.AllReadDataConsumed());
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
void QuicStreamFactoryTestBase::TestMigrationOnWriteError( void QuicStreamFactoryTestBase::TestMigrationOnWriteError(
IoMode write_error_mode) { IoMode write_error_mode) {
InitializeConnectionMigrationV2Test( InitializeConnectionMigrationV2Test(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment