Change QuicConnection::cipher_id() to get underlying cipher id differently.

The current implementation doesn't work if cipher_id() is called outside of ProcessUdpPacket() stack. The new implementation iterate through all decrypters at different encryption levels to get the cipher id.

Also renamed --gfe2_reloadable_flag_quic_limit_new_streams_per_loop to --gfe2_reloadable_flag_quic_limit_new_streams_per_loop_2.

Protected by FLAGS_quic_reloadable_flag_quic_limit_new_streams_per_loop_2.

PiperOrigin-RevId: 605355455
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index f1d65b9..cfcce7c 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -5724,8 +5724,23 @@
 
 uint32_t QuicConnection::cipher_id() const {
   if (version().KnowsWhichDecrypterToUse()) {
-    return framer_.GetDecrypter(last_received_packet_info_.decrypted_level)
-        ->cipher_id();
+    if (quic_limit_new_streams_per_loop_2_) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_limit_new_streams_per_loop_2, 4, 4);
+      for (auto decryption_level :
+           {ENCRYPTION_FORWARD_SECURE, ENCRYPTION_HANDSHAKE,
+            ENCRYPTION_ZERO_RTT, ENCRYPTION_INITIAL}) {
+        const QuicDecrypter* decrypter = framer_.GetDecrypter(decryption_level);
+        if (decrypter != nullptr) {
+          return decrypter->cipher_id();
+        }
+      }
+      QUICHE_BUG(no_decrypter_found)
+          << ENDPOINT << "No decrypter found at all encryption levels";
+      return 0;
+    } else {
+      return framer_.GetDecrypter(last_received_packet_info_.decrypted_level)
+          ->cipher_id();
+    }
   }
   return framer_.decrypter()->cipher_id();
 }
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 598a11e..7604cbb 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -1348,6 +1348,10 @@
     return packet_writer_params_.ecn_codepoint;
   }
 
+  bool quic_limit_new_streams_per_loop_2() const {
+    return quic_limit_new_streams_per_loop_2_;
+  }
+
  protected:
   // Calls cancel() on all the alarms owned by this connection.
   void CancelAllAlarms();
@@ -2418,6 +2422,9 @@
   // The ECN codepoint of the last packet to be sent to the writer, which
   // might be different from the next codepoint in per_packet_options_.
   QuicEcnCodepoint last_ecn_codepoint_sent_ = ECN_NOT_ECT;
+
+  const bool quic_limit_new_streams_per_loop_2_ =
+      GetQuicReloadableFlag(quic_limit_new_streams_per_loop_2);
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h
index c8b3447..10790c5 100644
--- a/quiche/quic/core/quic_flags_list.h
+++ b/quiche/quic/core/quic_flags_list.h
@@ -99,6 +99,8 @@
 QUIC_FLAG(quic_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false)
 // If true, when TicketCrypter fails to encrypt a session ticket, quic::TlsServerHandshaker will send a placeholder ticket, instead of an empty one, to the client.
 QUIC_FLAG(quic_reloadable_flag_quic_send_placeholder_ticket_when_encrypt_ticket_fails, true)
+// If true, when the peer sends connection options \\\\\\\'SLP1\\\\\\\', \\\\\\\'SLP2\\\\\\\' and \\\\\\\'SLPF\\\\\\\', internet facing GFEs will only allow a limited number of new requests to be processed per event loop, and postpone the rest to the following event loops. Also guard QuicConnection to iterate through all decrypters at each encryption level to get cipher id for a request.
+QUIC_FLAG(quic_reloadable_flag_quic_limit_new_streams_per_loop_2, false)
 // When true, allows sending of QUIC packets marked ECT(1). A different flag (TBD) will actually utilize this capability to send ECT(1).
 QUIC_FLAG(quic_restart_flag_quic_support_ect1, false)
 // When true, correctly stores the ECN mark on incoming packets when buffered while waiting for a crypto context.