Index: net/quic/chromium/quic_stream_factory_test.cc |
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc |
index 2ca8dbe9f779857174a7f32dec655cf4b8cc3dba..b63abc510bdbfcaa5dafb850782a6dc860cf548c 100644 |
--- a/net/quic/chromium/quic_stream_factory_test.cc |
+++ b/net/quic/chromium/quic_stream_factory_test.cc |
@@ -507,6 +507,18 @@ class QuicStreamFactoryTestBase { |
EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); |
} |
+ // Helper methods for tests of connection migration on write error. |
+ void TestMigrationOnWriteErrorNonMigratableStream(IoMode write_error_mode); |
+ void TestMigrationOnWriteErrorMigrationDisabled(IoMode write_error_mode); |
+ void TestMigrationOnWriteError(IoMode write_error_mode); |
+ void TestMigrationOnWriteErrorNoNewNetwork(IoMode write_error_mode); |
+ void TestMigrationOnMultipleWriteErrors(IoMode first_write_error_mode, |
+ IoMode second_write_error_mode); |
+ void TestMigrationOnWriteErrorWithNotificationQueued(bool disconnected); |
+ void TestMigrationOnNotificationWithWriteErrorQueued(bool disconnected); |
+ void OnNetworkDisconnected(bool async_write_before); |
+ void OnNetworkMadeDefault(bool async_write_before); |
+ |
MockHostResolver host_resolver_; |
scoped_refptr<SSLConfigService> ssl_config_service_; |
MockClientSocketFactory socket_factory_; |
@@ -1460,17 +1472,30 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) { |
EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeNetworkMadeDefault) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultWithSynchronousWriteBefore) { |
+ OnNetworkMadeDefault(/*async_write_before=*/false); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultWithAsyncWriteBefore) { |
+ OnNetworkMadeDefault(/*async_write_before=*/true); |
+} |
+ |
+void QuicStreamFactoryTestBase::OnNetworkMadeDefault(bool async_write_before) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ int packet_number = 1; |
MockQuicData socket_data; |
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
- socket_data.AddWrite( |
- ConstructGetRequestPacket(1, kClientDataStreamId1, true, true)); |
+ socket_data.AddWrite(ConstructGetRequestPacket( |
+ packet_number++, kClientDataStreamId1, true, true)); |
+ if (async_write_before) { |
+ socket_data.AddWrite(ASYNC, OK); |
+ packet_number++; |
+ } |
socket_data.AddSocketDataToFactory(&socket_factory_); |
// Create request and QuicHttpStream. |
@@ -1501,16 +1526,21 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeNetworkMadeDefault) { |
EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
callback_.callback())); |
+ // Do an async write to leave writer blocked. |
+ if (async_write_before) |
+ session->connection()->SendPing(); |
+ |
// Set up second socket data provider that is used after migration. |
// The response to the earlier request is read on this new socket. |
MockQuicData socket_data1; |
socket_data1.AddWrite( |
- client_maker_.MakePingPacket(2, /*include_version=*/true)); |
+ client_maker_.MakePingPacket(packet_number++, /*include_version=*/true)); |
socket_data1.AddRead( |
ConstructOkResponsePacket(1, kClientDataStreamId1, false, false)); |
socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket( |
- 3, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true)); |
+ packet_number++, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, |
+ 1, true)); |
socket_data1.AddSocketDataToFactory(&socket_factory_); |
// Trigger connection migration. This should cause a PING frame |
@@ -1567,17 +1597,30 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeNetworkMadeDefault) { |
EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnected) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedWithSynchronousWriteBefore) { |
+ OnNetworkDisconnected(/*async_write_before=*/false); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedWithAsyncWriteBefore) { |
+ OnNetworkDisconnected(/*async_write_before=*/true); |
+} |
+ |
+void QuicStreamFactoryTestBase::OnNetworkDisconnected(bool async_write_before) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ int packet_number = 1; |
MockQuicData socket_data; |
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
- socket_data.AddWrite( |
- ConstructGetRequestPacket(1, kClientDataStreamId1, true, true)); |
+ socket_data.AddWrite(ConstructGetRequestPacket( |
+ packet_number++, kClientDataStreamId1, true, true)); |
+ if (async_write_before) { |
+ socket_data.AddWrite(ASYNC, OK); |
+ packet_number++; |
+ } |
socket_data.AddSocketDataToFactory(&socket_factory_); |
// Create request and QuicHttpStream. |
@@ -1608,14 +1651,21 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnected) { |
EXPECT_EQ(OK, stream->SendRequest(request_headers, &response_info, |
callback_.callback())); |
+ // Do an async write to leave writer blocked. |
+ if (async_write_before) |
+ session->connection()->SendPing(); |
+ |
+ // Set up second socket data provider that is used after migration. |
+ // The response to the earlier request is read on this new socket. |
MockQuicData socket_data1; |
socket_data1.AddWrite( |
- client_maker_.MakePingPacket(2, /*include_version=*/true)); |
+ client_maker_.MakePingPacket(packet_number++, /*include_version=*/true)); |
socket_data1.AddRead( |
ConstructOkResponsePacket(1, kClientDataStreamId1, false, false)); |
socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket( |
- 3, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true)); |
+ packet_number++, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, |
+ 1, true)); |
socket_data1.AddSocketDataToFactory(&socket_factory_); |
// Trigger connection migration. This should cause a PING frame |
@@ -1659,7 +1709,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnected) { |
EXPECT_TRUE(socket_data2.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNetworks) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNoNetworks) { |
NetworkChangeNotifier::NetworkList no_networks(0); |
InitializeConnectionMigrationTest(no_networks); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -1704,7 +1754,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNetworks) { |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNewNetwork) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNoNewNetwork) { |
InitializeConnectionMigrationTest({kDefaultNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
@@ -1748,8 +1798,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoNewNetwork) { |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, |
- OnNetworkChangeNetworkMadeDefaultNonMigratableStream) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNonMigratableStream) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -1797,8 +1846,7 @@ TEST_P(QuicStreamFactoryTest, |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, |
- OnNetworkChangeNetworkMadeDefaultConnectionMigrationDisabled) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultConnectionMigrationDisabled) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -1849,7 +1897,7 @@ TEST_P(QuicStreamFactoryTest, |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNonMigratableStream) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNonMigratableStream) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -1896,7 +1944,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNonMigratableStream) { |
} |
TEST_P(QuicStreamFactoryTest, |
- OnNetworkChangeDisconnectedConnectionMigrationDisabled) { |
+ OnNetworkDisconnectedConnectionMigrationDisabled) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -1945,7 +1993,7 @@ TEST_P(QuicStreamFactoryTest, |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeNetworkMadeDefaultNoOpenStreams) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkMadeDefaultNoOpenStreams) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -1982,7 +2030,7 @@ TEST_P(QuicStreamFactoryTest, OnNetworkChangeNetworkMadeDefaultNoOpenStreams) { |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, OnNetworkChangeDisconnectedNoOpenStreams) { |
+TEST_P(QuicStreamFactoryTest, OnNetworkDisconnectedNoOpenStreams) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -2412,7 +2460,8 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyConnectionMigrationDisabled) { |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteError) { |
+void QuicStreamFactoryTestBase::TestMigrationOnWriteError( |
+ IoMode write_error_mode) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -2421,7 +2470,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteError) { |
MockQuicData socket_data; |
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
- socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); |
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); |
socket_data.AddSocketDataToFactory(&socket_factory_); |
// Create request and QuicHttpStream. |
@@ -2466,8 +2515,8 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteError) { |
EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
callback_.callback())); |
- // Run the message loop so that data queued in the new socket is read by the |
- // packet reader. |
+ // Run the message loop so that the migration attempt is executed and |
+ // 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 |
@@ -2489,14 +2538,23 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteError) { |
EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); |
} |
-TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNoNewNetwork) { |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorSynchronous) { |
+ TestMigrationOnWriteError(SYNCHRONOUS); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorAsync) { |
+ TestMigrationOnWriteError(ASYNC); |
+} |
+ |
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNoNewNetwork( |
+ IoMode write_error_mode) { |
InitializeConnectionMigrationTest({kDefaultNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
MockQuicData socket_data; |
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
- socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); |
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); |
socket_data.AddSocketDataToFactory(&socket_factory_); |
// Create request and QuicHttpStream. |
@@ -2525,18 +2583,31 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNoNewNetwork) { |
// a connection migration attempt. |
HttpResponseInfo response; |
HttpRequestHeaders request_headers; |
- EXPECT_EQ( |
- ERR_QUIC_PROTOCOL_ERROR, |
- stream->SendRequest(request_headers, &response, callback_.callback())); |
- |
- // Migration fails, and session is marked as going away. |
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
+ callback_.callback())); |
+ // Run message loop to execute migration attempt. |
+ base::RunLoop().RunUntilIdle(); |
+ // Migration fails, and session is closed and deleted. |
+ 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, MigrateSessionOnWriteErrorNonMigratableStream) { |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnWriteErrorNoNewNetworkSynchronous) { |
+ TestMigrationOnWriteErrorNoNewNetwork(SYNCHRONOUS); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNoNewNetworkAsync) { |
+ TestMigrationOnWriteErrorNoNewNetwork(ASYNC); |
+} |
+ |
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorNonMigratableStream( |
+ IoMode write_error_mode) { |
+ DVLOG(1) << "Mode: " |
+ << ((write_error_mode == SYNCHRONOUS) ? "SYNCHRONOUS" : "ASYNC"); |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -2544,7 +2615,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNonMigratableStream) { |
MockQuicData socket_data; |
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
- socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); |
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); |
socket_data.AddSocketDataToFactory(&socket_factory_); |
// Create request and QuicHttpStream. |
@@ -2574,18 +2645,32 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorNonMigratableStream) { |
// a connection migration attempt. |
HttpResponseInfo response; |
HttpRequestHeaders request_headers; |
- EXPECT_EQ( |
- ERR_QUIC_PROTOCOL_ERROR, |
- stream->SendRequest(request_headers, &response, callback_.callback())); |
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
+ callback_.callback())); |
+ |
+ // Run message loop to execute migration attempt. |
+ base::RunLoop().RunUntilIdle(); |
- // Migration fails, and session is marked as going away. |
+ // Migration fails, and session is closed and deleted. |
+ 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, MigrateSessionOnWriteErrorMigrationDisabled) { |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnWriteErrorNonMigratableStreamSynchronous) { |
+ TestMigrationOnWriteErrorNonMigratableStream(SYNCHRONOUS); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnWriteErrorNonMigratableStreamAsync) { |
+ TestMigrationOnWriteErrorNonMigratableStream(ASYNC); |
+} |
+ |
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorMigrationDisabled( |
+ IoMode write_error_mode) { |
InitializeConnectionMigrationTest( |
{kDefaultNetworkForTests, kNewNetworkForTests}); |
ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
@@ -2593,7 +2678,7 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorMigrationDisabled) { |
MockQuicData socket_data; |
socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
- socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); |
+ socket_data.AddWrite(write_error_mode, ERR_ADDRESS_UNREACHABLE); |
socket_data.AddSocketDataToFactory(&socket_factory_); |
// Create request and QuicHttpStream. |
@@ -2626,15 +2711,304 @@ TEST_P(QuicStreamFactoryTest, MigrateSessionOnWriteErrorMigrationDisabled) { |
// a connection migration attempt. |
HttpResponseInfo response; |
HttpRequestHeaders request_headers; |
- EXPECT_EQ( |
- ERR_QUIC_PROTOCOL_ERROR, |
- stream->SendRequest(request_headers, &response, callback_.callback())); |
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
+ callback_.callback())); |
+ // Run message loop to execute migration attempt. |
+ base::RunLoop().RunUntilIdle(); |
+ // Migration fails, and session is closed and deleted. |
+ 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, |
+ MigrateSessionOnWriteErrorMigrationDisabledSynchronous) { |
+ TestMigrationOnWriteErrorMigrationDisabled(SYNCHRONOUS); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnWriteErrorMigrationDisabledAsync) { |
+ TestMigrationOnWriteErrorMigrationDisabled(ASYNC); |
+} |
+ |
+void QuicStreamFactoryTestBase::TestMigrationOnMultipleWriteErrors( |
+ IoMode first_write_error_mode, |
+ IoMode second_write_error_mode) { |
+ const int kMaxReadersPerQuicSession = 5; |
+ InitializeConnectionMigrationTest( |
+ {kDefaultNetworkForTests, kNewNetworkForTests}); |
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ |
+ // Set up kMaxReadersPerQuicSession socket data providers, since |
+ // migration will cause kMaxReadersPerQuicSession write failures as |
+ // the session hops repeatedly between the two networks. |
+ MockQuicData socket_data[kMaxReadersPerQuicSession + 1]; |
+ for (int i = 0; i <= kMaxReadersPerQuicSession; ++i) { |
+ // The last socket is created but never used. |
+ if (i < kMaxReadersPerQuicSession) { |
+ socket_data[i].AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
+ socket_data[i].AddWrite( |
+ (i % 2 == 0) ? first_write_error_mode : second_write_error_mode, |
+ ERR_FAILED); |
+ } |
+ socket_data[i].AddSocketDataToFactory(&socket_factory_); |
+ } |
+ |
+ // 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. This should cause a write error, which triggers |
+ // a connection migration attempt. |
+ HttpResponseInfo response; |
+ HttpRequestHeaders request_headers; |
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
+ callback_.callback())); |
+ EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(callback_.callback())); |
+ |
+ // Run the message loop so that data queued in the new socket is read by the |
+ // packet reader. |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // The connection should be closed because of a write error after migration. |
+ EXPECT_FALSE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); |
+ EXPECT_FALSE(HasActiveSession(host_port_pair_)); |
+ EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, |
+ stream->ReadResponseHeaders(callback_.callback())); |
+ |
+ stream.reset(); |
+ for (int i = 0; i <= kMaxReadersPerQuicSession; ++i) { |
+ DLOG(INFO) << "Socket number: " << i; |
+ EXPECT_TRUE(socket_data[i].AllReadDataConsumed()); |
+ EXPECT_TRUE(socket_data[i].AllWriteDataConsumed()); |
+ } |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncSync) { |
+ TestMigrationOnMultipleWriteErrors(SYNCHRONOUS, SYNCHRONOUS); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsSyncAsync) { |
+ TestMigrationOnMultipleWriteErrors(SYNCHRONOUS, ASYNC); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsAsyncSync) { |
+ TestMigrationOnMultipleWriteErrors(ASYNC, SYNCHRONOUS); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, MigrateSessionOnMultipleWriteErrorsAsyncAsync) { |
+ TestMigrationOnMultipleWriteErrors(ASYNC, ASYNC); |
+} |
+ |
+void QuicStreamFactoryTestBase::TestMigrationOnWriteErrorWithNotificationQueued( |
+ bool disconnected) { |
+ InitializeConnectionMigrationTest( |
+ {kDefaultNetworkForTests, kNewNetworkForTests}); |
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ |
+ MockQuicData socket_data; |
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
+ socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); |
+ socket_data.AddSocketDataToFactory(&socket_factory_); |
- // Migration fails, and session is marked as going away. |
+ // 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_)); |
+ |
+ // Set up second socket data provider that is used after |
+ // migration. The request is rewritten to this new socket, and the |
+ // response to the request is read on this new socket. |
+ MockQuicData socket_data1; |
+ socket_data1.AddWrite( |
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true)); |
+ socket_data1.AddRead( |
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false)); |
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket( |
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true)); |
+ socket_data1.AddSocketDataToFactory(&socket_factory_); |
+ |
+ // First queue a network change notification in the message loop. |
+ if (disconnected) { |
+ scoped_mock_network_change_notifier_->mock_network_change_notifier() |
+ ->QueueNetworkDisconnected(kDefaultNetworkForTests); |
+ } else { |
+ scoped_mock_network_change_notifier_->mock_network_change_notifier() |
+ ->QueueNetworkMadeDefault(kNewNetworkForTests); |
+ } |
+ // Send GET request on stream. This should cause a write error, |
+ // which triggers a connection migration attempt. This will queue a |
+ // migration attempt behind the notification in the message loop. |
+ HttpResponseInfo response; |
+ HttpRequestHeaders request_headers; |
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
+ callback_.callback())); |
+ |
+ 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()); |
+ |
+ stream.reset(); |
+ |
+ EXPECT_TRUE(socket_data.AllReadDataConsumed()); |
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed()); |
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnWriteErrorWithNetworkDisconnectedQueued) { |
+ TestMigrationOnWriteErrorWithNotificationQueued(/*disconnected=*/true); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnWriteErrorWithNetworkMadeDefaultQueued) { |
+ TestMigrationOnWriteErrorWithNotificationQueued(/*disconnected=*/false); |
+} |
+ |
+void QuicStreamFactoryTestBase::TestMigrationOnNotificationWithWriteErrorQueued( |
+ bool disconnected) { |
+ InitializeConnectionMigrationTest( |
+ {kDefaultNetworkForTests, kNewNetworkForTests}); |
+ ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); |
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); |
+ |
+ MockQuicData socket_data; |
+ socket_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
+ socket_data.AddWrite(SYNCHRONOUS, ERR_ADDRESS_UNREACHABLE); |
+ socket_data.AddSocketDataToFactory(&socket_factory_); |
+ |
+ // 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_)); |
+ |
+ // Set up second socket data provider that is used after |
+ // migration. The request is rewritten to this new socket, and the |
+ // response to the request is read on this new socket. |
+ MockQuicData socket_data1; |
+ socket_data1.AddWrite( |
+ ConstructGetRequestPacket(1, kClientDataStreamId1, true, true)); |
+ socket_data1.AddRead( |
+ ConstructOkResponsePacket(1, kClientDataStreamId1, false, false)); |
+ socket_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); |
+ socket_data1.AddWrite(client_maker_.MakeAckAndRstPacket( |
+ 2, false, kClientDataStreamId1, QUIC_STREAM_CANCELLED, 1, 1, 1, true)); |
+ socket_data1.AddSocketDataToFactory(&socket_factory_); |
+ |
+ // Send GET request on stream. This should cause a write error, |
+ // which triggers a connection migration attempt. This will queue a |
+ // migration attempt in the message loop. |
+ HttpResponseInfo response; |
+ HttpRequestHeaders request_headers; |
+ EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, |
+ callback_.callback())); |
+ |
+ // Now queue a network change notification in the message loop behind |
+ // the migration attempt. |
+ if (disconnected) { |
+ scoped_mock_network_change_notifier_->mock_network_change_notifier() |
+ ->QueueNetworkDisconnected(kDefaultNetworkForTests); |
+ } else { |
+ scoped_mock_network_change_notifier_->mock_network_change_notifier() |
+ ->QueueNetworkMadeDefault(kNewNetworkForTests); |
+ } |
+ |
+ 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()); |
+ |
+ stream.reset(); |
EXPECT_TRUE(socket_data.AllReadDataConsumed()); |
EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed()); |
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed()); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnNetworkDisconnectedWithWriteErrorQueued) { |
+ TestMigrationOnNotificationWithWriteErrorQueued(/*disconnected=*/true); |
+} |
+ |
+TEST_P(QuicStreamFactoryTest, |
+ MigrateSessionOnNetworkMadeDefaultWithWriteErrorQueued) { |
+ TestMigrationOnNotificationWithWriteErrorQueued(/*disconnected=*/true); |
} |
TEST_P(QuicStreamFactoryTest, MigrateSessionEarlyToBadSocket) { |