Make the QuicSession actually delete the QuicConfig after the handshake
compelete, and save various members into local state.

Protected by quic_reloadable_flag_quic_delete_config.

PiperOrigin-RevId: 838907991
diff --git a/quiche/common/quiche_feature_flags_list.h b/quiche/common/quiche_feature_flags_list.h
index cabd955..a34aa63 100755
--- a/quiche/common/quiche_feature_flags_list.h
+++ b/quiche/common/quiche_feature_flags_list.h
@@ -25,6 +25,7 @@
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_default_to_bbr, true, false, "When true, defaults to BBR congestion control instead of Cubic.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_default_to_bbr_v2, false, false, "If true, use BBRv2 as the default congestion controller. Takes precedence over --quic_default_to_bbr.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_delay_connection_close_on_invalid_sni, true, true, "Delay closing the connection on invalid SNI in client hello till after the transport parameters are parsed.")
+QUICHE_FLAG(bool, quiche_reloadable_flag_quic_delete_config, false, false, "If true, the QuicSession will delete the QuicConfig after the handshake completes.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_deliver_stop_sending_to_zombie_streams, true, true, "If true, deliver STOP_SENDING to zombie streams.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_disable_batch_write, false, false, "If true, round-robin stream writes instead of batching in QuicWriteBlockedList.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_disable_server_blackhole_detection, false, false, "If true, disable blackhole detection on server side.")
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index 841c020..d0a766a 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -101,6 +101,58 @@
 
 }  // namespace
 
