Make QuicSendControlStream send actual value for SETTINGS_QPACK_MAX_TABLE_CAPACITY.

gfe-relnote: n/a, change to QUIC v99-only code.  Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 266454276
Change-Id: If56657c5955985ce55aee2bd9d2bc70e9dcb175d
diff --git a/quic/core/http/quic_send_control_stream.cc b/quic/core/http/quic_send_control_stream.cc
index 2924eda..507380d 100644
--- a/quic/core/http/quic_send_control_stream.cc
+++ b/quic/core/http/quic_send_control_stream.cc
@@ -13,9 +13,12 @@
 QuicSendControlStream::QuicSendControlStream(
     QuicStreamId id,
     QuicSession* session,
+    uint64_t qpack_maximum_dynamic_table_capacity,
     uint64_t max_inbound_header_list_size)
     : QuicStream(id, session, /*is_static = */ true, WRITE_UNIDIRECTIONAL),
       settings_sent_(false),
+      qpack_maximum_dynamic_table_capacity_(
+          qpack_maximum_dynamic_table_capacity),
       max_inbound_header_list_size_(max_inbound_header_list_size) {}
 
 void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
@@ -43,7 +46,8 @@
   settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
       max_inbound_header_list_size_;
   settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
-      kDefaultQpackMaxDynamicTableCapacity;
+      qpack_maximum_dynamic_table_capacity_;
+
   std::unique_ptr<char[]> buffer;
   QuicByteCount frame_length =
       encoder_.SerializeSettingsFrame(settings, &buffer);
diff --git a/quic/core/http/quic_send_control_stream.h b/quic/core/http/quic_send_control_stream.h
index e18fd27..2e8959b 100644
--- a/quic/core/http/quic_send_control_stream.h
+++ b/quic/core/http/quic_send_control_stream.h
@@ -19,9 +19,10 @@
  public:
   // |session| can't be nullptr, and the ownership is not passed. The stream can
   // only be accessed through the session.
-  explicit QuicSendControlStream(QuicStreamId id,
-                                 QuicSession* session,
-                                 uint64_t max_inbound_header_list_size);
+  QuicSendControlStream(QuicStreamId id,
+                        QuicSession* session,
+                        uint64_t qpack_maximum_dynamic_table_capacity,
+                        uint64_t max_inbound_header_list_size);
   QuicSendControlStream(const QuicSendControlStream&) = delete;
   QuicSendControlStream& operator=(const QuicSendControlStream&) = delete;
   ~QuicSendControlStream() override = default;
@@ -49,7 +50,9 @@
   // Track if a settings frame is already sent.
   bool settings_sent_;
 
-  // Max inbound header list size that will send as setting.
+  // SETTINGS_QPACK_MAX_TABLE_CAPACITY value to send.
+  const uint64_t qpack_maximum_dynamic_table_capacity_;
+  // SETTINGS_MAX_HEADER_LIST_SIZE value to send.
   const uint64_t max_inbound_header_list_size_;
 };
 
diff --git a/quic/core/http/quic_send_control_stream_test.cc b/quic/core/http/quic_send_control_stream_test.cc
index fc64574..49cc0ed 100644
--- a/quic/core/http/quic_send_control_stream_test.cc
+++ b/quic/core/http/quic_send_control_stream_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h"
 
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h"
 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
 
@@ -11,6 +12,7 @@
 namespace test {
 
 namespace {
+
 using ::testing::_;
 using ::testing::Invoke;
 using ::testing::StrictMock;
@@ -53,12 +55,15 @@
             perspective(),
             SupportedVersions(GetParam().version))),
         session_(connection_) {
-    session_.Initialize();
-    send_control_stream_ = QuicSpdySessionPeer::GetSendControlStream(&session_);
     ON_CALL(session_, WritevData(_, _, _, _, _))
         .WillByDefault(Invoke(MockQuicSession::ConsumeData));
   }
 
+  void Initialize() {
+    session_.Initialize();
+    send_control_stream_ = QuicSpdySessionPeer::GetSendControlStream(&session_);
+  }
+
   Perspective perspective() const { return GetParam().perspective; }
 
   MockQuicConnectionHelper helper_;
@@ -73,19 +78,68 @@
                          QuicSendControlStreamTest,
                          ::testing::ValuesIn(GetTestParams()));
 
