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. Then, subsequent requests will go over a new TCP
// connection instead of going back to the broken QUIC connection.
// This is a regression tests for crbug/731303.
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. Then, subsequent requests will go over a new TCP
connection instead of going back to the broken QUIC connection.
This is a regression tests for crbug/731303.
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 . Then subsequent requests will go over a new TCP connection instead of going back to the broken QUIC connection . This is a regression tests for crbug / 731303 .
TEST_P(QuicNetworkTransactionTest,
       ResetPooledAfterHandshakeConfirmedThenBroken) {
  context_.params()->allow_remote_alt_svc = true;
  GURL origin1 = request_.url;
  GURL origin2("https://www.example.org/");
  ASSERT_NE(origin1.host(), origin2.host());
  MockQuicData mock_quic_data(version_);
  scoped_refptr<X509Certificate> cert(
      ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
  ASSERT_TRUE(cert->VerifyNameMatch("www.example.org"));
  ASSERT_TRUE(cert->VerifyNameMatch("mail.example.org"));
  ProofVerifyDetailsChromium verify_details;
  verify_details.cert_verify_result.verified_cert = cert;
  verify_details.cert_verify_result.is_issued_by_known_root = true;
  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
  int packet_num = 1;
  if (VersionUsesHttp3(version_.transport_version)) {
    mock_quic_data.AddWrite(SYNCHRONOUS,
                            ConstructInitialSettingsPacket(packet_num++));
  }
  mock_quic_data.AddWrite(
      SYNCHRONOUS,
      ConstructClientRequestHeadersPacket(
          packet_num++, GetNthClientInitiatedBidirectionalStreamId(0), true,
          true, GetRequestHeaders("GET", "https", "/")));
  mock_quic_data.AddRead(
      ASYNC, ConstructServerResponseHeadersPacket(
                 1, GetNthClientInitiatedBidirectionalStreamId(0), false, false,
                 GetResponseHeaders("200 OK")));
  std::string header = ConstructDataHeader(6);
  mock_quic_data.AddRead(
      ASYNC, ConstructServerDataPacket(
                 2, GetNthClientInitiatedBidirectionalStreamId(0), false, true,
                 header + "hello!"));
  mock_quic_data.AddWrite(SYNCHRONOUS,
                          ConstructClientAckPacket(packet_num++, 2, 1, 1));
  QuicTestPacketMaker client_maker2(
      version_,
      quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()),
      context_.clock(), origin2.host(), quic::Perspective::IS_CLIENT,
      client_headers_include_h2_stream_dependency_);
  QuicTestPacketMaker server_maker2(
      version_,
      quic::QuicUtils::CreateRandomConnectionId(context_.random_generator()),
      context_.clock(), origin2.host(), quic::Perspective::IS_SERVER, false);
  mock_quic_data.AddWrite(
      SYNCHRONOUS,
      ConstructClientRequestHeadersPacket(
          packet_num++, GetNthClientInitiatedBidirectionalStreamId(1), false,
          true, GetRequestHeaders("GET", "https", "/", &client_maker2),
          GetNthClientInitiatedBidirectionalStreamId(0)));
  mock_quic_data.AddRead(
      ASYNC, ConstructServerRstPacket(
                 3, false, GetNthClientInitiatedBidirectionalStreamId(1),
                 quic::QUIC_HEADERS_TOO_LARGE));
  if (VersionUsesHttp3(version_.transport_version)) {
    mock_quic_data.AddWrite(
        SYNCHRONOUS, ConstructClientDataPacket(
                         packet_num++, GetQpackDecoderStreamId(), true, false,
                         StreamCancellationQpackDecoderInstruction(1)));
  }
  mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING);  
  mock_quic_data.AddRead(ASYNC, 0);               
  mock_quic_data.AddSocketDataToFactory(&socket_factory_);
  MockWrite http_writes[] = {
      MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n"),
      MockWrite(SYNCHRONOUS, 1, "Host: www.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_);
  socket_factory_.AddSocketDataProvider(&http_data);
  socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
  CreateSession();
  QuicStreamFactoryPeer::SetAlarmFactory(
      session_->quic_stream_factory(),
      std::make_unique<QuicChromiumAlarmFactory>(quic_task_runner_.get(),
                                                 context_.clock()));
  base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
  AlternativeService alternative1(kProtoQUIC, origin1.host(), 443);
  http_server_properties_->SetQuicAlternativeService(
      url::SchemeHostPort(origin1), NetworkIsolationKey(), alternative1,
      expiration, supported_versions_);
  AlternativeService alternative2(kProtoQUIC, origin2.host(), 443);
  http_server_properties_->SetQuicAlternativeService(
      url::SchemeHostPort(origin2), NetworkIsolationKey(), alternative2,
      expiration, supported_versions_);
  SendRequestAndExpectQuicResponse("hello!");
  request_.url = origin2;
  SendRequestAndExpectHttpResponse("hello world");
  EXPECT_FALSE(http_server_properties_->IsAlternativeServiceBroken(
      alternative1, NetworkIsolationKey()))
      << alternative1.ToString();
  EXPECT_TRUE(http_server_properties_->IsAlternativeServiceBroken(
      alternative2, NetworkIsolationKey()))
      << alternative2.ToString();
  SendRequestAndExpectHttpResponse("hello world");
}
TEST_P ( QuicNetworkTransactionTest , ResetPooledAfterHandshakeConfirmedThenBroken ) { context_ . params ( ) -> allow_remote_alt_svc = true ; GURL origin1 = request_ . url ; GURL origin2 ( " " ) ; ASSERT_NE ( origin1 . host ( ) , origin2 . host ( ) ) ; MockQuicData mock_quic_data ( version_ ) ; scoped_refptr < X509Certificate > cert ( ImportCertFromFile ( GetTestCertsDirectory ( ) , " " ) ) ; ASSERT_TRUE ( cert -> VerifyNameMatch ( " " ) ) ; ASSERT_TRUE ( cert -> VerifyNameMatch ( " " ) ) ; ProofVerifyDetailsChromium verify_details ; verify_details . cert_verify_result . verified_cert = cert ; verify_details . cert_verify_result . is_issued_by_known_root = true ; crypto_client_stream_factory_ . AddProofVerifyDetails ( & verify_details ) ; int packet_num = 1 ; if ( VersionUsesHttp3 ( version_ . transport_version ) ) { mock_quic_data . AddWrite ( SYNCHRONOUS , ConstructInitialSettingsPacket ( packet_num ++ ) ) ; } mock_quic_data . AddWrite ( SYNCHRONOUS , ConstructClientRequestHeadersPacket ( packet_num ++ , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , true , true , GetRequestHeaders ( " " , " " , " " ) ) ) ; mock_quic_data . AddRead ( ASYNC , ConstructServerResponseHeadersPacket ( 1 , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , false , false , GetResponseHeaders ( " " ) ) ) ; std :: string header = ConstructDataHeader ( 6 ) ; mock_quic_data . AddRead ( ASYNC , ConstructServerDataPacket ( 2 , GetNthClientInitiatedBidirectionalStreamId ( 0 ) , false , true , header + " " ) ) ; mock_quic_data . AddWrite ( SYNCHRONOUS , ConstructClientAckPacket ( packet_num ++ , 2 , 1 , 1 ) ) ; QuicTestPacketMaker client_maker2 ( version_ , quic :: QuicUtils :: CreateRandomConnectionId ( context_ . random_generator ( ) ) , context_ . clock ( ) , origin2 . host ( ) , quic :: Perspective :: IS_CLIENT , client_headers_include_h2_stream_dependency_ ) ; QuicTestPacketMaker server_maker2 ( version_ , quic :: QuicUtils :: CreateRandomConnectionId ( context_ . random_generator ( ) ) , context_ . clock ( ) , origin2 . host ( ) , quic :: Perspective :: IS_SERVER , false ) ; mock_quic_data . AddWrite ( SYNCHRONOUS , ConstructClientRequestHeadersPacket ( packet_num ++ , GetNthClientInitiatedBidirectionalStreamId ( 1 ) , false , true , GetRequestHeaders ( " " , " " , " " , & client_maker2 ) , GetNthClientInitiatedBidirectionalStreamId ( 0 ) ) ) ; mock_quic_data . AddRead ( ASYNC , ConstructServerRstPacket ( 3 , false , GetNthClientInitiatedBidirectionalStreamId ( 1 ) , quic :: QUIC_HEADERS_TOO_LARGE ) ) ; if ( VersionUsesHttp3 ( version_ . transport_version ) ) { mock_quic_data . AddWrite ( SYNCHRONOUS , ConstructClientDataPacket ( packet_num ++ , GetQpackDecoderStreamId ( ) , true , false , StreamCancellationQpackDecoderInstruction ( 1 ) ) ) ; } mock_quic_data . AddRead ( ASYNC , ERR_IO_PENDING ) ; mock_quic_data . AddRead ( ASYNC , 0 ) ; mock_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_ ) ; socket_factory_ . AddSocketDataProvider ( & http_data ) ; socket_factory_ . AddSSLSocketDataProvider ( & ssl_data_ ) ; CreateSession ( ) ; QuicStreamFactoryPeer :: SetAlarmFactory ( session_ -> quic_stream_factory ( ) , std :: make_unique < QuicChromiumAlarmFactory > ( quic_task_runner_ . get ( ) , context_ . clock ( ) ) ) ; base :: Time expiration = base :: Time :: Now ( ) + base :: TimeDelta :: FromDays ( 1 ) ; AlternativeService alternative1 ( kProtoQUIC , origin1 . host ( ) , 443 ) ; http_server_properties_ -> SetQuicAlternativeService ( url :: SchemeHostPort ( origin1 ) , NetworkIsolationKey ( ) , alternative1 , expiration , supported_versions_ ) ; AlternativeService alternative2 ( kProtoQUIC , origin2 . host ( ) , 443 ) ; http_server_properties_ -> SetQuicAlternativeService ( url :: SchemeHostPort ( origin2 ) , NetworkIsolationKey ( ) , alternative2 , expiration , supported_versions_ ) ; SendRequestAndExpectQuicResponse ( " " ) ; request_ . url = origin2 ; SendRequestAndExpectHttpResponse ( " " ) ; EXPECT_FALSE ( http_server_properties_ -> IsAlternativeServiceBroken ( alternative1 , NetworkIsolationKey ( ) ) ) << alternative1 . ToString ( ) ; EXPECT_TRUE ( http_server_properties_ -> IsAlternativeServiceBroken ( alternative2 , NetworkIsolationKey ( ) ) ) << alternative2 . ToString ( ) ; SendRequestAndExpectHttpResponse ( " " ) ; }
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 .
// First request. // Second request will go over the pooled QUIC connection, but will be // reset by the server. // No more data to read // EOF // After that fails, it will be resent via TCP. // Then the next request to the second origin will be sent over TCP. // Set up alternative service for |origin1|. // Set up alternative service for |origin2|. // First request opens connection to |destination1| // with quic::QuicServerId.host() == origin1.host(). // Second request pools to existing connection with same destination, // because certificate matches, even though quic::QuicServerId is different. // After it is reset, it will fail back to TCP and mark QUIC as broken. // The third request should use a new TCP connection, not the broken // QUIC connection.