gfe-relnote: Remove stateless reject from QUIC. This deprecates two flags in the false position: --gfe2_reloadable_flag_enable_quic_stateless_reject_support and --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects.

PiperOrigin-RevId: 250347964
Change-Id: I50e150f91e76b672160eadc04a379b529a4f602d
diff --git a/quic/core/crypto/crypto_handshake_message.cc b/quic/core/crypto/crypto_handshake_message.cc
index 579bb37..457d0fb 100644
--- a/quic/core/crypto/crypto_handshake_message.cc
+++ b/quic/core/crypto/crypto_handshake_message.cc
@@ -286,16 +286,6 @@
           done = true;
         }
         break;
-      case kRCID:
-        // uint64_t value
-        if (it->second.size() == 8) {
-          uint64_t value;
-          memcpy(&value, it->second.data(), sizeof(value));
-          value = QuicEndian::NetToHost64(value);
-          ret += QuicTextUtils::Uint64ToString(value);
-          done = true;
-        }
-        break;
       case kTBKP:
       case kKEXS:
       case kAEAD:
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index e8c8d84..e63224a 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -27,14 +27,13 @@
 typedef std::string ServerConfigID;
 
 // The following tags have been deprecated and should not be reused:
-// "BBQ4"
+// "BBQ4", "RCID", "SREJ"
 
 // clang-format off
 const QuicTag kCHLO = TAG('C', 'H', 'L', 'O');   // Client hello
 const QuicTag kSHLO = TAG('S', 'H', 'L', 'O');   // Server hello
 const QuicTag kSCFG = TAG('S', 'C', 'F', 'G');   // Server config
 const QuicTag kREJ  = TAG('R', 'E', 'J', '\0');  // Reject
-const QuicTag kSREJ = TAG('S', 'R', 'E', 'J');   // Stateless reject
 const QuicTag kCETV = TAG('C', 'E', 'T', 'V');   // Client encrypted tag-value
                                                  // pairs
 const QuicTag kPRST = TAG('P', 'R', 'S', 'T');   // Public reset
@@ -245,9 +244,7 @@
 
 // Rejection tags
 const QuicTag kRREJ = TAG('R', 'R', 'E', 'J');   // Reasons for server sending
-// Stateless Reject tags
-const QuicTag kRCID = TAG('R', 'C', 'I', 'D');   // Server-designated
-                                                 // connection ID
+
 // Server hello tags
 const QuicTag kCADR = TAG('C', 'A', 'D', 'R');   // Client IP address and port
 const QuicTag kASAD = TAG('A', 'S', 'A', 'D');   // Alternate Server IP address
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc
index 5d86dcb..306a28b 100644
--- a/quic/core/crypto/crypto_server_test.cc
+++ b/quic/core/crypto/crypto_server_test.cc
@@ -148,14 +148,6 @@
         SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
     CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons));
 
-    // TODO(wub): Delete this block when deprecating RCID.
-    {
-      uint64_t server_designated_connection_id;
-      EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
-                out_.GetUint64(kRCID, &server_designated_connection_id));
-      rand_for_id_generation_.ChangeValue();
-    }
-
     QuicStringPiece srct;
     ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
     srct_hex_ = "#" + QuicTextUtils::HexEncode(srct);
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index d216f66..4fca4bb 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -761,8 +761,8 @@
     std::string* error_details) {
   DCHECK(error_details != nullptr);
 
-  if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) {
-    *error_details = "Message is not REJ or SREJ";
+  if (rej.tag() != kREJ) {
+    *error_details = "Message is not REJ";
     return QUIC_CRYPTO_INTERNAL_ERROR;
   }
 
@@ -778,30 +778,6 @@
     out_params->server_nonce = std::string(nonce);
   }
 