-TEST_P(QuicSendControlStreamTest, WriteSettingsOnlyForOnce) {
+TEST_P(QuicSendControlStreamTest, WriteSettings) {
   if (GetParam().version.handshake_protocol == PROTOCOL_TLS1_3) {
     // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
     // enabled and fix it.
     return;
   }
+
+  session_.set_qpack_maximum_dynamic_table_capacity(255);
+  session_.set_max_inbound_header_list_size(1024);
+
+  Initialize();
   testing::InSequence s;
 
-  EXPECT_CALL(session_, WritevData(_, _, 1, _, _));
-  EXPECT_CALL(session_, WritevData(_, _, _, _, _));
+  std::string expected_write_data = QuicTextUtils::HexDecode(
+      "00"      // stream type: control stream
+      "04"      // frame type: SETTINGS frame
+      "06"      // frame length
+      "01"      // SETTINGS_QPACK_MAX_TABLE_CAPACITY
+      "40ff"    // 255
+      "06"      // SETTINGS_MAX_HEADER_LIST_SIZE
+      "4400");  // 1024
+
+  auto buffer = QuicMakeUnique<char[]>(expected_write_data.size());
+  QuicDataWriter writer(expected_write_data.size(), buffer.get());
+
+  // A lambda to save and consume stream data when QuicSession::WritevData() is
+  // called.
+  auto save_write_data = [&writer](QuicStream* stream, QuicStreamId /*id*/,
+                                   size_t write_length, QuicStreamOffset offset,
+                                   StreamSendingState /*state*/) {
+    stream->WriteStreamData(offset, write_length, &writer);
+    return QuicConsumedData(/* bytes_consumed = */ write_length,
+                            /* fin_consumed = */ false);
+  };
+
+  EXPECT_CALL(session_, WritevData(send_control_stream_, _, 1, _, _))
+      .WillOnce(Invoke(save_write_data));
+  EXPECT_CALL(session_, WritevData(send_control_stream_, _,
+                                   expected_write_data.size() - 1, _, _))
+      .WillOnce(Invoke(save_write_data));
+
+  send_control_stream_->MaybeSendSettingsFrame();
+  EXPECT_EQ(expected_write_data,
+            QuicStringPiece(writer.data(), writer.length()));
+}
+
+TEST_P(QuicSendControlStreamTest, WriteSettingsOnlyOnce) {
+  if (GetParam().version.handshake_protocol == PROTOCOL_TLS1_3) {
+    // TODO(nharper, b/112643533): Figure out why this test fails when TLS is
+    // enabled and fix it.
+    return;
+  }
+
+  Initialize();
+  testing::InSequence s;
+
+  EXPECT_CALL(session_, WritevData(send_control_stream_, _, 1, _, _));
+  EXPECT_CALL(session_, WritevData(send_control_stream_, _, _, _, _));
   send_control_stream_->MaybeSendSettingsFrame();
 
-  // No data should be written the sencond time SendSettingsFrame() is called.
+  // No data should be written the sencond time MaybeSendSettingsFrame() is
+  // called.
   send_control_stream_->MaybeSendSettingsFrame();
 }
 
@@ -96,20 +150,21 @@
     return;
   }
 
+  Initialize();
   testing::InSequence s;
 
   // The first write will trigger the control stream to write stream type and a
   // Settings frame before the Priority frame.
-  EXPECT_CALL(session_, WritevData(_, send_control_stream_->id(), _, _, _))
-      .Times(3);
+  EXPECT_CALL(session_, WritevData(send_control_stream_, _, _, _, _)).Times(3);
   PriorityFrame frame;
   send_control_stream_->WritePriority(frame);
 
-  EXPECT_CALL(session_, WritevData(_, send_control_stream_->id(), _, _, _));
+  EXPECT_CALL(session_, WritevData(send_control_stream_, _, _, _, _));
   send_control_stream_->WritePriority(frame);
 }
 
 TEST_P(QuicSendControlStreamTest, ResetControlStream) {
+  Initialize();
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId,
                                send_control_stream_->id(),
                                QUIC_STREAM_CANCELLED, 1234);
@@ -118,6 +173,7 @@
 }
 
 TEST_P(QuicSendControlStreamTest, ReceiveDataOnSendControlStream) {
+  Initialize();
   QuicStreamFrame frame(send_control_stream_->id(), false, 0, "test");
   EXPECT_CALL(
       *connection_,
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 73f63bb..719b3dc 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -391,9 +391,8 @@
         QuicMakeUnique<QpackDecoder>(qpack_maximum_dynamic_table_capacity_,
                                      qpack_maximum_blocked_streams_, this);
     MaybeInitializeHttp3UnidirectionalStreams();
-    // TODO(b/112770235): Send SETTINGS_QPACK_MAX_TABLE_CAPACITY with value
-    // qpack_maximum_dynamic_table_capacity_, and SETTINGS_QPACK_BLOCKED_STREAMS
-    // with value qpack_maximum_blocked_streams_.
+    // TODO(b/112770235): Send SETTINGS_QPACK_BLOCKED_STREAMS with value
+    // qpack_maximum_blocked_streams_.
   }
 
   spdy_framer_visitor_->set_max_header_list_size(max_inbound_header_list_size_);
@@ -973,7 +972,7 @@
   if (!send_control_stream_ && CanOpenNextOutgoingUnidirectionalStream()) {
     auto send_control = QuicMakeUnique<QuicSendControlStream>(
         GetNextOutgoingUnidirectionalStreamId(), this,
-        max_inbound_header_list_size_);
+        qpack_maximum_dynamic_table_capacity_, max_inbound_header_list_size_);
     send_control_stream_ = send_control.get();
     RegisterStaticStream(std::move(send_control));
   }