Fix original issue of QNZR by only forcing the first CHLO to be inchoate.
Also replace the connection option with QNZ2.

Manually tested with netlog at https://drive.google.com/file/d/1WDFHBZJGy9ZM6hXwriyH3GEjvgdUVy4W/view?usp=sharing

Protected by client connection option QNZ2.

PiperOrigin-RevId: 338360564
Change-Id: I1cac9589006b59ff32dbd325e97ca77d70e2b6cb
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index b5ed5c7..50fa103 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -27,7 +27,8 @@
 typedef std::string ServerConfigID;
 
 // The following tags have been deprecated and should not be reused:
-// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL"
+// "1CON", "BBQ4", "NCON", "RCID", "SREJ", "TBKP", "TB10", "SCLS", "SMHL",
+// "QNZR"
 
 // clang-format off
 const QuicTag kCHLO = TAG('C', 'H', 'L', 'O');   // Client hello
@@ -369,7 +370,8 @@
 const QuicTag kXLCT = TAG('X', 'L', 'C', 'T');   // Expected leaf certificate.
 const QuicTag kQLVE = TAG('Q', 'L', 'V', 'E');   // Legacy Version
                                                  // Encapsulation.
-const QuicTag kQNZR = TAG('Q', 'N', 'Z', 'R');   // Turn off QUIC crypto 0-RTT.
+
+const QuicTag kQNZ2 = TAG('Q', 'N', 'Z', '2');   // Turn off QUIC crypto 0-RTT.
 
 const QuicTag kQNSP = TAG('Q', 'N', 'S', 'P');   // Turn off server push in
                                                  // gQUIC.
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 3335b4a..6d579f5 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -2185,6 +2185,41 @@
   server_thread_->Resume();
 }
 
+// Regression test for b/171378845
+TEST_P(EndToEndTest, ClientDisablesGQuicZeroRtt) {
+  if (version_.UsesTls()) {
+    // This feature is gQUIC only.
+    ASSERT_TRUE(Initialize());
+    return;
+  }
+  QuicTagVector options;
+  options.push_back(kQNZ2);
+  client_config_.SetClientConnectionOptions(options);
+
+  ASSERT_TRUE(Initialize());
+
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+  QuicSpdyClientSession* client_session = GetClientSession();
+  ASSERT_TRUE(client_session);
+  EXPECT_FALSE(client_session->EarlyDataAccepted());
+  EXPECT_FALSE(client_session->ReceivedInchoateReject());
+  EXPECT_FALSE(client_->client()->EarlyDataAccepted());
+  EXPECT_FALSE(client_->client()->ReceivedInchoateReject());
+
+  client_->Disconnect();
+
+  // Make sure that the request succeeds but 0-RTT was not used.
+  client_->Connect();
+  EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable());
+  ASSERT_TRUE(client_->client()->connected());
+  EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+
+  client_session = GetClientSession();
+  ASSERT_TRUE(client_session);
+  EXPECT_FALSE(client_session->EarlyDataAccepted());
+  EXPECT_FALSE(client_->client()->EarlyDataAccepted());
+}
+
 TEST_P(EndToEndTest, MaxInitialRTT) {
   // Client tries to suggest twice the server's max initial rtt and the server
   // uses the max.
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index 784a451..f744153 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -317,7 +317,8 @@
     early_data_reason_ = ssl_early_data_no_session_offered;
     fill_inchoate_client_hello = true;
   } else if (session()->config()->HasClientRequestedIndependentOption(
-                 kQNZR, session()->perspective())) {
+                 kQNZ2, session()->perspective()) &&
+             num_client_hellos_ == 1) {
     early_data_reason_ = ssl_early_data_disabled;
     fill_inchoate_client_hello = true;
   }
diff --git a/quic/core/quic_crypto_client_stream_test.cc b/quic/core/quic_crypto_client_stream_test.cc
index eef6b49..86fa3b8 100644
--- a/quic/core/quic_crypto_client_stream_test.cc
+++ b/quic/core/quic_crypto_client_stream_test.cc
@@ -69,7 +69,8 @@
   void CompleteCryptoHandshake() {
     int proof_verify_details_calls = 1;
     if (stream()->handshake_protocol() != PROTOCOL_TLS1_3) {
-      EXPECT_CALL(*session_, OnProofValid(testing::_));
+      EXPECT_CALL(*session_, OnProofValid(testing::_))
+          .Times(testing::AtLeast(1));
       proof_verify_details_calls = 0;
     }
     EXPECT_CALL(*session_, OnProofVerifyDetailsAvailable(testing::_))
@@ -172,14 +173,13 @@
 
   // Set connection option.
   QuicTagVector options;
-  options.push_back(kQNZR);
+  options.push_back(kQNZ2);
   session_->config()->SetClientConnectionOptions(options);
 
-  EXPECT_CALL(*session_, OnProofValid(testing::_));
-  stream()->CryptoConnect();
-  // Check that a client hello was sent.
-  ASSERT_EQ(1u, connection_->encrypted_packets_.size());
-  EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level());
+  CompleteCryptoHandshake();
+  // Check that two client hellos were sent, one inchoate and one normal.
+  EXPECT_EQ(2, stream()->num_sent_client_hellos());
+  EXPECT_FALSE(stream()->EarlyDataAccepted());
   EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_disabled);
 }