Update QuicControlFrameManager to support RESET_STREAM_AT frames.

New code is not called anywhere in the code base.

PiperOrigin-RevId: 686983422
diff --git a/quiche/quic/core/quic_control_frame_manager.cc b/quiche/quic/core/quic_control_frame_manager.cc
index 28c5b0c..9dd73a1 100644
--- a/quiche/quic/core/quic_control_frame_manager.cc
+++ b/quiche/quic/core/quic_control_frame_manager.cc
@@ -10,8 +10,10 @@
 #include "quiche/quic/core/frames/quic_ack_frequency_frame.h"
 #include "quiche/quic/core/frames/quic_frame.h"
 #include "quiche/quic/core/frames/quic_new_connection_id_frame.h"
+#include "quiche/quic/core/frames/quic_reset_stream_at_frame.h"
 #include "quiche/quic/core/frames/quic_retire_connection_id_frame.h"
 #include "quiche/quic/core/quic_constants.h"
+#include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/core/quic_session.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/quic_utils.h"
@@ -68,6 +70,15 @@
       ++last_control_frame_id_, id, error, bytes_written))));
 }
 
+void QuicControlFrameManager::WriteOrBufferResetStreamAt(
+    QuicStreamId id, QuicResetStreamError error, QuicStreamOffset bytes_written,
+    QuicStreamOffset reliable_size) {
+  QUIC_DVLOG(1) << "Writing RST_STREAM_AT_FRAME";
+  WriteOrBufferQuicFrame((QuicFrame(new QuicResetStreamAtFrame(
+      ++last_control_frame_id_, id, error.ietf_application_code(),
+      bytes_written, reliable_size))));
+}
+
 void QuicControlFrameManager::WriteOrBufferGoAway(
     QuicErrorCode error, QuicStreamId last_good_stream_id,
     const std::string& reason) {
diff --git a/quiche/quic/core/quic_control_frame_manager.h b/quiche/quic/core/quic_control_frame_manager.h
index 3508f9d..3fc93b0 100644
--- a/quiche/quic/core/quic_control_frame_manager.h
+++ b/quiche/quic/core/quic_control_frame_manager.h
@@ -57,6 +57,12 @@
   void WriteOrBufferRstStream(QuicControlFrameId id, QuicResetStreamError error,
                               QuicStreamOffset bytes_written);
 
+  // Tries to send a RESET_STREAM_AT frame. Buffers the frame if it cannot be
+  // sent immediately.
+  void WriteOrBufferResetStreamAt(QuicStreamId id, QuicResetStreamError error,
+                                  QuicStreamOffset bytes_written,
+                                  QuicStreamOffset reliable_size);
+
   // Tries to send a GOAWAY_FRAME. Buffers the frame if it cannot be sent
   // immediately.
   void WriteOrBufferGoAway(QuicErrorCode error,
diff --git a/quiche/quic/core/quic_control_frame_manager_test.cc b/quiche/quic/core/quic_control_frame_manager_test.cc
index 2201c4a..a007d92 100644
--- a/quiche/quic/core/quic_control_frame_manager_test.cc
+++ b/quiche/quic/core/quic_control_frame_manager_test.cc
@@ -10,7 +10,9 @@
 
 #include "quiche/quic/core/crypto/null_encrypter.h"
 #include "quiche/quic/core/frames/quic_ack_frequency_frame.h"
+#include "quiche/quic/core/frames/quic_reset_stream_at_frame.h"
 #include "quiche/quic/core/frames/quic_retire_connection_id_frame.h"
+#include "quiche/quic/core/quic_error_codes.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_expect_bug.h"
 #include "quiche/quic/platform/api/quic_flags.h"
@@ -84,6 +86,26 @@
   EXPECT_FALSE(manager_->WillingToWrite());
 }
 
+TEST_F(QuicControlFrameManagerTest, WriteOrBufferResetStreamAt) {
+  QuicResetStreamAtFrame reset_stream_at = {1, kTestStreamId,
+                                            QUIC_STREAM_CANCELLED, 20, 10};
+  EXPECT_CALL(*session_, WriteControlFrame(_, _))
+      .WillOnce(Invoke([&reset_stream_at](const QuicFrame& frame,
+                                          TransmissionType /*type*/) {
+        EXPECT_EQ(RESET_STREAM_AT_FRAME, frame.type);
+        EXPECT_EQ(reset_stream_at, *frame.reset_stream_at_frame);
+        ClearControlFrame(frame);
+        return true;
+      }));
+  manager_->WriteOrBufferResetStreamAt(
+      reset_stream_at.stream_id,
+      QuicResetStreamError::FromIetf(reset_stream_at.error),
+      reset_stream_at.final_offset, reset_stream_at.reliable_offset);
+  EXPECT_EQ(1, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
+  EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&reset_stream_at)));
+  EXPECT_FALSE(manager_->WillingToWrite());
+}
+
 TEST_F(QuicControlFrameManagerTest, WriteOrBufferGoAway) {
   QuicGoAwayFrame goaway = {1, QUIC_PEER_GOING_AWAY, kTestStreamId,
                             "Going away."};