src/net/quic/quic_network_transaction_unittest.cc
// Verify that with retry_without_alt_svc_on_quic_errors enabled, if a QUIC
// request is reset from, then QUIC will be marked as broken and the request
// retried over TCP.
Verify that with retry_without_alt_svc_on_quic_errors enabled, if a QUIC
request is reset from, then QUIC will be marked as broken and the request
retried over TCP.
Verify that with retry_without_alt_svc_on_quic_errors enabled if a QUIC request is reset from then QUIC will be marked as broken and the request retried over TCP .
TEST_P(QuicNetworkTransactionTest, ResetAfterHandshakeConfirmedThenBroken) {
  if (version_.handshake_protocol == quic::PROTOCOL_TLS1_3) {
    return;
  }
  MockQuicData quic_data(version_);
  spdy::SpdyPriority priority =
      ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
  client_maker_->SetEncryptionLevel(quic::ENCRYPTION_ZERO_RTT);
  int packet_num = 1;
  if (VersionUsesHttp3(version_.transport_version)) {
    quic_data.AddWrite(SYNCHRONOUS,
                       ConstructInitialSettingsPacket(packet_num++));
  }
  quic_data.AddWrite(
      SYNCHRONOUS,
      client_maker_->MakeRequestHeadersPacket(
          packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), true,
          true, priority, GetRequestHeaders("GET", "https", "/"), 0, nullptr));
  client_maker_->SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
  quic_data.AddRead(ASYNC, ERR_IO_PENDING);  
  quic_data.AddRead(ASYNC,
                    ConstructServerRstPacket(
                        1, false, GetNthClientInitiatedBidirectionalStreamId(0),
                        quic::QUIC_HEADERS_TOO_LARGE));
  if (VersionUsesHttp3(version_.transport_version)) {
    quic_data.AddWrite(SYNCHRONOUS,
                       ConstructClientDataPacket(
                           packet_num++, GetQpackDecoderStreamId(), true, false,
                           StreamCancellationQpackDecoderInstruction(0)));
  }
  quic_data.AddRead(ASYNC, OK);
  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, "hello world"), MockRead(SYNCHRONOUS, OK, 6)};
  SequencedSocketData http_data(http_reads, http_writes);
  socket_factory_.AddSocketDataProvider(&http_data);
  socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
  host_resolver_.set_synchronous_mode(true);
  host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
                                           "");
  CreateSession();
  AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
  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();
  crypto_client_stream_factory_.last_stream()
      ->NotifySessionOneRttKeyAvailable();
  quic_data.Resume();
  ASSERT_TRUE(quic_data.AllWriteDataConsumed());
  ExpectQuicAlternateProtocolMapping();
  EXPECT_THAT(callback.WaitForResult(), IsOk());
  ASSERT_TRUE(quic_data.AllWriteDataConsumed());
  ASSERT_FALSE(http_data.AllReadDataConsumed());
  CheckResponseData(&trans, "hello world");
  ExpectBrokenAlternateProtocolMapping();
  ASSERT_TRUE(http_data.AllWriteDataConsumed());
  ASSERT_TRUE(http_data.AllReadDataConsumed());
}
TEST_P ( QuicNetworkTransactionTest , ResetAfterHandshakeConfirmedThenBroken ) { if ( version_ . handshake_protocol == quic :: PROTOCOL_TLS1_3 ) { return ; } MockQuicData quic_data ( version_ ) ; spdy :: SpdyPriority priority = ConvertRequestPriorityToQuicPriority ( DEFAULT_PRIORITY ) ; client_maker_ -> SetEncryptionLevel ( quic :: ENCRYPTION_ZERO_RTT ) ; int packet_num = 1 ; if ( VersionUsesHttp3 ( version_ . transport_version ) ) { quic_data . AddWrite ( SYNCHRONOUS , ConstructInitialSettingsPacket ( packet_num ++ ) ) ; } quic_data . AddWrite ( SYNCHRONOUS , client_maker_ -> MakeRequestHeadersPacket ( packet_num ++ , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , true , true , priority , GetRequestHeaders ( " " , " " , " " ) , 0 , nullptr ) ) ; client_maker_ -> SetEncryptionLevel ( quic :: ENCRYPTION_FORWARD_SECURE ) ; quic_data . AddRead ( ASYNC , ERR_IO_PENDING ) ; quic_data . AddRead ( ASYNC , ConstructServerRstPacket ( 1 , false , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , quic :: QUIC_HEADERS_TOO_LARGE ) ) ; if ( VersionUsesHttp3 ( version_ . transport_version ) ) { quic_data . AddWrite ( SYNCHRONOUS , ConstructClientDataPacket ( packet_num ++ , GetQpackDecoderStreamId ( ) , true , false , StreamCancellationQpackDecoderInstruction ( 0 ) ) ) ; } quic_data . AddRead ( ASYNC , OK ) ; 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_ ) ; host_resolver_ . set_synchronous_mode ( true ) ; host_resolver_ . rules ( ) -> AddIPLiteralRule ( " " , " " , " " ) ; CreateSession ( ) ; AddQuicAlternateProtocolMapping ( MockCryptoClientStream :: ZERO_RTT ) ; 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 ( ) ; crypto_client_stream_factory_ . last_stream ( ) -> NotifySessionOneRttKeyAvailable ( ) ; quic_data . Resume ( ) ; ASSERT_TRUE ( quic_data . AllWriteDataConsumed ( ) ) ; ExpectQuicAlternateProtocolMapping ( ) ; EXPECT_THAT ( callback . WaitForResult ( ) , IsOk ( ) ) ; ASSERT_TRUE ( quic_data . AllWriteDataConsumed ( ) ) ; ASSERT_FALSE ( http_data . AllReadDataConsumed ( ) ) ; CheckResponseData ( & trans , " " ) ; ExpectBrokenAlternateProtocolMapping ( ) ; ASSERT_TRUE ( http_data . AllWriteDataConsumed ( ) ) ; ASSERT_TRUE ( http_data . AllReadDataConsumed ( ) ) ; }
Verify that with retry_without_alt_svc_on_quic_errors enabled, if a QUIC
request is reset from, then QUIC will be marked as broken and the request
retried over TCP.
Verify that with retry_without_alt_svc_on_quic_errors enabled if a QUIC request is reset from then QUIC will be marked as broken and the request retried over TCP .
// QUIC with TLS1.3 handshake doesn't support 0-rtt. // The request will initially go out over QUIC. // Pause // After that fails, it will be resent via TCP. // In order for a new QUIC session to be established via alternate-protocol // without racing an HTTP connection, we need the host resolution to happen // synchronously.  Of course, even though QUIC *could* perform a 0-RTT // connection to the the server, in this test we require confirmation // before encrypting so the HTTP job will still start. // Pump the message loop to get the request started. // Explicitly confirm the handshake. // Run the QUIC session to completion. // Let the transaction proceed which will result in QUIC being marked // as broken and the request falling back to TCP. // Read the response body over TCP.