-  if (rej.tag() == kSREJ) {
-    QuicConnectionId connection_id;
-
-    QuicStringPiece connection_id_bytes;
-    if (!rej.GetStringPiece(kRCID, &connection_id_bytes)) {
-      *error_details = "Missing kRCID";
-      return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
-    }
-    connection_id = QuicConnectionId(connection_id_bytes.data(),
-                                     connection_id_bytes.length());
-    if (!QuicUtils::IsConnectionIdValidForVersion(connection_id, version)) {
-      QUIC_PEER_BUG << "Received server-designated connection ID "
-                    << connection_id << " which is invalid with version "
-                    << QuicVersionToString(version);
-      *error_details = "Bad kRCID length";
-      return QUIC_CRYPTO_INTERNAL_ERROR;
-    }
-    cached->add_server_designated_connection_id(connection_id);
-    if (!nonce.empty()) {
-      cached->add_server_nonce(std::string(nonce));
-    }
-    return QUIC_NO_ERROR;
-  }
-
   return QUIC_NO_ERROR;
 }
 
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 404a29e..54d4bf4 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -1437,28 +1437,8 @@
     const std::vector<uint32_t>& reject_reasons,
     CryptoHandshakeMessage* out) const {
   const QuicWallTime now = context.clock()->WallNow();
-  if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) &&
-      context.use_stateless_rejects()) {
-    QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject "
-                  << "with server-designated connection ID "
-                  << context.server_designated_connection_id();
-    out->set_tag(kSREJ);
-    if (!QuicUtils::IsConnectionIdValidForVersion(
-            context.server_designated_connection_id(),
-            context.transport_version())) {
-      QUIC_BUG << "Tried to send server designated connection ID "
-               << context.server_designated_connection_id()
-               << " which is invalid with version "
-               << QuicVersionToString(context.transport_version());
-      return;
-    }
-    out->SetStringPiece(
-        kRCID,
-        QuicStringPiece(context.server_designated_connection_id().data(),
-                        context.server_designated_connection_id().length()));
-  } else {
-    out->set_tag(kREJ);
-  }
+
+  out->set_tag(kREJ);
   out->SetStringPiece(kSCFG, config.serialized);
   out->SetStringPiece(
       kSourceAddressTokenTag,
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index 9f3a7bc..039da84 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -338,6 +338,8 @@
       const QuicSocketAddress& client_address,
       ParsedQuicVersion version,
       const ParsedQuicVersionVector& supported_versions,
+      // TODO(wub): Deprecate use_stateless_rejects and
+      // server_designated_connection_id.
       bool use_stateless_rejects,
       QuicConnectionId server_designated_connection_id,
       const QuicClock* clock,
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index b0c26be..bf432ff 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -65,7 +65,6 @@
       proof_verify_callback_(nullptr),
       proof_handler_(proof_handler),
       verify_ok_(false),
-      stateless_reject_received_(false),
       proof_verify_start_time_(QuicTime::Zero()),
       num_scup_messages_received_(0),
       encryption_established_(false),
@@ -232,20 +231,6 @@
 
 void QuicCryptoClientHandshaker::DoSendCHLO(
     QuicCryptoClientConfig::CachedState* cached) {
-  if (stateless_reject_received_) {
-    // If we've gotten to this point, we've sent at least one hello
-    // and received a stateless reject in response.  We cannot
-    // continue to send hellos because the server has abandoned state
-    // for this connection.  Abandon further handshakes.
-    next_state_ = STATE_NONE;
-    if (session()->connection()->connected()) {
-      session()->connection()->CloseConnection(
-          QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received",
-          ConnectionCloseBehavior::SILENT_CLOSE);
-    }
-    return;
-  }
-
   // Send the client hello in plaintext.
   session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
   encryption_established_ = false;
@@ -295,15 +280,6 @@
     return;
   }
 
-  // If the server nonce is empty, copy over the server nonce from a previous
-  // SREJ, if there is one.
-  if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) &&
-      crypto_negotiated_params_->server_nonce.empty() &&
-      cached->has_server_nonce()) {
-    crypto_negotiated_params_->server_nonce = cached->GetNextServerNonce();
-    DCHECK(!crypto_negotiated_params_->server_nonce.empty());
-  }
-
   std::string error_details;
   QuicErrorCode error = crypto_config_->FillClientHello(
       server_id_, session()->connection()->connection_id(),
@@ -358,7 +334,7 @@
   // perform a handshake, or we sent a full hello that the server
   // rejected. Here we hope to have a REJ that contains the information
   // that we need.
-  if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
+  if (in->tag() != kREJ) {
     next_state_ = STATE_NONE;
     stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
                                         "Expected REJ");
@@ -391,7 +367,6 @@
   // so we can cancel and retransmissions.
   session()->NeuterUnencryptedData();
 
-  stateless_reject_received_ = in->tag() == kSREJ;
   std::string error_details;
   QuicErrorCode error = crypto_config_->ProcessRejection(
       *in, session()->connection()->clock()->WallNow(),
@@ -500,7 +475,7 @@
   // hoping for a SHLO from the server to confirm that.  First check
   // to see whether the response was a reject, and if so, move on to
   // the reject-processing state.
-  if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
+  if (in->tag() == kREJ) {
     // A reject message must be sent in ENCRYPTION_INITIAL.
     if (session()->connection()->last_decrypted_level() != ENCRYPTION_INITIAL) {
       // The rejection was sent encrypted!
diff --git a/quic/core/quic_crypto_client_handshaker.h b/quic/core/quic_crypto_client_handshaker.h
index 023905b..5b7ce35 100644
--- a/quic/core/quic_crypto_client_handshaker.h
+++ b/quic/core/quic_crypto_client_handshaker.h
@@ -164,11 +164,6 @@
   std::string verify_error_details_;
   std::unique_ptr<ProofVerifyDetails> verify_details_;
 
-  // True if the server responded to a previous CHLO with a stateless
-  // reject.  Used for book-keeping between the STATE_RECV_REJ,
-  // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
-  bool stateless_reject_received_;
-
   QuicTime proof_verify_start_time_;
 
   int num_scup_messages_received_;
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc
index 025e391..f345a14 100644
--- a/quic/core/quic_crypto_server_handshaker.cc
+++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -169,27 +169,9 @@
   }
 
   if (reply->tag() != kSHLO) {
-    if (reply->tag() == kSREJ) {
-      DCHECK(false) << "Unexpected SREJ reply.";
-      // Before sending the SREJ, cause the connection to save crypto packets
-      // so that they can be added to the time wait list manager and
-      // retransmitted.
-      session()->connection()->EnableSavingCryptoPackets();
-    }
     session()->connection()->set_fully_pad_crypto_hadshake_packets(
         crypto_config_->pad_rej());
     SendHandshakeMessage(*reply);
-
-    if (reply->tag() == kSREJ) {
-      DCHECK(false) << "Unexpected SREJ reply.";
-      DCHECK(!handshake_confirmed());
-      QUIC_DLOG(INFO) << "Closing connection "
-                      << session()->connection()->connection_id()
-                      << " because of a stateless reject.";
-      session()->connection()->CloseConnection(
-          QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
-          ConnectionCloseBehavior::SILENT_CLOSE);
-    }
     return;
   }
 
diff --git a/quic/core/quic_crypto_server_stream.cc b/quic/core/quic_crypto_server_stream.cc
index e8937a0..a6486d8 100644
--- a/quic/core/quic_crypto_server_stream.cc
+++ b/quic/core/quic_crypto_server_stream.cc
@@ -28,24 +28,6 @@
 QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(QuicSession* session)
     : QuicCryptoStream(session) {}
 
-// TODO(jokulik): Once stateless rejects support is inherent in the version
-// number, this function will likely go away entirely.
-// static
-bool QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(
-    const CryptoHandshakeMessage& message) {
-  QuicTagVector received_tags;
-  QuicErrorCode error = message.GetTaglist(kCOPT, &received_tags);
-  if (error != QUIC_NO_ERROR) {
-    return false;
-  }
-  for (const QuicTag tag : received_tags) {
-    if (tag == kSREJ) {
-      return true;
-    }
-  }
-  return false;
-}
-
 QuicCryptoServerStream::QuicCryptoServerStream(
     const QuicCryptoServerConfig* crypto_config,
     QuicCompressedCertsCache* compressed_certs_cache,
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h
index 9edd2ea..71ce297 100644
--- a/quic/core/quic_crypto_server_stream.h
+++ b/quic/core/quic_crypto_server_stream.h
@@ -56,11 +56,6 @@
       const = 0;
   virtual void SetPreviousCachedNetworkParams(
       CachedNetworkParameters cached_network_params) = 0;
-
-  // Checks the options on the handshake-message to see whether the
-  // peer supports stateless-rejects.
-  static bool DoesPeerSupportStatelessRejects(
-      const CryptoHandshakeMessage& message);
 };
 
 class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index 609c6b6..796b2dc 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -14,7 +14,6 @@
 #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -229,55 +228,6 @@
   std::string alpn_;
 };
 
-// Class which sits between the ChloExtractor and the StatelessRejector
-// to give the QuicDispatcher a chance to apply policy checks to the CHLO.
-class ChloValidator : public ChloAlpnExtractor {
- public:
-  ChloValidator(QuicCryptoServerStream::Helper* helper,
-                const QuicSocketAddress& client_address,
-                const QuicSocketAddress& peer_address,
-                const QuicSocketAddress& self_address,
-                StatelessRejector* rejector)
-      : helper_(helper),
-        client_address_(client_address),
-        peer_address_(peer_address),
-        self_address_(self_address),
-        rejector_(rejector),
-        can_accept_(false),
-        error_details_("CHLO not processed") {}
-
-  // ChloExtractor::Delegate implementation.
-  void OnChlo(QuicTransportVersion version,
-              QuicConnectionId server_connection_id,
-              const CryptoHandshakeMessage& chlo) override {
-    // Extract the ALPN
-    ChloAlpnExtractor::OnChlo(version, server_connection_id, chlo);
-    if (helper_->CanAcceptClientHello(chlo, client_address_, peer_address_,
-                                      self_address_, &error_details_)) {
-      can_accept_ = true;
-      rejector_->OnChlo(
-          version, server_connection_id,
-          helper_->GenerateConnectionIdForReject(version, server_connection_id),
-          chlo);
-    }
-  }
-
-  bool can_accept() const { return can_accept_; }
-
-  const std::string& error_details() const { return error_details_; }
-
- private:
-  QuicCryptoServerStream::Helper* helper_;  // Unowned.
-  // client_address_ and peer_address_ could be different values for proxy
-  // connections.
-  QuicSocketAddress client_address_;
-  QuicSocketAddress peer_address_;
-  QuicSocketAddress self_address_;
-  StatelessRejector* rejector_;  // Unowned.
-  bool can_accept_;
-  std::string error_details_;
-};
-
 }  // namespace
 
 QuicDispatcher::QuicDispatcher(
@@ -551,10 +501,8 @@
   // Packet's connection ID is unknown.  Apply the validity checks.
   QuicPacketFate fate = ValidityChecks(header);
   if (fate == kFateProcess) {
-    // Execute stateless rejection logic to determine the packet fate, then
-    // invoke ProcessUnauthenticatedHeaderFate.
-    MaybeRejectStatelessly(server_connection_id, header.form,
-                           header.version_flag, header.version);
+    ProcessOrBufferPacket(server_connection_id, header.form,
+                          header.version_flag, header.version);
   } else {
     // If the fate is already known, process it without executing stateless
     // rejection logic.
@@ -575,21 +523,16 @@
       break;
     }
     case kFateTimeWait:
-      // MaybeRejectStatelessly or OnExpiredPackets might have already added the
-      // connection to time wait, in which case it should not be added again.
-      if (!GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) ||
-          !time_wait_list_manager_->IsConnectionIdInTimeWait(
-              server_connection_id)) {
-        // Add this connection_id to the time-wait state, to safely reject
-        // future packets.
-        QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id
-                        << " to time-wait list.";
-        QUIC_CODE_COUNT(quic_reject_fate_time_wait);
-        StatelesslyTerminateConnection(
-            server_connection_id, form, version_flag, version,
-            QUIC_HANDSHAKE_FAILED, "Reject connection",
-            quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
-      }
+      // Add this connection_id to the time-wait state, to safely reject
+      // future packets.
+      QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id
+                      << " to time-wait list.";
+      QUIC_CODE_COUNT(quic_reject_fate_time_wait);
+      StatelesslyTerminateConnection(
+          server_connection_id, form, version_flag, version,
+          QUIC_HANDSHAKE_FAILED, "Reject connection",
+          quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
+
       DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
           server_connection_id));
       time_wait_list_manager_->ProcessPacket(
@@ -1167,10 +1110,6 @@
                   << server_connection_id << " because of " << result;
 }
 
-bool QuicDispatcher::ShouldAttemptCheapStatelessRejection() {
-  return true;
-}
-
 QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
   return new QuicTimeWaitListManager(writer_.get(), this, helper_->GetClock(),
                                      alarm_factory_.get());
@@ -1274,49 +1213,7 @@
   return true;
 }
 
