src/net/quic/quic_network_transaction_unittest.cc
// Much like above test, but verifies NetworkIsolationKeys are respected.
Much like above test, but verifies NetworkIsolationKeys are respected.
Much like above test but verifies NetworkIsolationKeys are respected .
TEST_P(QuicNetworkTransactionTest,
       RetryOnAlternateNetworkWhileTCPSucceedsWithNetworkIsolationKey) {
  if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) {
    return;
  }
  const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/"));
  const net::NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1);
  const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/"));
  const net::NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2);
  base::test::ScopedFeatureList feature_list;
  feature_list.InitWithFeatures(
      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
       features::kPartitionConnectionsByNetworkIsolationKey},
      {});
  http_server_properties_ = std::make_unique<HttpServerProperties>();
  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_);
  MockWrite http_writes[] = {
      MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
      MockWrite(SYNCHRONOUS, 1, "Host: mail.example.org\r\n"),
      MockWrite(SYNCHRONOUS, 2, "Connection: keep-alive\r\n\r\n")};
  MockRead http_reads[] = {
      MockRead(SYNCHRONOUS, 3, "HTTP/1.1 200 OK\r\n"),
      MockRead(SYNCHRONOUS, 4, kQuicAlternativeServiceHeader),
      MockRead(SYNCHRONOUS, 5, "TCP succeeds"), MockRead(SYNCHRONOUS, OK, 6)};
  SequencedSocketData http_data(http_reads, http_writes);
  socket_factory_.AddSocketDataProvider(&http_data);
  socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
  MockQuicData quic_data2(version_);
  quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  
  quic_data2.AddWrite(SYNCHRONOUS,
                      client_maker_->MakeDummyCHLOPacket(1));  
  client_maker_->SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
  if (VersionUsesHttp3(version_.transport_version))
    quic_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket(2));
  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, kNetworkIsolationKey1);
  AddQuicAlternateProtocolMapping(
      MockCryptoClientStream::COLD_START_WITH_CHLO_SENT, kNetworkIsolationKey2);
  request_.network_isolation_key = kNetworkIsolationKey1;
  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();
  EXPECT_THAT(callback.WaitForResult(), IsOk());
  CheckResponseData(&trans, "TCP succeeds");
  quic_task_runner_->FastForwardBy(quic::QuicTime::Delta::FromSeconds(4));
  ASSERT_TRUE(quic_data.AllReadDataConsumed());
  ASSERT_TRUE(quic_data.AllWriteDataConsumed());
  ExpectQuicAlternateProtocolMapping(kNetworkIsolationKey1);
  ExpectQuicAlternateProtocolMapping(kNetworkIsolationKey2);
  crypto_client_stream_factory_.last_stream()
      ->NotifySessionOneRttKeyAvailable();
  base::RunLoop().RunUntilIdle();
  ExpectBrokenAlternateProtocolMapping(kNetworkIsolationKey1);
  ExpectQuicAlternateProtocolMapping(kNetworkIsolationKey2);
  scoped_mock_change_notifier_->mock_network_change_notifier()
      ->NotifyNetworkMadeDefault(kNewNetworkForTests);
  ExpectQuicAlternateProtocolMapping(kNetworkIsolationKey1);
  ExpectQuicAlternateProtocolMapping(kNetworkIsolationKey2);
  ASSERT_TRUE(quic_data2.AllReadDataConsumed());
  ASSERT_TRUE(quic_data2.AllWriteDataConsumed());
}
TEST_P ( QuicNetworkTransactionTest , RetryOnAlternateNetworkWhileTCPSucceedsWithNetworkIsolationKey ) { if ( version_ . handshake_protocol == quic :: PROTOCOL_TLS1_3 ) { return ; } const url :: Origin kOrigin1 = url :: Origin :: Create ( GURL ( " " ) ) ; const net :: NetworkIsolationKey kNetworkIsolationKey1 ( kOrigin1 , kOrigin1 ) ; const url :: Origin kOrigin2 = url :: Origin :: Create ( GURL ( " " ) ) ; const net :: NetworkIsolationKey kNetworkIsolationKey2 ( kOrigin2 , kOrigin2 ) ; base :: test :: ScopedFeatureList feature_list ; feature_list . InitWithFeatures ( { features :: kPartitionHttpServerPropertiesByNetworkIsolationKey , features :: kPartitionConnectionsByNetworkIsolationKey } , { } ) ; http_server_properties_ = std :: make_unique < HttpServerProperties > ( ) ; 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_ ) ; MockWrite http_writes [ ] = { MockWrite ( SYNCHRONOUS , 0 , " \r \n " ) , MockWrite ( SYNCHRONOUS , 1 , " \r \n " ) , MockWrite ( SYNCHRONOUS , 2 , " \r \n \r \n " ) } ; MockRead http_reads [ ] = { MockRead ( SYNCHRONOUS , 3 , " \r \n " ) , MockRead ( SYNCHRONOUS , 4 , kQuicAlternativeServiceHeader ) , MockRead ( SYNCHRONOUS , 5 , " " ) , MockRead ( SYNCHRONOUS , OK , 6 ) } ; SequencedSocketData http_data ( http_reads , http_writes ) ; socket_factory_ . AddSocketDataProvider ( & http_data ) ; socket_factory_ . AddSSLSocketDataProvider ( & ssl_data_ ) ; MockQuicData quic_data2 ( version_ ) ; quic_data2 . AddRead ( SYNCHRONOUS , ERR_IO_PENDING ) ; quic_data2 . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeDummyCHLOPacket ( 1 ) ) ; client_maker_ -> SetEncryptionLevel ( quic :: ENCRYPTION_FORWARD_SECURE ) ; if ( VersionUsesHttp3 ( version_ . transport_version ) ) quic_data2 . AddWrite ( SYNCHRONOUS , ConstructInitialSettingsPacket ( 2 ) ) ; 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 , kNetworkIsolationKey1 ) ; AddQuicAlternateProtocolMapping ( MockCryptoClientStream :: COLD_START_WITH_CHLO_SENT , kNetworkIsolationKey2 ) ; request_ . network_isolation_key = kNetworkIsolationKey1 ; 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 ( ) ; EXPECT_THAT ( callback . WaitForResult ( ) , IsOk ( ) ) ; CheckResponseData ( & trans , " " ) ; quic_task_runner_ -> FastForwardBy ( quic :: QuicTime :: Delta :: FromSeconds ( 4 ) ) ; ASSERT_TRUE ( quic_data . AllReadDataConsumed ( ) ) ; ASSERT_TRUE ( quic_data . AllWriteDataConsumed ( ) ) ; ExpectQuicAlternateProtocolMapping ( kNetworkIsolationKey1 ) ; ExpectQuicAlternateProtocolMapping ( kNetworkIsolationKey2 ) ; crypto_client_stream_factory_ . last_stream ( ) -> NotifySessionOneRttKeyAvailable ( ) ; base :: RunLoop ( ) . RunUntilIdle ( ) ; ExpectBrokenAlternateProtocolMapping ( kNetworkIsolationKey1 ) ; ExpectQuicAlternateProtocolMapping ( kNetworkIsolationKey2 ) ; scoped_mock_change_notifier_ -> mock_network_change_notifier ( ) -> NotifyNetworkMadeDefault ( kNewNetworkForTests ) ; ExpectQuicAlternateProtocolMapping ( kNetworkIsolationKey1 ) ; ExpectQuicAlternateProtocolMapping ( kNetworkIsolationKey2 ) ; ASSERT_TRUE ( quic_data2 . AllReadDataConsumed ( ) ) ; ASSERT_TRUE ( quic_data2 . AllWriteDataConsumed ( ) ) ; }
Much like above test, but verifies NetworkIsolationKeys are respected.
Much like above test but verifies NetworkIsolationKeys are respected .
// QUIC with TLS1.3 handshake doesn't support 0-rtt. // enabled_features // Need to partition connections by NetworkIsolationKey for // QuicSessionAliasKey to include NetworkIsolationKeys. // disabled_features // Since HttpServerProperties caches the feature value, have to create a new // one. // 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 successful TCP data so that TCP job will succeed. // Quic connection will be retried on the alternate network after the initial // one fails on the default network. // Handing read. // CHLO // 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. // Request will be served with TCP job. // Fast forward to idle timeout the original connection. A new connection will // be kicked off on the alternate network. // The second connection hasn't finish handshake, verify that QUIC is not // marked as broken. // Explicitly confirm the handshake on the second connection. // Run message loop to execute posted tasks, which will notify JoController // about the orphaned job status. // Verify that QUIC is marked as broken for kNetworkIsolationKey1 only. // Deliver a message to notify the new network becomes default, the previous // brokenness will be clear as the brokenness is bond with old default // network.