Disable resumption when receiving NRES connection option.

Protected by FLAGS_quic_reloadable_flag_quic_enable_disable_resumption.

PiperOrigin-RevId: 443195566
diff --git a/quiche/quic/core/crypto/crypto_protocol.h b/quiche/quic/core/crypto/crypto_protocol.h
index 7dbbb6d..907857b 100644
--- a/quiche/quic/core/crypto/crypto_protocol.h
+++ b/quiche/quic/core/crypto/crypto_protocol.h
@@ -426,6 +426,7 @@
                                                  // wire PING (ROWP) on the
                                                  // server side.
 const QuicTag kGSR0 = TAG('G', 'S', 'R', '0');   // Selective Resumption
+const QuicTag kNRES = TAG('N', 'R', 'E', 'S');   // No resumption
 
 const QuicTag kINVC = TAG('I', 'N', 'V', 'C');   // Send connection close for
                                                  // INVALID_VERSION
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index 7eb3c79..9e805f2 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -1963,6 +1963,31 @@
   VerifyCleanConnection(false);
 }
 
+TEST_P(EndToEndTest, DisableResumption) {
+  client_extra_copts_.push_back(kNRES);
+  ASSERT_TRUE(Initialize());
+  if (!version_.UsesTls()) {
+    return;
+  }
+  SendSynchronousFooRequestAndCheckResponse();
+  QuicSpdyClientSession* client_session = GetClientSession();
+  ASSERT_TRUE(client_session);
+  EXPECT_EQ(client_session->GetCryptoStream()->EarlyDataReason(),
+            ssl_early_data_no_session_offered);
+  client_->Disconnect();
+
+  SendSynchronousFooRequestAndCheckResponse();
+  client_session = GetClientSession();
+  ASSERT_TRUE(client_session);
+  if (GetQuicReloadableFlag(quic_enable_disable_resumption)) {
+    EXPECT_EQ(client_session->GetCryptoStream()->EarlyDataReason(),
+              ssl_early_data_session_not_resumed);
+  } else {
+    EXPECT_EQ(client_session->GetCryptoStream()->EarlyDataReason(),
+              ssl_early_data_accepted);
+  }
+}
+
 // This is a regression test for b/162595387
 TEST_P(EndToEndTest, PostZeroRTTRequestDuringHandshake) {
   if (!version_.UsesTls()) {
diff --git a/quiche/quic/core/http/quic_server_session_base.cc b/quiche/quic/core/http/quic_server_session_base.cc
index 7ad1e3a..fd38825 100644
--- a/quiche/quic/core/http/quic_server_session_base.cc
+++ b/quiche/quic/core/http/quic_server_session_base.cc
@@ -86,6 +86,16 @@
     }
   }
 
+  if (GetQuicReloadableFlag(quic_enable_disable_resumption) &&
+      version().UsesTls() &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kNRES) &&
+      crypto_stream_->ResumptionAttempted()) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_enable_disable_resumption);
+    const bool disabled = crypto_stream_->DisableResumption();
+    QUIC_BUG_IF(quic_failed_to_disable_resumption, !disabled)
+        << "Failed to disable resumption";
+  }
+
   // Enable bandwidth resumption if peer sent correct connection options.
   const bool last_bandwidth_resumption =
       ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE);
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index 3c1bc12..179eda3 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -57,6 +57,8 @@
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_version_draft_29, false)
 // If true, disable blackhole detection on server side.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_disable_server_blackhole_detection, false)
+// If true, disable resumption when receiving NRES connection option.
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_enable_disable_resumption, false)
 // If true, discard INITIAL packet if the key has been dropped.
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_discard_initial_packet_with_key_dropped, true)
 // If true, do not bundle ACK while sending PATH_CHALLENGE on alternative path.