-class StatelessRejectorProcessDoneCallback
-    : public StatelessRejector::ProcessDoneCallback {
- public:
-  StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
-                                       ParsedQuicVersion first_version,
-                                       PacketHeaderFormat form,
-                                       bool version_flag)
-      : dispatcher_(dispatcher),
-        current_client_address_(dispatcher->current_client_address_),
-        current_peer_address_(dispatcher->current_peer_address_),
-        current_self_address_(dispatcher->current_self_address_),
-        additional_context_(dispatcher->GetPerPacketContext()),
-        current_packet_(
-            dispatcher->current_packet_->Clone()),  // Note: copies the packet
-        first_version_(first_version),
-        current_packet_format_(form),
-        current_version_flag_(version_flag) {}
-
-  void Run(std::unique_ptr<StatelessRejector> rejector) override {
-    if (additional_context_ != nullptr) {
-      dispatcher_->RestorePerPacketContext(std::move(additional_context_));
-    }
-    dispatcher_->OnStatelessRejectorProcessDone(
-        std::move(rejector), current_client_address_, current_peer_address_,
-        current_self_address_, std::move(current_packet_), first_version_,
-        current_packet_format_, current_version_flag_);
-  }
-
- private:
-  QuicDispatcher* dispatcher_;
-  QuicSocketAddress current_client_address_;
-  QuicSocketAddress current_peer_address_;
-  QuicSocketAddress current_self_address_;
-  // TODO(wub): Wrap all current_* variables into PerPacketContext. And rename
-  // |additional_context_| to |context_|.
-  std::unique_ptr<QuicPerPacketContext> additional_context_;
-  std::unique_ptr<QuicReceivedPacket> current_packet_;
-  ParsedQuicVersion first_version_;
-  const PacketHeaderFormat current_packet_format_;
-  bool current_version_flag_;
-};
-
-void QuicDispatcher::MaybeRejectStatelessly(
+void QuicDispatcher::ProcessOrBufferPacket(
     QuicConnectionId server_connection_id,
     PacketHeaderFormat form,
     bool version_flag,
@@ -1327,179 +1224,20 @@
     return;
     // TODO(nharper): Support buffering non-ClientHello packets when using TLS.
   }
-  // TODO(rch): This logic should probably live completely inside the rejector.
-  if (!FLAGS_quic_allow_chlo_buffering ||
-      !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) ||
-      !GetQuicReloadableFlag(enable_quic_stateless_reject_support) ||
-      !ShouldAttemptCheapStatelessRejection()) {
-    // Not use cheap stateless reject.
-    ChloAlpnExtractor alpn_extractor;
-    if (FLAGS_quic_allow_chlo_buffering &&
-        !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
-                                config_->create_session_tag_indicators(),
-                                &alpn_extractor,
-                                server_connection_id.length())) {
-      // Buffer non-CHLO packets.
-      ProcessUnauthenticatedHeaderFate(kFateBuffer, server_connection_id, form,
-                                       version_flag, version);
-      return;
-    }
-    current_alpn_ = alpn_extractor.ConsumeAlpn();
-    ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form,
-                                     version_flag, version);
-    return;
-  }
 
-  std::unique_ptr<StatelessRejector> rejector(new StatelessRejector(
-      version, GetSupportedVersions(), crypto_config_, &compressed_certs_cache_,
-      helper()->GetClock(), helper()->GetRandomGenerator(),
-      current_packet_->length(), current_client_address_,
-      current_self_address_));
-  ChloValidator validator(session_helper_.get(), current_client_address_,
-                          current_peer_address_, current_self_address_,
-                          rejector.get());
-  if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
+  ChloAlpnExtractor alpn_extractor;
+  if (FLAGS_quic_allow_chlo_buffering &&
+      !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
                               config_->create_session_tag_indicators(),
-                              &validator, server_connection_id.length())) {
+                              &alpn_extractor, server_connection_id.length())) {
+    // Buffer non-CHLO packets.
     ProcessUnauthenticatedHeaderFate(kFateBuffer, server_connection_id, form,
                                      version_flag, version);
     return;
   }