+void QuicSession::SavedConfig::DeleteConfig(ParsedQuicVersion version) {
+  if (!delete_config_) {
+    config_deleted_ = true;
+    return;
+  }
+
+  if (version.IsIetfQuic()) {
+    QUIC_BUG_IF(no_config_in_delete_config, config_ == nullptr);
+  } else if (config_ == nullptr) {
+    return;
+  }
+
+  if (config_->HasReceivedInitialStreamFlowControlWindowBytes()) {
+    has_received_initial_stream_flow_control_window_bytes_ = true;
+    received_initial_stream_flow_control_window_bytes_ =
+        config_->ReceivedInitialStreamFlowControlWindowBytes();
+  }
+  if (config_->HasReceivedInitialMaxStreamDataBytesUnidirectional()) {
+    has_received_initial_max_stream_data_bytes_unidirectional_ = true;
+    received_initial_max_stream_data_bytes_unidirectional_ =
+        config_->ReceivedInitialMaxStreamDataBytesUnidirectional();
+  }
+  if (config_->HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional()) {
+    has_received_initial_max_stream_data_bytes_outgoing_bidirectional_ = true;
+    received_initial_max_stream_data_bytes_outgoing_bidirectional_ =
+        config_->ReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
+  }
+  if (config_->HasReceivedInitialMaxStreamDataBytesIncomingBidirectional()) {
+    has_received_initial_max_stream_data_bytes_incoming_bidirectional_ = true;
+    received_initial_max_stream_data_bytes_incoming_bidirectional_ =
+        config_->ReceivedInitialMaxStreamDataBytesIncomingBidirectional();
+  }
+  if (config_->HasReceivedMaxBidirectionalStreams()) {
+    has_received_max_bidirectional_streams_ = true;
+    received_max_bidirectional_streams_ =
+        config_->ReceivedMaxBidirectionalStreams();
+  }
+
+  get_initial_stream_flow_control_window_to_send_ =
+      config_->GetInitialStreamFlowControlWindowToSend();
+  get_initial_max_stream_data_bytes_unidirectional_to_send_ =
+      config_->GetInitialMaxStreamDataBytesUnidirectionalToSend();
+  get_initial_max_stream_data_bytes_outgoing_bidirectional_to_send_ =
+      config_->GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend();
+  get_initial_max_stream_data_bytes_incoming_bidirectional_to_send_ =
+      config_->GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
+  received_max_bidirectional_streams_ =
+      config_->ReceivedMaxBidirectionalStreams();
+  idle_network_timeout_ = config_->IdleNetworkTimeout();
+  config_.reset();
+}
+
 #define ENDPOINT \
   (perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
 
@@ -1970,7 +2022,7 @@
   GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel(
       ENCRYPTION_HANDSHAKE);
   connection()->OnHandshakeComplete();
-  saved_config_.DeleteConfig();
+  saved_config_.DeleteConfig(version());
 }
 
 void QuicSession::OnZeroRttRejected(int reason) {
diff --git a/quiche/quic/core/quic_session.h b/quiche/quic/core/quic_session.h
index ca0d23c..562b2db 100644
--- a/quiche/quic/core/quic_session.h
+++ b/quiche/quic/core/quic_session.h
@@ -120,86 +120,149 @@
   class QUICHE_EXPORT SavedConfig {
    public:
     // Creates a new `SavedConfig` which stores a copy of `config`.
-    SavedConfig(const QuicConfig& config) : config_(config) {}
+    explicit SavedConfig(const QuicConfig& config)
+        : config_(std::make_unique<QuicConfig>(config)) {}
 
     // Returns the underlying `QuicConfig`. Must not be called after the config
     // is deleted.
     QuicConfig* RawConfig() {
       QUIC_BUG_IF(no_config, config_deleted_);
-      return &config_;
+      QUIC_BUG_IF(no_config, delete_config_ && config_ == nullptr);
+      return config_.get();
     }
 
-    // Marks the config deleted but does not actually delete it.
-    // TODO(b/461482627): Store `config_` in a unique_ptr and reset it.
-    void DeleteConfig() { config_deleted_ = true; }
+    void DeleteConfig(ParsedQuicVersion version);
 
     bool HasReceivedInitialStreamFlowControlWindowBytes() const {
-      return config_.HasReceivedInitialStreamFlowControlWindowBytes();
+      if (delete_config_ && config_ == nullptr) {
+        return has_received_initial_stream_flow_control_window_bytes_;
+      }
+      return config_->HasReceivedInitialStreamFlowControlWindowBytes();
     }
 
     bool HasReceivedInitialMaxStreamDataBytesUnidirectional() const {
-      return config_.HasReceivedInitialMaxStreamDataBytesUnidirectional();
+      if (delete_config_ && config_ == nullptr) {
+        return has_received_initial_max_stream_data_bytes_unidirectional_;
+      }
+      return config_->HasReceivedInitialMaxStreamDataBytesUnidirectional();
     }
 
     bool HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const {
+      if (delete_config_ && config_ == nullptr) {
+        return has_received_initial_max_stream_data_bytes_outgoing_bidirectional_;  // NOLINT
+      }
       return config_
-          .HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
+          ->HasReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
     }
 
     bool HasReceivedInitialMaxStreamDataBytesIncomingBidirectional() const {
+      if (delete_config_ && config_ == nullptr) {
+        return has_received_initial_max_stream_data_bytes_incoming_bidirectional_;  // NOLINT
+      }
       return config_
-          .HasReceivedInitialMaxStreamDataBytesIncomingBidirectional();
+          ->HasReceivedInitialMaxStreamDataBytesIncomingBidirectional();
     }
 
     bool HasReceivedMaxBidirectionalStreams() const {
-      return config_.HasReceivedMaxBidirectionalStreams();
+      if (delete_config_ && config_ == nullptr) {
+        return has_received_max_bidirectional_streams_;
+      }
+      return config_->HasReceivedMaxBidirectionalStreams();
     }
 
     uint64_t ReceivedInitialStreamFlowControlWindowBytes() const {
-      return config_.ReceivedInitialStreamFlowControlWindowBytes();
+      if (delete_config_ && config_ == nullptr) {
+        return received_initial_stream_flow_control_window_bytes_;
+      }
+      return config_->ReceivedInitialStreamFlowControlWindowBytes();
     }
 
     uint64_t ReceivedInitialMaxStreamDataBytesUnidirectional() const {
-      return config_.ReceivedInitialMaxStreamDataBytesUnidirectional();
+      if (delete_config_ && config_ == nullptr) {
+        return received_initial_max_stream_data_bytes_unidirectional_;
+      }
+      return config_->ReceivedInitialMaxStreamDataBytesUnidirectional();
     }
 
     uint64_t ReceivedInitialMaxStreamDataBytesOutgoingBidirectional() const {
-      return config_.ReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
+      if (delete_config_ && config_ == nullptr) {
+        return received_initial_max_stream_data_bytes_outgoing_bidirectional_;
+      }
+      return config_->ReceivedInitialMaxStreamDataBytesOutgoingBidirectional();
     }
 
     uint64_t ReceivedInitialMaxStreamDataBytesIncomingBidirectional() const {
-      return config_.ReceivedInitialMaxStreamDataBytesIncomingBidirectional();
+      if (delete_config_ && config_ == nullptr) {
+        return received_initial_max_stream_data_bytes_incoming_bidirectional_;
+      }
+      return config_->ReceivedInitialMaxStreamDataBytesIncomingBidirectional();
     }
 
     uint64_t GetInitialStreamFlowControlWindowToSend() const {
-      return config_.GetInitialStreamFlowControlWindowToSend();
+      if (delete_config_ && config_ == nullptr) {
+        return get_initial_stream_flow_control_window_to_send_;
+      }
+      return config_->GetInitialStreamFlowControlWindowToSend();
     }
 
     uint64_t GetInitialMaxStreamDataBytesUnidirectionalToSend() const {
-      return config_.GetInitialMaxStreamDataBytesUnidirectionalToSend();
+      if (delete_config_ && config_ == nullptr) {
+        return get_initial_max_stream_data_bytes_unidirectional_to_send_;
+      }
+      return config_->GetInitialMaxStreamDataBytesUnidirectionalToSend();
     }
 
     uint64_t GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend() const {
-      return config_.GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend();
+      if (delete_config_ && config_ == nullptr) {
+        return get_initial_max_stream_data_bytes_outgoing_bidirectional_to_send_;  // NOLINT
+      }
+      return config_->GetInitialMaxStreamDataBytesOutgoingBidirectionalToSend();
     }
 
     uint64_t GetInitialMaxStreamDataBytesIncomingBidirectionalToSend() const {
-      return config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
+      if (delete_config_ && config_ == nullptr) {
+        return get_initial_max_stream_data_bytes_incoming_bidirectional_to_send_;  // NOLINT
+      }
+      return config_->GetInitialMaxStreamDataBytesIncomingBidirectionalToSend();
     }
 
     uint64_t ReceivedMaxBidirectionalStreams() const {
-      return config_.ReceivedMaxBidirectionalStreams();
+      if (delete_config_ && config_ == nullptr) {
+        return received_max_bidirectional_streams_;
+      }
+      return config_->ReceivedMaxBidirectionalStreams();
     }
 
     QuicTime::Delta IdleNetworkTimeout() const {
-      return config_.IdleNetworkTimeout();
+      if (delete_config_ && config_ == nullptr) {
+        return idle_network_timeout_;
+      }
+      return config_->IdleNetworkTimeout();
     }
 
    private:
-    // TODO(b/461482627): Store `config_` in a unique_ptr and reset it in
-    // `DeleteConfig()`.
-    QuicConfig config_;
+    std::unique_ptr<QuicConfig> config_;
+    // TODO(b/461482627): Delete this when retiring the flag.
     bool config_deleted_ = false;
+    const bool delete_config_ = GetQuicReloadableFlag(quic_delete_config);
+
+    bool has_received_initial_stream_flow_control_window_bytes_ = false;
+    bool has_received_initial_max_stream_data_bytes_unidirectional_ = false;
+    bool has_received_initial_max_stream_data_bytes_outgoing_bidirectional_ =
+        false;
+    bool has_received_initial_max_stream_data_bytes_incoming_bidirectional_ =
+        false;
+    bool has_received_max_bidirectional_streams_ = false;
+    uint64_t received_initial_stream_flow_control_window_bytes_;
+    uint64_t received_initial_max_stream_data_bytes_unidirectional_;
+    uint64_t received_initial_max_stream_data_bytes_outgoing_bidirectional_;
+    uint64_t received_initial_max_stream_data_bytes_incoming_bidirectional_;
+    uint64_t get_initial_stream_flow_control_window_to_send_;
+    uint64_t get_initial_max_stream_data_bytes_unidirectional_to_send_;
+    uint64_t get_initial_max_stream_data_bytes_outgoing_bidirectional_to_send_;
+    uint64_t get_initial_max_stream_data_bytes_incoming_bidirectional_to_send_;
+    uint64_t received_max_bidirectional_streams_;
+    QuicTime::Delta idle_network_timeout_ = QuicTime::Delta::Zero();
   };
 
   // Does not take ownership of |connection| or |visitor|.