src/net/quic/quic_network_transaction_unittest.cc
// This test verifies that a new QUIC connection will be attempted on the
// alternate network if the original QUIC connection fails with idle timeout
// before handshake is confirmed. If TCP doesn't succeed but QUIC on the
// alternative network succeeds, QUIC is not marked as broken.
This test verifies that a new QUIC connection will be attempted on the
alternate network if the original QUIC connection fails with idle timeout
before handshake is confirmed. If TCP doesn't succeed but QUIC on the
alternative network succeeds, QUIC is not marked as broken.
This test verifies that a new QUIC connection will be attempted on the alternate network if the original QUIC connection fails with idle timeout before handshake is confirmed . If TCP doesn ' t succeed but QUIC on the alternative network succeeds QUIC is not marked as broken .
TEST_P(QuicNetworkTransactionTest, RetryOnAlternateNetworkWhileTCPHanging) {
  if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) {
    return;
  }
  SetUpTestForRetryConnectionOnAlternateNetwork();
  client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
  MockQuicData quic_data(version_);
  quic_data.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  
  int packet_num = 1;
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));  
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeDummyCHLOPacket(packet_num++));
  quic_data.AddWrite(SYNCHRONOUS,
                     client_maker_->MakeConnectionClosePacket(
                         packet_num++, true, quic::QUIC_NETWORK_IDLE_TIMEOUT,
                         "No recent network activity after 4s. Timeout:4s"));
  quic_data.AddSocketDataToFactory(&socket_factory_);
  AddHangingNonAlternateProtocolSocketData();
  MockQuicData quic_data2(version_);
  packet_num = 1;
  quic_data2.AddWrite(
      SYNCHRONOUS,
      client_maker_->MakeDummyCHLOPacket(packet_num++));  
  const std::string body = "hello!";
  std::string header = ConstructDataHeader(body.length());
  client_maker_->SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
  if (VersionUsesHttp3(version_.transport_version)) {
    quic_data2.AddWrite(SYNCHRONOUS,
                        ConstructInitialSettingsPacket(packet_num++));
  }
  quic_data2.AddWrite(
      SYNCHRONOUS,
      ConstructClientRequestHeadersPacket(
          packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), true,
          true, GetRequestHeaders("GET", "https", "/")));
  quic_data2.AddRead(
      ASYNC, ConstructServerResponseHeadersPacket(
                 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false,
                 GetResponseHeaders("200 OK")));
  quic_data2.AddRead(
      ASYNC, ConstructServerDataPacket(
                 2, GetNthClientInitiatedBidirectionalStreamId(0), false, true,
                 header + body));
  quic_data2.AddWrite(SYNCHRONOUS,
                      ConstructClientAckPacket(packet_num++, 2, 1, 1));
  quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  
  quic_data2.AddSocketDataToFactory(&socket_factory_);
  host_resolver_.set_synchronous_mode(true);
  host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
                                           "");
  CreateSession();
  session_->quic_stream_factory()->set_is_quic_known_to_work_on_current_network(
      false);
  QuicStreamFactoryPeer::SetAlarmFactory(
      session_->quic_stream_factory(),
      std::make_unique<QuicChromiumAlarmFactory>(quic_task_runner_.get(),
                                                 context_.clock()));
  AddQuicAlternateProtocolMapping(
      MockCryptoClientStream::COLD_START_WITH_CHLO_SENT);
  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback callback;
  int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
  base::RunLoop().RunUntilIdle();
  quic_task_runner_->FastForwardBy(quic::QuicTime::Delta::FromSeconds(4));
  ASSERT_TRUE(quic_data.AllReadDataConsumed());
  ASSERT_TRUE(quic_data.AllWriteDataConsumed());
  ExpectQuicAlternateProtocolMapping();
  crypto_client_stream_factory_.last_stream()
      ->NotifySessionOneRttKeyAvailable();
  EXPECT_THAT(callback.WaitForResult(), IsOk());
  CheckResponseData(&trans, body);
  ExpectQuicAlternateProtocolMapping();
  scoped_mock_change_notifier_->mock_network_change_notifier()
      ->NotifyNetworkMadeDefault(kNewNetworkForTests);
  ExpectQuicAlternateProtocolMapping();
  ASSERT_TRUE(quic_data2.AllReadDataConsumed());
  ASSERT_TRUE(quic_data2.AllWriteDataConsumed());
}
TEST_P ( QuicNetworkTransactionTest , RetryOnAlternateNetworkWhileTCPHanging ) { if ( version_ . handshake_protocol == quic :: PROTOCOL_TLS1_3 ) { return ; } SetUpTestForRetryConnectionOnAlternateNetwork ( ) ; client_maker_ -> SetEncryptionLevel ( quic :: ENCRYPTION_ZERO_RTT ) ; MockQuicData quic_data ( version_ ) ; quic_data . AddRead ( SYNCHRONOUS , ERR_IO_PENDING ) ; int packet_num = 1 ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeConnectionClosePacket ( packet_num ++ , true , quic :: QUIC_NETWORK_IDLE_TIMEOUT , " " ) ) ; quic_data . AddSocketDataToFactory ( & socket_factory_ ) ; AddHangingNonAlternateProtocolSocketData ( ) ; MockQuicData quic_data2 ( version_ ) ; packet_num = 1 ; quic_data2 . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( packet_num ++ ) ) ; const std :: string body = " " ; std :: string header = ConstructDataHeader ( body . length ( ) ) ; client_maker_ -> SetEncryptionLevel ( quic :: ENCRYPTION_FORWARD_SECURE ) ; if ( VersionUsesHttp3 ( version_ . transport_version ) ) { quic_data2 . AddWrite ( SYNCHRONOUS , ConstructInitialSettingsPacket ( packet_num ++ ) ) ; } quic_data2 . AddWrite ( SYNCHRONOUS , ConstructClientRequestHeadersPacket ( packet_num ++ , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , true , true , GetRequestHeaders ( " " , " " , " " ) ) ) ; quic_data2 . AddRead ( ASYNC , ConstructServerResponseHeadersPacket ( 1 , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , false , false , GetResponseHeaders ( " " ) ) ) ; quic_data2 . AddRead ( ASYNC , ConstructServerDataPacket ( 2 , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , false , true , header + body ) ) ; quic_data2 . AddWrite ( SYNCHRONOUS , ConstructClientAckPacket ( packet_num ++ , 2 , 1 , 1 ) ) ; quic_data2 . AddRead ( SYNCHRONOUS , ERR_IO_PENDING ) ; quic_data2 . AddSocketDataToFactory ( & socket_factory_ ) ; host_resolver_ . set_synchronous_mode ( true ) ; host_resolver_ . rules ( ) -> AddIPLiteralRule ( " " , " " , " " ) ; CreateSession ( ) ; session_ -> quic_stream_factory ( ) -> set_is_quic_known_to_work_on_current_network ( false ) ; QuicStreamFactoryPeer :: SetAlarmFactory ( session_ -> quic_stream_factory ( ) , std :: make_unique < QuicChromiumAlarmFactory > ( quic_task_runner_ . get ( ) , context_ . clock ( ) ) ) ; AddQuicAlternateProtocolMapping ( MockCryptoClientStream :: COLD_START_WITH_CHLO_SENT ) ; HttpNetworkTransaction trans ( DEFAULT_PRIORITY , session_ . get ( ) ) ; TestCompletionCallback callback ; int rv = trans . Start ( & request_ , callback . callback ( ) , net_log_ . bound ( ) ) ; EXPECT_THAT ( rv , IsError ( ERR_IO_PENDING ) ) ; base :: RunLoop ( ) . RunUntilIdle ( ) ; quic_task_runner_ -> FastForwardBy ( quic :: QuicTime :: Delta :: FromSeconds ( 4 ) ) ; ASSERT_TRUE ( quic_data . AllReadDataConsumed ( ) ) ; ASSERT_TRUE ( quic_data . AllWriteDataConsumed ( ) ) ; ExpectQuicAlternateProtocolMapping ( ) ; crypto_client_stream_factory_ . last_stream ( ) -> NotifySessionOneRttKeyAvailable ( ) ; EXPECT_THAT ( callback . WaitForResult ( ) , IsOk ( ) ) ; CheckResponseData ( & trans , body ) ; ExpectQuicAlternateProtocolMapping ( ) ; scoped_mock_change_notifier_ -> mock_network_change_notifier ( ) -> NotifyNetworkMadeDefault ( kNewNetworkForTests ) ; ExpectQuicAlternateProtocolMapping ( ) ; ASSERT_TRUE ( quic_data2 . AllReadDataConsumed ( ) ) ; ASSERT_TRUE ( quic_data2 . AllWriteDataConsumed ( ) ) ; }
This test verifies that a new QUIC connection will be attempted on the
alternate network if the original QUIC connection fails with idle timeout
before handshake is confirmed.
This test verifies that a new QUIC connection will be attempted on the alternate network if the original QUIC connection fails with idle timeout before handshake is confirmed .
// QUIC with TLS1.3 handshake doesn't support 0-rtt. // The request will initially go out over QUIC. // Hanging read // CHLO // Retranmit the handshake messages. // After timeout, connection will be closed with QUIC_NETWORK_IDLE_TIMEOUT. // Add hanging TCP data so that TCP job will never succeeded. // Quic connection will then be retried on the alternate network. // CHLO // No more data to read // Resolve the host resolution synchronously. // Use a TestTaskRunner to avoid waiting in real time for timeouts. // Add alternate protocol mapping to race QUIC and TCP. // QUIC connection requires handshake to be confirmed and sends CHLO to the // peer. // Pump the message loop to get the request started. // Fast forward to idle timeout the original connection. A new connection will // be kicked off on the alternate network. // Verify that QUIC is not marked as broken. // Explicitly confirm the handshake on the second connection. // Read the response. // Verify that QUIC is not marked as broken. // Deliver a message to notify the new network becomes default.