-  current_alpn_ = validator.ConsumeAlpn();
-
-  if (!validator.can_accept()) {
-    // This CHLO is prohibited by policy.
-    QUIC_CODE_COUNT(quic_reject_cant_accept_chlo);
-    StatelessConnectionTerminator terminator(
-        server_connection_id, version, helper(), time_wait_list_manager_.get());
-    terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, validator.error_details(),
-                               form != GOOGLE_QUIC_PACKET);
-    QuicSession::RecordConnectionCloseAtServer(
-        QUIC_HANDSHAKE_FAILED, ConnectionCloseSource::FROM_SELF);
-    ProcessUnauthenticatedHeaderFate(kFateTimeWait, server_connection_id, form,
-                                     version_flag, version);
-    return;
-  }
-
-  // If we were able to make a decision about this CHLO based purely on the
-  // information available in OnChlo, just invoke the done callback immediately.
-  if (rejector->state() != StatelessRejector::UNKNOWN) {
-    ProcessStatelessRejectorState(std::move(rejector), version, form,
-                                  version_flag);
-    return;
-  }
-
-  // Insert into set of connection IDs to buffer
-  const bool ok =
-      temporarily_buffered_connections_.insert(server_connection_id).second;
-  QUIC_BUG_IF(!ok)
-      << "Processing multiple stateless rejections for connection ID "
-      << server_connection_id;
-
-  // Continue stateless rejector processing
-  std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
-      new StatelessRejectorProcessDoneCallback(this, version, form,
-                                               version_flag));
-  StatelessRejector::Process(std::move(rejector), std::move(cb));
-}
-
-void QuicDispatcher::OnStatelessRejectorProcessDone(
-    std::unique_ptr<StatelessRejector> rejector,
-    const QuicSocketAddress& current_client_address,
-    const QuicSocketAddress& current_peer_address,
-    const QuicSocketAddress& current_self_address,
-    std::unique_ptr<QuicReceivedPacket> current_packet,
-    ParsedQuicVersion first_version,
-    PacketHeaderFormat current_packet_format,
-    bool current_version_flag) {
-  // Reset current_* to correspond to the packet which initiated the stateless
-  // reject logic.
-  current_client_address_ = current_client_address;
-  current_peer_address_ = current_peer_address;
-  current_self_address_ = current_self_address;
-  current_packet_ = current_packet.get();
-  current_server_connection_id_ = rejector->connection_id();
-  if (!no_framer_) {
-    framer_.set_version(first_version);
-  }
-
-  // Stop buffering packets on this connection
-  const auto num_erased =
-      temporarily_buffered_connections_.erase(rejector->connection_id());
-  QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for "
-                                  "non-buffered connection ID "
-                               << rejector->connection_id();
-
-  // If this connection has gone into time-wait during the async processing,
-  // don't proceed.
-  if (time_wait_list_manager_->IsConnectionIdInTimeWait(
-          rejector->connection_id())) {
-    time_wait_list_manager_->ProcessPacket(
-        current_self_address, current_peer_address, rejector->connection_id(),
-        current_packet_format, GetPerPacketContext());
-    return;
-  }
-
-  ProcessStatelessRejectorState(std::move(rejector), first_version,
-                                current_packet_format, current_version_flag);
-}
-
-void QuicDispatcher::ProcessStatelessRejectorState(
-    std::unique_ptr<StatelessRejector> rejector,
-    ParsedQuicVersion first_version,
-    PacketHeaderFormat form,
-    bool version_flag) {
-  QuicPacketFate fate;
-  switch (rejector->state()) {
-    case StatelessRejector::FAILED: {
-      // There was an error processing the client hello.
-      QUIC_CODE_COUNT(quic_reject_error_processing_chlo);
-      StatelessConnectionTerminator terminator(rejector->connection_id(),
-                                               first_version, helper(),
-                                               time_wait_list_manager_.get());
-      terminator.CloseConnection(rejector->error(), rejector->error_details(),
-                                 form != GOOGLE_QUIC_PACKET);
-      fate = kFateTimeWait;
-      break;
-    }
-
-    case StatelessRejector::UNSUPPORTED:
-      // Cheap stateless rejects are not supported so process the packet.
-      fate = kFateProcess;
-      break;
-
-    case StatelessRejector::ACCEPTED:
-      // Contains a valid CHLO, so process the packet and create a connection.
-      fate = kFateProcess;
-      break;
-
-    case StatelessRejector::REJECTED: {
-      QUIC_BUG_IF(!no_framer_ && first_version != framer_.version())
-          << "SREJ: Client's version: "
-          << QuicVersionToString(first_version.transport_version)
-          << " is different from current dispatcher framer's version: "
-          << QuicVersionToString(framer_.transport_version());
-      StatelessConnectionTerminator terminator(rejector->connection_id(),
-                                               first_version, helper(),
-                                               time_wait_list_manager_.get());
-      terminator.RejectConnection(
-          rejector->reply().GetSerialized().AsStringPiece(),
-          form != GOOGLE_QUIC_PACKET);
-      QuicSession::RecordConnectionCloseAtServer(
-          QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
-          ConnectionCloseSource::FROM_SELF);
-      OnConnectionRejectedStatelessly();
-      fate = kFateTimeWait;
-      break;
-    }
-
-    default:
-      QUIC_BUG << "Rejector has invalid state " << rejector->state();
-      fate = kFateDrop;
-      break;
-  }
-  ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), form,
-                                   version_flag, rejector->version());
+  current_alpn_ = alpn_extractor.ConsumeAlpn();
+  ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form,
+                                   version_flag, version);
 }
 
 const QuicTransportVersionVector&
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index 1798a0d..f22505a 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -23,7 +23,6 @@
 #include "net/third_party/quiche/src/quic/core/quic_session.h"
 #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
 
@@ -208,12 +207,6 @@
                                          QuicStringPiece alpn,
                                          const ParsedQuicVersion& version) = 0;
 
-  // Called when a connection is rejected statelessly.
-  virtual void OnConnectionRejectedStatelessly() {}
-
-  // Returns true if cheap stateless rejection should be attempted.
-  virtual bool ShouldAttemptCheapStatelessRejection();
-
   // Values to be returned by ValidityChecks() to indicate what should be done
   // with a packet.  Fates with greater values are considered to be higher
   // priority, in that if one validity check indicates a lower-valued fate and
@@ -384,23 +377,21 @@
 
  private:
   friend class test::QuicDispatcherPeer;
-  friend class StatelessRejectorProcessDoneCallback;
 
   typedef QuicUnorderedSet<QuicConnectionId, QuicConnectionIdHash>
       QuicConnectionIdSet;
 
   // Based on an unauthenticated packet header |header|, calls ValidityChecks
-  // and then either MaybeRejectStatelessly or ProcessUnauthenticatedHeaderFate.
+  // and then ProcessUnauthenticatedHeaderFate.
   void ProcessHeader(const QuicPacketHeader& header);
 
-  // Attempts to reject the connection statelessly, if stateless rejects are
-  // possible and if the current packet contains a CHLO message.  Determines a
-  // fate which describes what subsequent processing should be performed on the
-  // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
-  void MaybeRejectStatelessly(QuicConnectionId server_connection_id,
-                              PacketHeaderFormat form,
-                              bool version_flag,
-                              ParsedQuicVersion version);
+  // TODO(wub): Move the body to ProcessHeader, then remove this function.
+  // Determine whether the current packet needs to be processed now or buffered
+  // for later processing, then invokes ProcessUnauthenticatedHeaderFate.
+  void ProcessOrBufferPacket(QuicConnectionId server_connection_id,
+                             PacketHeaderFormat form,
+                             bool version_flag,
+                             ParsedQuicVersion version);
 
   // Deliver |packets| to |session| for further processing.
   void DeliverPacketsToSession(
@@ -415,30 +406,6 @@
                                         bool version_flag,
                                         ParsedQuicVersion version);
 
-  // Invoked when StatelessRejector::Process completes. |first_version| is the
-  // version of the packet which initiated the stateless reject.
-  // WARNING: This function can be called when a async proof returns, i.e. not
-  // from a stack traceable to ProcessPacket().
-  // TODO(fayang): maybe consider not using callback when there is no crypto
-  // involved.
-  void OnStatelessRejectorProcessDone(
-      std::unique_ptr<StatelessRejector> rejector,
-      const QuicSocketAddress& current_client_address,
-      const QuicSocketAddress& current_peer_address,
-      const QuicSocketAddress& current_self_address,
-      std::unique_ptr<QuicReceivedPacket> current_packet,
-      ParsedQuicVersion first_version,
-      PacketHeaderFormat current_packet_format,
-      bool current_version_flag);
-
-  // Examine the state of the rejector and decide what to do with the current
-  // packet.
-  void ProcessStatelessRejectorState(
-      std::unique_ptr<StatelessRejector> rejector,
-      ParsedQuicVersion first_version,
-      PacketHeaderFormat form,
-      bool version_flag);
-
   // If the connection ID length is different from what the dispatcher expects,
   // replace the connection ID with a random one of the right length,
   // and save it to make sure the mapping is persistent.
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index de06c52..6fdd130 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -19,7 +19,6 @@
 #include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
 #include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
@@ -1401,56 +1400,14 @@
   MarkSession1Deleted();
 }
 
-// Tests that bufferring packets works in stateful reject, expensive stateless
-// reject and cheap stateless reject.
-struct BufferedPacketStoreTestParams {
-  BufferedPacketStoreTestParams(bool enable_stateless_rejects_via_flag,
-                                bool support_cheap_stateless_reject)
-      : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag),
-        support_cheap_stateless_reject(support_cheap_stateless_reject) {}
-
-  friend std::ostream& operator<<(std::ostream& os,
-                                  const BufferedPacketStoreTestParams& p) {
-    os << "{  enable_stateless_rejects_via_flag: "
-       << p.enable_stateless_rejects_via_flag << std::endl;
-    os << "  support_cheap_stateless_reject: "
-       << p.support_cheap_stateless_reject << " }";
-    return os;
-  }
-
-  // This only enables the stateless reject feature via the feature-flag.
-  // This should be a no-op if the peer does not support them.
-  bool enable_stateless_rejects_via_flag;
-  // Whether to do cheap stateless or not.
-  bool support_cheap_stateless_reject;
-};
-
-std::vector<BufferedPacketStoreTestParams> GetBufferedPacketStoreTestParams() {
-  std::vector<BufferedPacketStoreTestParams> params;
-  for (bool enable_stateless_rejects_via_flag : {true, false}) {
-    for (bool support_cheap_stateless_reject : {true, false}) {
-      params.push_back(BufferedPacketStoreTestParams(
-          enable_stateless_rejects_via_flag, support_cheap_stateless_reject));
-    }
-  }
-  return params;
-}
-
 // A dispatcher whose stateless rejector will always ACCEPTs CHLO.
-class BufferedPacketStoreTest
-    : public QuicDispatcherTest,
-      public testing::WithParamInterface<BufferedPacketStoreTestParams> {
+class BufferedPacketStoreTest : public QuicDispatcherTest {
  public:
   BufferedPacketStoreTest()
       : QuicDispatcherTest(),
         server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)),
         client_addr_(QuicIpAddress::Loopback4(), 1234),
-        signed_config_(new QuicSignedServerConfig) {
-    SetQuicReloadableFlag(quic_use_cheap_stateless_rejects,
-                          GetParam().support_cheap_stateless_reject);
-    SetQuicReloadableFlag(enable_quic_stateless_reject_support,
-                          GetParam().enable_stateless_rejects_via_flag);
-  }
+        signed_config_(new QuicSignedServerConfig) {}
 
   void SetUp() override {
     QuicDispatcherTest::SetUp();
@@ -1460,7 +1417,6 @@
     CryptoHandshakeMessage chlo =
         crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version,
                                                        &crypto_config_);
-    chlo.SetVector(kCOPT, QuicTagVector{kSREJ});
     // Pass an inchoate CHLO.
     crypto_test_utils::GenerateFullCHLO(
         chlo, &crypto_config_, server_addr_, client_addr_, version, clock_,
@@ -1480,12 +1436,7 @@
   CryptoHandshakeMessage full_chlo_;
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    BufferedPacketStoreTests,
-    BufferedPacketStoreTest,
-    ::testing::ValuesIn(GetBufferedPacketStoreTestParams()));
-
-TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
+TEST_F(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
   InSequence s;
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   QuicConnectionId conn_id = TestConnectionId(1);
@@ -1524,7 +1475,7 @@
   ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 }
 
-TEST_P(BufferedPacketStoreTest,
+TEST_F(BufferedPacketStoreTest,
        ProcessNonChloPacketsForDifferentConnectionsUptoLimit) {
   InSequence s;
   // A bunch of non-CHLO should be buffered upon arrival.
@@ -1578,7 +1529,7 @@
 }
 
 // Tests that store delivers empty packet list if CHLO arrives firstly.
-TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
+TEST_F(BufferedPacketStoreTest, DeliverEmptyPackets) {
   QuicConnectionId conn_id = TestConnectionId(1);
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   EXPECT_CALL(*dispatcher_,
@@ -1596,7 +1547,7 @@
 
 // Tests that a retransmitted CHLO arrives after a connection for the
 // CHLO has been created.
-TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
+TEST_F(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
   InSequence s;
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   QuicConnectionId conn_id = TestConnectionId(1);
@@ -1626,7 +1577,7 @@
 }
 
 // Tests that expiration of a connection add connection id to time wait list.
-TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
+TEST_F(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
   InSequence s;
   CreateTimeWaitListManager();
   QuicBufferedPacketStore* store =
@@ -1652,7 +1603,7 @@
   ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
 }
 
-TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
+TEST_F(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
   // Process more than (|kMaxNumSessionsToCreate| +
   // |kDefaultMaxConnectionsInStore|) CHLOs,
   // the first |kMaxNumSessionsToCreate| should create connections immediately,
@@ -1729,7 +1680,7 @@
 }
 
 // Duplicated CHLO shouldn't be buffered.
-TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
+TEST_F(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
   for (uint64_t conn_id = 1; conn_id <= kMaxNumSessionsToCreate + 1;
        ++conn_id) {
     // Last CHLO will be buffered. Others will create connection right away.
@@ -1778,7 +1729,7 @@
   dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
 }
 
-TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
+TEST_F(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
   uint64_t last_conn_id = kMaxNumSessionsToCreate + 1;
   QuicConnectionId last_connection_id = TestConnectionId(last_conn_id);
   for (uint64_t conn_id = 1; conn_id <= last_conn_id; ++conn_id) {
@@ -1832,7 +1783,7 @@
 
 // Tests that when dispatcher's packet buffer is full, a CHLO on connection
 // which doesn't have buffered CHLO should be buffered.
-TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
+TEST_F(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
   QuicBufferedPacketStore* store =
       QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
 
@@ -1877,7 +1828,7 @@
 }
 
 // Regression test for b/117874922.
-TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
+TEST_F(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
   // Turn off version 99, such that the preferred version is not supported by
   // the server.
   SetQuicReloadableFlag(quic_enable_version_99, false);
diff --git a/quic/core/stateless_rejector.cc b/quic/core/stateless_rejector.cc
deleted file mode 100644
index e2ef51c..0000000
--- a/quic/core/stateless_rejector.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-
-namespace quic {
-
-class StatelessRejector::ValidateCallback
-    : public ValidateClientHelloResultCallback {
- public:
-  explicit ValidateCallback(
-      std::unique_ptr<StatelessRejector> rejector,
-      std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb)
-      : rejector_(std::move(rejector)), cb_(std::move(cb)) {}
-
-  ~ValidateCallback() override = default;
-
-  void Run(QuicReferenceCountedPointer<Result> result,
-           std::unique_ptr<ProofSource::Details> /* proof_source_details */)
-      override {
-    StatelessRejector* rejector_ptr = rejector_.get();
-    rejector_ptr->ProcessClientHello(std::move(result), std::move(rejector_),
-                                     std::move(cb_));
-  }
-
- private:
-  std::unique_ptr<StatelessRejector> rejector_;
-  std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb_;
-};
-
-StatelessRejector::StatelessRejector(
-    ParsedQuicVersion version,
-    const ParsedQuicVersionVector& versions,
-    const QuicCryptoServerConfig* crypto_config,
-    QuicCompressedCertsCache* compressed_certs_cache,
-    const QuicClock* clock,
-    QuicRandom* random,
-    QuicByteCount chlo_packet_size,
-    const QuicSocketAddress& client_address,
-    const QuicSocketAddress& server_address)
-    : state_(UNKNOWN),
-      error_(QUIC_INTERNAL_ERROR),
-      version_(version),
-      versions_(versions),
-      connection_id_(EmptyQuicConnectionId()),
-      chlo_packet_size_(chlo_packet_size),
-      client_address_(client_address),
-      server_address_(server_address),
-      clock_(clock),
-      random_(random),
-      crypto_config_(crypto_config),
-      compressed_certs_cache_(compressed_certs_cache),
-      signed_config_(new QuicSignedServerConfig),
-      params_(new QuicCryptoNegotiatedParameters) {}
-
-StatelessRejector::~StatelessRejector() = default;
-
-void StatelessRejector::OnChlo(QuicTransportVersion version,
-                               QuicConnectionId connection_id,
-                               QuicConnectionId server_designated_connection_id,
-                               const CryptoHandshakeMessage& message) {
-  DCHECK_EQ(kCHLO, message.tag());
-  DCHECK_NE(connection_id, server_designated_connection_id);
-  DCHECK_EQ(state_, UNKNOWN);
-
-  if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support) ||
-      !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) ||
-      !QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message)) {
-    state_ = UNSUPPORTED;
-    return;
-  }
-
-  connection_id_ = connection_id;
-  server_designated_connection_id_ = server_designated_connection_id;
-  chlo_ = message;  // Note: copies the message
-}
-
-void StatelessRejector::Process(std::unique_ptr<StatelessRejector> rejector,
-                                std::unique_ptr<ProcessDoneCallback> done_cb) {
-  QUIC_BUG_IF(rejector->state() != UNKNOWN) << "StatelessRejector::Process "
-                                               "called for a rejector which "
-                                               "has already made a decision";
-  StatelessRejector* rejector_ptr = rejector.get();
-  rejector_ptr->crypto_config_->ValidateClientHello(
-      rejector_ptr->chlo_, rejector_ptr->client_address_.host(),
-      rejector_ptr->server_address_, rejector_ptr->version_.transport_version,
-      rejector_ptr->clock_, rejector_ptr->signed_config_,
-      std::unique_ptr<ValidateCallback>(
-          new ValidateCallback(std::move(rejector), std::move(done_cb))));
-}
-
-class StatelessRejector::ProcessClientHelloCallback
-    : public ProcessClientHelloResultCallback {
- public:
-  ProcessClientHelloCallback(
-      std::unique_ptr<StatelessRejector> rejector,
-      std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb)
-      : rejector_(std::move(rejector)), done_cb_(std::move(done_cb)) {}
-
-  void Run(QuicErrorCode error,
-           const std::string& error_details,
-           std::unique_ptr<CryptoHandshakeMessage> message,
-           std::unique_ptr<DiversificationNonce> diversification_nonce,
-           std::unique_ptr<ProofSource::Details> /* proof_source_details */)
-      override {
-    StatelessRejector* rejector_ptr = rejector_.get();
-    rejector_ptr->ProcessClientHelloDone(
-        error, error_details, std::move(message), std::move(rejector_),
-        std::move(done_cb_));
-  }
-
- private:
-  std::unique_ptr<StatelessRejector> rejector_;
-  std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb_;
-};
-
-void StatelessRejector::ProcessClientHello(
-    QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
-        result,
-    std::unique_ptr<StatelessRejector> rejector,
-    std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
-  std::unique_ptr<ProcessClientHelloCallback> cb(
-      new ProcessClientHelloCallback(std::move(rejector), std::move(done_cb)));
-  crypto_config_->ProcessClientHello(
-      result,
-      /*reject_only=*/true, connection_id_, server_address_, client_address_,
-      version_, versions_,
-      /*use_stateless_rejects=*/true, server_designated_connection_id_, clock_,
-      random_, compressed_certs_cache_, params_, signed_config_,
-      QuicCryptoStream::CryptoMessageFramingOverhead(version_.transport_version,
-                                                     connection_id_),
-      chlo_packet_size_, std::move(cb));
-}
-
-void StatelessRejector::ProcessClientHelloDone(
-    QuicErrorCode error,
-    const std::string& error_details,
-    std::unique_ptr<CryptoHandshakeMessage> message,
-    std::unique_ptr<StatelessRejector> rejector,
-    std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
-  reply_ = std::move(message);
-
-  if (error != QUIC_NO_ERROR) {
-    error_ = error;
-    error_details_ = error_details;
-    state_ = FAILED;
-  } else if (reply_->tag() == kSREJ) {
-    state_ = REJECTED;
-  } else {
-    state_ = ACCEPTED;
-  }
-  done_cb->Run(std::move(rejector));
-}
-
-}  // namespace quic
diff --git a/quic/core/stateless_rejector.h b/quic/core/stateless_rejector.h
deleted file mode 100644
index 18dbdcb..0000000
--- a/quic/core/stateless_rejector.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_
-#define QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_packets.h"
-
-namespace quic {
-
-// The StatelessRejector receives CHLO messages and generates an SREJ
-// message in response, if the CHLO can be statelessly rejected.
-class StatelessRejector {
- public:
-  enum State {
-    UNKNOWN,      // State has not yet been determined
-    UNSUPPORTED,  // Stateless rejects are not supported
-    FAILED,       // There was an error processing the CHLO.
-    ACCEPTED,     // The CHLO was accepted
-    REJECTED,     // The CHLO was rejected.
-  };
-
-  StatelessRejector(ParsedQuicVersion version,
-                    const ParsedQuicVersionVector& versions,
-                    const QuicCryptoServerConfig* crypto_config,
-                    QuicCompressedCertsCache* compressed_certs_cache,
-                    const QuicClock* clock,
-                    QuicRandom* random,
-                    QuicByteCount chlo_packet_size,
-                    const QuicSocketAddress& client_address,
-                    const QuicSocketAddress& server_address);
-  StatelessRejector(const StatelessRejector&) = delete;
-  StatelessRejector& operator=(const StatelessRejector&) = delete;
-
-  ~StatelessRejector();
-
-  // Called when |chlo| is received for |connection_id|.
-  void OnChlo(QuicTransportVersion version,
-              QuicConnectionId connection_id,
-              QuicConnectionId server_designated_connection_id,
-              const CryptoHandshakeMessage& chlo);
-
-  class ProcessDoneCallback {
-   public:
-    virtual ~ProcessDoneCallback() = default;
-    virtual void Run(std::unique_ptr<StatelessRejector> rejector) = 0;
-  };
-
-  // Perform processing to determine whether the CHLO received in OnChlo should
-  // be statelessly rejected, and invoke the callback once a decision has been
-  // made.
-  static void Process(std::unique_ptr<StatelessRejector> rejector,
-                      std::unique_ptr<ProcessDoneCallback> done_cb);
-
-  // Return the version of the CHLO.
-  ParsedQuicVersion version() const { return version_; }
-
-  // Returns the state of the rejector after OnChlo() has been called.
-  State state() const { return state_; }
-
-  // Returns the error code when state() returns FAILED.
-  QuicErrorCode error() const { return error_; }
-
-  // Returns the error details when state() returns FAILED.
-  std::string error_details() const { return error_details_; }
-
-  // Returns the connection ID.
-  QuicConnectionId connection_id() const { return connection_id_; }
-
-  // Returns the SREJ message when state() returns REJECTED.
-  const CryptoHandshakeMessage& reply() const { return *reply_; }
-
- private:
-  // Helper class which is passed in to
-  // QuicCryptoServerConfig::ValidateClientHello.
-  class ValidateCallback;
-  friend class ValidateCallback;
-
-  class ProcessClientHelloCallback;
-  friend class ProcessClientHelloCallback;
-
-  void ProcessClientHello(
-      QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
-          result,
-      std::unique_ptr<StatelessRejector> rejector,
-      std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
-
-  void ProcessClientHelloDone(
-      QuicErrorCode error,
-      const std::string& error_details,
-      std::unique_ptr<CryptoHandshakeMessage> message,
-      std::unique_ptr<StatelessRejector> rejector,
-      std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
-
-  State state_;
-  QuicErrorCode error_;
-  std::string error_details_;
-  ParsedQuicVersion version_;
-  ParsedQuicVersionVector versions_;
-  QuicConnectionId connection_id_;
-  QuicConnectionId server_designated_connection_id_;
-  QuicByteCount chlo_packet_size_;
-  QuicSocketAddress client_address_;
-  QuicSocketAddress server_address_;
-  const QuicClock* clock_;
-  QuicRandom* random_;
-  const QuicCryptoServerConfig* crypto_config_;
-  QuicCompressedCertsCache* compressed_certs_cache_;
-  CryptoHandshakeMessage chlo_;
-  std::unique_ptr<CryptoHandshakeMessage> reply_;
-  CryptoFramer crypto_framer_;
-  QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
-  QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
-};
-
-}  // namespace quic
-
-#endif  // QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_
diff --git a/quic/core/stateless_rejector_test.cc b/quic/core/stateless_rejector_test.cc
deleted file mode 100644
index f8757e1..0000000
--- a/quic/core/stateless_rejector_test.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-
-namespace quic {
-namespace test {
-namespace {
-
-QuicConnectionId TestServerDesignatedConnectionId() {
-  return TestConnectionId(24);
-}
-
-// All four combinations of the two flags involved.
-enum FlagsMode { ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED };
-
-const char* FlagsModeToString(FlagsMode mode) {
-  switch (mode) {
-    case ENABLED:
-      return "ENABLED";
-    case STATELESS_DISABLED:
-      return "STATELESS_DISABLED";
-    case CHEAP_DISABLED:
-      return "CHEAP_DISABLED";
-    case BOTH_DISABLED:
-      return "BOTH_DISABLED";
-    default:
-      QUIC_DLOG(FATAL) << "Unexpected FlagsMode";
-      return nullptr;
-  }
-}
-
-// Test various combinations of QUIC version and flag state.
-struct TestParams {
-  ParsedQuicVersion version = UnsupportedQuicVersion();
-  FlagsMode flags;
-};
-
-std::string TestParamToString(
-    const testing::TestParamInfo<TestParams>& params) {
-  return QuicStrCat("v", ParsedQuicVersionToString(params.param.version), "_",
-                    FlagsModeToString(params.param.flags));
-}
-
-std::vector<TestParams> GetTestParams() {
-  std::vector<TestParams> params;
-  for (FlagsMode flags :
-       {ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED}) {
-    for (ParsedQuicVersion version : AllSupportedVersions()) {
-      TestParams param;
-      param.version = version;
-      param.flags = flags;
-      params.push_back(param);
-    }
-  }
-  return params;
-}
-
-class StatelessRejectorTest : public QuicTestWithParam<TestParams> {
- public:
-  StatelessRejectorTest()
-      : proof_source_(crypto_test_utils::ProofSourceForTesting()),
-        config_(QuicCryptoServerConfig::TESTING,
-                QuicRandom::GetInstance(),
-                crypto_test_utils::ProofSourceForTesting(),
-                KeyExchangeSource::Default(),
-                TlsServerHandshaker::CreateSslCtx()),
-        config_peer_(&config_),
-        compressed_certs_cache_(
-            QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
-        rejector_(QuicMakeUnique<StatelessRejector>(
-            GetParam().version,
-            AllSupportedVersions(),
-            &config_,
-            &compressed_certs_cache_,
-            &clock_,
-            QuicRandom::GetInstance(),
-            kDefaultMaxPacketSize,
-            QuicSocketAddress(QuicIpAddress::Loopback4(), 12345),
-            QuicSocketAddress(QuicIpAddress::Loopback4(), 443))) {
-    SetQuicReloadableFlag(
-        enable_quic_stateless_reject_support,
-        GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED);
-    SetQuicReloadableFlag(
-        quic_use_cheap_stateless_rejects,
-        GetParam().flags == ENABLED || GetParam().flags == STATELESS_DISABLED);
-
-    // Add a new primary config.
-    std::unique_ptr<CryptoHandshakeMessage> msg(config_.AddDefaultConfig(
-        QuicRandom::GetInstance(), &clock_, config_options_));
-
-    // Save the server config.
-    scid_hex_ =
-        "#" + QuicTextUtils::HexEncode(config_peer_.GetPrimaryConfig()->id);
-
-    // Encode the QUIC version.
-    ver_hex_ = ParsedQuicVersionToString(GetParam().version);
-
-    // Generate a public value.
-    char public_value[32];
-    memset(public_value, 42, sizeof(public_value));
-    pubs_hex_ =
-        "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value));
-
-    // Generate a client nonce.
-    std::string nonce;
-    CryptoUtils::GenerateNonce(
-        clock_.WallNow(), QuicRandom::GetInstance(),
-        QuicStringPiece(
-            reinterpret_cast<char*>(config_peer_.GetPrimaryConfig()->orbit),
-            kOrbitSize),
-        &nonce);
-    nonc_hex_ = "#" + QuicTextUtils::HexEncode(nonce);
-
-    // Generate a source address token.
-    SourceAddressTokens previous_tokens;
-    QuicIpAddress ip = QuicIpAddress::Loopback4();
-    MockRandom rand;
-    std::string stk = config_peer_.NewSourceAddressToken(
-        config_peer_.GetPrimaryConfig()->id, previous_tokens, ip, &rand,
-        clock_.WallNow(), nullptr);
-    stk_hex_ = "#" + QuicTextUtils::HexEncode(stk);
-  }
-
- protected:
-  class ProcessDoneCallback : public StatelessRejector::ProcessDoneCallback {
-   public:
-    explicit ProcessDoneCallback(StatelessRejectorTest* test) : test_(test) {}
-    void Run(std::unique_ptr<StatelessRejector> rejector) override {
-      test_->rejector_ = std::move(rejector);
-    }
-
-   private:
-    StatelessRejectorTest* test_;
-  };
-
-  std::unique_ptr<ProofSource> proof_source_;
-  MockClock clock_;
-  QuicCryptoServerConfig config_;
-  QuicCryptoServerConfigPeer config_peer_;
-  QuicCompressedCertsCache compressed_certs_cache_;
-  QuicCryptoServerConfig::ConfigOptions config_options_;
-  std::unique_ptr<StatelessRejector> rejector_;
-
-  // Values used in CHLO messages
-  std::string scid_hex_;
-  std::string nonc_hex_;
-  std::string pubs_hex_;
-  std::string ver_hex_;
-  std::string stk_hex_;
-};
-
-INSTANTIATE_TEST_SUITE_P(Flags,
-                         StatelessRejectorTest,
-                         ::testing::ValuesIn(GetTestParams()),
-                         TestParamToString);
-
-TEST_P(StatelessRejectorTest, InvalidChlo) {
-  // clang-format off
-  const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
-      {{"PDMD", "X509"},
-       {"COPT", "SREJ"}});
-  // clang-format on
-  rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
-                    TestServerDesignatedConnectionId(), client_hello);
-
-  if (GetParam().flags != ENABLED) {
-    EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
-    return;
-  }
-
-  // The StatelessRejector is undecided - proceed with async processing
-  ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
-  StatelessRejector::Process(std::move(rejector_),
-                             QuicMakeUnique<ProcessDoneCallback>(this));
-
-  EXPECT_EQ(StatelessRejector::FAILED, rejector_->state());
-  EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_->error());
-}
-
-TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) {
-  // clang-format off
-  const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
-      {{"PDMD", "X509"},
-       {"AEAD", "AESG"},
-       {"KEXS", "C255"},
-       {"PUBS", pubs_hex_},
-       {"NONC", nonc_hex_},
-       {"VER\0", ver_hex_}},
-      kClientHelloMinimumSize);
-  // clang-format on
-
-  rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
-                    TestServerDesignatedConnectionId(), client_hello);
-  EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
-}
-
-TEST_P(StatelessRejectorTest, RejectChlo) {
-  // clang-format off
-  const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
-      {{"PDMD", "X509"},
-       {"AEAD", "AESG"},
-       {"KEXS", "C255"},
-       {"COPT", "SREJ"},
-       {"SCID", scid_hex_},
-       {"PUBS", pubs_hex_},
-       {"NONC", nonc_hex_},
-       {"#004b5453", stk_hex_},
-       {"VER\0", ver_hex_}},
-      kClientHelloMinimumSize);
-  // clang-format on
-
-  rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
-                    TestServerDesignatedConnectionId(), client_hello);
-  if (GetParam().flags != ENABLED) {
-    EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
-    return;
-  }
-
-  // The StatelessRejector is undecided - proceed with async processing
-  ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
-  StatelessRejector::Process(std::move(rejector_),
-                             QuicMakeUnique<ProcessDoneCallback>(this));
-
-  ASSERT_EQ(StatelessRejector::REJECTED, rejector_->state());
-  const CryptoHandshakeMessage& reply = rejector_->reply();
-  EXPECT_EQ(kSREJ, reply.tag());
-  QuicTagVector reject_reasons;
-  EXPECT_EQ(QUIC_NO_ERROR, reply.GetTaglist(kRREJ, &reject_reasons));
-  EXPECT_EQ(1u, reject_reasons.size());
-  EXPECT_EQ(INVALID_EXPECTED_LEAF_CERTIFICATE,
-            static_cast<HandshakeFailureReason>(reject_reasons[0]));
-}
-
-TEST_P(StatelessRejectorTest, AcceptChlo) {
-  const uint64_t xlct = crypto_test_utils::LeafCertHashForTesting();
-  const std::string xlct_hex =
-      "#" + QuicTextUtils::HexEncode(reinterpret_cast<const char*>(&xlct),
-                                     sizeof(xlct));
-  // clang-format off
-  const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
-      {{"PDMD", "X509"},
-       {"AEAD", "AESG"},
-       {"KEXS", "C255"},
-       {"COPT", "SREJ"},
-       {"SCID", scid_hex_},
-       {"PUBS", pubs_hex_},
-       {"NONC", nonc_hex_},
-       {"#004b5453", stk_hex_},
-       {"VER\0", ver_hex_},
-       {"XLCT", xlct_hex}},
-      kClientHelloMinimumSize);
-  // clang-format on
-
-  rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
-                    TestServerDesignatedConnectionId(), client_hello);
-  if (GetParam().flags != ENABLED) {
-    EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
-    return;
-  }
-
-  // The StatelessRejector is undecided - proceed with async processing
-  ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
-  StatelessRejector::Process(std::move(rejector_),
-                             QuicMakeUnique<ProcessDoneCallback>(this));
-
-  EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_->state());
-}
-
-}  // namespace
-}  // namespace test
-}  // namespace quic