Simplify QuicStreamSendBuffer::SaveStreamData().

This method is called at two places in production:
QuicCryptoStream::WriteCryptoData() and QuicStream::WriteOrBufferDataAtLevel(),
both times with an iovec created locally from an absl::string_view.  In order to
reduce complexity, this CL changes SaveStreamData() to take an absl::string_view
directly instead of an iovec.
PiperOrigin-RevId: 432178898
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 311cf1f..a629827 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -341,14 +341,12 @@
   }
 
   QuicConsumedData SendStreamData(QuicStream* stream) {
-    struct iovec iov;
     if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(),
                                      stream->id()) &&
         connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
       this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
     }
-    MakeIOVector("not empty", &iov);
-    QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
+    QuicStreamPeer::SendBuffer(stream).SaveStreamData("not empty");
     QuicConsumedData consumed =
         WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION,
                    GetEncryptionLevelToSendApplicationData());
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index fc4df23..84f0bce 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -230,16 +230,15 @@
   }
 
   QuicConsumedData SaveAndSendStreamData(QuicStreamId id,
-                                         const struct iovec* iov, int iov_count,
-                                         size_t total_length,
+                                         absl::string_view data,
                                          QuicStreamOffset offset,
                                          StreamSendingState state) {
     ScopedPacketFlusher flusher(this);
-    producer_.SaveStreamData(id, iov, iov_count, 0u, total_length);
+    producer_.SaveStreamData(id, data);
     if (notifier_ != nullptr) {
-      return notifier_->WriteOrBufferData(id, total_length, state);
+      return notifier_->WriteOrBufferData(id, data.length(), state);
     }
-    return QuicConnection::SendStreamData(id, total_length, offset, state);
+    return QuicConnection::SendStreamData(id, data.length(), offset, state);
   }
 
   QuicConsumedData SendStreamDataWithString(QuicStreamId id,
@@ -257,9 +256,7 @@
         QuicConnectionPeer::SetAddressValidated(this);
       }
     }
-    struct iovec iov;
-    MakeIOVector(data, &iov);
-    return SaveAndSendStreamData(id, &iov, 1, data.length(), offset, state);
+    return SaveAndSendStreamData(id, data, offset, state);
   }
 
   QuicConsumedData SendApplicationDataAtLevel(EncryptionLevel encryption_level,
@@ -271,9 +268,7 @@
     QUICHE_DCHECK(encryption_level >= ENCRYPTION_ZERO_RTT);
     SetEncrypter(encryption_level, std::make_unique<TaggingEncrypter>(0x01));
     SetDefaultEncryptionLevel(encryption_level);
-    struct iovec iov;
-    MakeIOVector(data, &iov);
-    return SaveAndSendStreamData(id, &iov, 1, data.length(), offset, state);
+    return SaveAndSendStreamData(id, data, offset, state);
   }
 
   QuicConsumedData SendStreamData3() {
@@ -3707,19 +3702,11 @@
 
 TEST_P(QuicConnectionTest, FramePackingSendv) {
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
-  // Send data in 1 packet by writing multiple blocks in a single iovector
-  // using writev.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
 
-  char data[] = "ABCDEF";
-  struct iovec iov[2];
-  iov[0].iov_base = data;
-  iov[0].iov_len = 4;
-  iov[1].iov_base = data + 4;
-  iov[1].iov_len = 2;
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       connection_.transport_version(), Perspective::IS_CLIENT);
-  connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN);
+  connection_.SaveAndSendStreamData(stream_id, "ABCDEF", 0, NO_FIN);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -3737,19 +3724,12 @@
 
 TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
-  // Try to send two stream frames in 1 packet by using writev.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
 
   BlockOnNextWrite();
-  char data[] = "ABCDEF";
-  struct iovec iov[2];
-  iov[0].iov_base = data;
-  iov[0].iov_len = 4;
-  iov[1].iov_base = data + 4;
-  iov[1].iov_len = 2;
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       connection_.transport_version(), Perspective::IS_CLIENT);
-  connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN);
+  connection_.SaveAndSendStreamData(stream_id, "ABCDEF", 0, NO_FIN);
 
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
   EXPECT_TRUE(connection_.HasQueuedData());
@@ -3763,7 +3743,10 @@
   EXPECT_EQ(1u, writer_->frame_count());
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_EQ(0u, writer_->padding_frames().size());
-  EXPECT_EQ(stream_id, writer_->stream_frames()[0]->stream_id);
+  QuicStreamFrame* frame = writer_->stream_frames()[0].get();
+  EXPECT_EQ(stream_id, frame->stream_id);
+  EXPECT_EQ("ABCDEF",
+            absl::string_view(frame->data_buffer, frame->data_length));
 }
 
 TEST_P(QuicConnectionTest, SendingZeroBytes) {
@@ -3772,7 +3755,7 @@
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       connection_.transport_version(), Perspective::IS_CLIENT);
-  connection_.SaveAndSendStreamData(stream_id, nullptr, 0, 0, 0, FIN);
+  connection_.SaveAndSendStreamData(stream_id, {}, 0, FIN);
 
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -3805,16 +3788,11 @@
 
   // Send data and ensure the ack is bundled.
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(9);
-  size_t len = 10000;
-  std::unique_ptr<char[]> data_array(new char[len]);
-  memset(data_array.get(), '?', len);
-  struct iovec iov;
-  iov.iov_base = data_array.get();
-  iov.iov_len = len;
+  const std::string data(10000, '?');
   QuicConsumedData consumed = connection_.SaveAndSendStreamData(
-      GetNthClientInitiatedStreamId(0, connection_.transport_version()), &iov,
-      1, len, 0, FIN);
-  EXPECT_EQ(len, consumed.bytes_consumed);
+      GetNthClientInitiatedStreamId(0, connection_.transport_version()), data,
+      0, FIN);
+  EXPECT_EQ(data.length(), consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_EQ(0u, connection_.NumQueuedPackets());
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -7409,9 +7387,7 @@
 
   EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
       .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
-  struct iovec iov;
-  MakeIOVector("", &iov);
-  EXPECT_QUIC_BUG(connection_.SaveAndSendStreamData(3, &iov, 1, 0, 0, FIN),
+  EXPECT_QUIC_BUG(connection_.SaveAndSendStreamData(3, {}, 0, FIN),
                   "Cannot send stream data with level: ENCRYPTION_INITIAL");
   EXPECT_FALSE(connection_.connected());
   EXPECT_EQ(1, connection_close_frame_count_);
@@ -12292,11 +12268,8 @@
       .WillOnce(Invoke([=](const QuicStreamFrame& frame) {
         // Send some data on the stream. The STREAM_FRAME should be built into
         // one packet together with the latter PATH_RESPONSE and PATH_CHALLENGE.
-        std::string data{"response body"};
-        struct iovec iov;
-        MakeIOVector(data, &iov);
-        connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
-                                               data.length());
+        const std::string data{"response body"};
+        connection_.producer()->SaveStreamData(frame.stream_id, data);
         return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
                                            NO_FIN);
       }));
@@ -12365,11 +12338,8 @@
       .WillOnce(Invoke([=](const QuicStreamFrame& frame) {
         // Send some data on the stream. The STREAM_FRAME should be built into a
         // new packet but throttled by anti-amplifciation limit.
-        std::string data{"response body"};
-        struct iovec iov;
-        MakeIOVector(data, &iov);
-        connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
-                                               data.length());
+        const std::string data{"response body"};
+        connection_.producer()->SaveStreamData(frame.stream_id, data);
         return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
                                            NO_FIN);
       }));
@@ -12409,11 +12379,8 @@
       .WillRepeatedly(Invoke([=](const QuicStreamFrame& frame) {
         // Send some data on the stream. The STREAM_FRAME should be built into
         // one packet together with the latter PATH_RESPONSE.
-        std::string data{"response body"};
-        struct iovec iov;
-        MakeIOVector(data, &iov);
-        connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
-                                               data.length());
+        const std::string data{"response body"};
+        connection_.producer()->SaveStreamData(frame.stream_id, data);
         return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
                                            NO_FIN);
       }));
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index b579ff5..5690743 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -140,11 +140,9 @@
   }
   const bool had_buffered_data = HasBufferedCryptoFrames();
   // Append |data| to the send buffer for this encryption level.
-  struct iovec iov(QuicUtils::MakeIovec(data));
   QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
   QuicStreamOffset offset = send_buffer->stream_offset();
-  send_buffer->SaveStreamData(&iov, /*iov_count=*/1, /*iov_offset=*/0,
-                              data.length());
+  send_buffer->SaveStreamData(data);
   if (kMaxStreamLength - offset < data.length()) {
     QUIC_BUG(quic_bug_10322_2) << "Writing too much crypto handshake data";
     // TODO(nharper): Switch this to an IETF QUIC error code, possibly
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index 3b56f82..f038e33 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -104,24 +104,18 @@
         producer_(producer),
         version_(framer->version()) {}
 
-  bool ConsumeDataToFillCurrentPacket(QuicStreamId id,
-                                      const struct iovec* iov,
-                                      int iov_count,
-                                      size_t total_length,
-                                      size_t iov_offset,
-                                      QuicStreamOffset offset,
-                                      bool fin,
+  bool ConsumeDataToFillCurrentPacket(QuicStreamId id, absl::string_view data,
+                                      QuicStreamOffset offset, bool fin,
                                       bool needs_full_padding,
                                       TransmissionType transmission_type,
                                       QuicFrame* frame) {
     // Save data before data is consumed.
-    QuicByteCount data_length = total_length - iov_offset;
-    if (data_length > 0) {
-      producer_->SaveStreamData(id, iov, iov_count, iov_offset, data_length);
+    if (!data.empty()) {
+      producer_->SaveStreamData(id, data);
     }
     return QuicPacketCreator::ConsumeDataToFillCurrentPacket(
-        id, data_length - iov_offset, offset, fin, needs_full_padding,
-        transmission_type, frame);
+        id, data.length(), offset, fin, needs_full_padding, transmission_type,
+        frame);
   }
 
   void StopSendingVersion() {
@@ -283,7 +277,6 @@
   StrictMock<MockFramerVisitor> framer_visitor_;
   StrictMock<MockPacketCreatorDelegate> delegate_;
   std::string data_;
-  struct iovec iov_;
   TestPacketCreator creator_;
   std::unique_ptr<SerializedPacket> serialized_packet_;
   SimpleDataProducer producer_;
@@ -384,12 +377,11 @@
 TEST_P(QuicPacketCreatorTest, ConsumeDataToFillCurrentPacket) {
   creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
   QuicFrame frame;
-  MakeIOVector("test", &iov_);
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
+  const std::string data("test");
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id, data, 0u, false, false, NOT_RETRANSMISSION, &frame));
   size_t consumed = frame.stream_frame.data_length;
   EXPECT_EQ(4u, consumed);
   CheckStreamFrame(frame, stream_id, "test", 0u, false);
@@ -399,12 +391,11 @@
 TEST_P(QuicPacketCreatorTest, ConsumeDataFin) {
   creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
   QuicFrame frame;
-  MakeIOVector("test", &iov_);
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
+  const std::string data("test");
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, true, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id, data, 0u, true, false, NOT_RETRANSMISSION, &frame));
   size_t consumed = frame.stream_frame.data_length;
   EXPECT_EQ(4u, consumed);
   CheckStreamFrame(frame, stream_id, "test", 0u, true);
@@ -417,8 +408,7 @@
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, nullptr, 0u, 0u, 0u, 0u, true, false, NOT_RETRANSMISSION,
-      &frame));
+      stream_id, {}, 0u, true, false, NOT_RETRANSMISSION, &frame));
   size_t consumed = frame.stream_frame.data_length;
   EXPECT_EQ(0u, consumed);
   CheckStreamFrame(frame, stream_id, std::string(), 0u, true);
@@ -445,13 +435,13 @@
                                              kOffset, /* data_size=*/0xffff));
     if (should_have_room) {
       QuicFrame frame;
-      MakeIOVector("testdata", &iov_);
+      const std::string data("testdata");
       EXPECT_CALL(delegate_, OnSerializedPacket(_))
           .WillRepeatedly(Invoke(
               this, &QuicPacketCreatorTest::ClearSerializedPacketForTests));
       ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-          GetNthClientInitiatedStreamId(1), &iov_, 1u, iov_.iov_len, 0u,
-          kOffset, false, false, NOT_RETRANSMISSION, &frame));
+          GetNthClientInitiatedStreamId(1), data, kOffset, false, false,
+          NOT_RETRANSMISSION, &frame));
       size_t bytes_consumed = frame.stream_frame.data_length;
       EXPECT_LT(0u, bytes_consumed);
       creator_.FlushCurrentPacket();
@@ -472,10 +462,9 @@
     std::string data(capacity + delta, 'A');
     size_t bytes_free = delta > 0 ? 0 : 0 - delta;
     QuicFrame frame;
-    MakeIOVector(data, &iov_);
     ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-        GetNthClientInitiatedStreamId(1), &iov_, 1u, iov_.iov_len, 0u, kOffset,
-        false, false, NOT_RETRANSMISSION, &frame));
+        GetNthClientInitiatedStreamId(1), data, kOffset, false, false,
+        NOT_RETRANSMISSION, &frame));
 
     // BytesFree() returns bytes available for the next frame, which will
     // be two bytes smaller since the stream frame would need to be grown.
@@ -513,7 +502,6 @@
     size_t bytes_free = delta > 0 ? 0 : 0 - delta;
 
     QuicFrame frame;
-    MakeIOVector(data, &iov_);
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillRepeatedly(
             Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
@@ -524,8 +512,7 @@
     if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
       ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
           QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
-          &iov_, 1u, iov_.iov_len, 0u, kOffset, false, true, NOT_RETRANSMISSION,
-          &frame));
+          data, kOffset, false, true, NOT_RETRANSMISSION, &frame));
       size_t bytes_consumed = frame.stream_frame.data_length;
       EXPECT_LT(0u, bytes_consumed);
     } else {
@@ -569,12 +556,11 @@
     size_t bytes_free = delta > 0 ? 0 : 0 - delta;
 
     QuicFrame frame;
-    MakeIOVector(data, &iov_);
     EXPECT_CALL(delegate_, OnSerializedPacket(_))
         .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
     ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-        GetNthClientInitiatedStreamId(1), &iov_, 1u, iov_.iov_len, 0u, kOffset,
-        false, false, NOT_RETRANSMISSION, &frame));
+        GetNthClientInitiatedStreamId(1), data, kOffset, false, false,
+        NOT_RETRANSMISSION, &frame));
     size_t bytes_consumed = frame.stream_frame.data_length;
     EXPECT_LT(0u, bytes_consumed);
     creator_.FlushCurrentPacket();
@@ -1398,14 +1384,13 @@
   QuicFrame frame;
   size_t payload_length = creator_.max_packet_length();
   const std::string too_long_payload(payload_length, 'a');
-  MakeIOVector(too_long_payload, &iov_);
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, true, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id, too_long_payload, 0u, true, false, NOT_RETRANSMISSION,
+      &frame));
   size_t consumed = frame.stream_frame.data_length;
   // The entire payload could not be consumed.
   EXPECT_GT(payload_length, consumed);
@@ -1450,11 +1435,10 @@
   EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id));
 
   QuicFrame frame;
-  MakeIOVector("test", &iov_);
+  const std::string data("test");
   EXPECT_CALL(debug, OnFrameAddedToPacket(_));
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id, data, 0u, false, false, NOT_RETRANSMISSION, &frame));
   size_t consumed = frame.stream_frame.data_length;
   EXPECT_EQ(4u, consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -1504,9 +1488,8 @@
   }
   EXPECT_FALSE(creator_.HasPendingFrames());
 
-  MakeIOVector("test", &iov_);
-  producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), &iov_, 1u, 0u,
-                           iov_.iov_len);
+  const std::string data("test");
+  producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), data);
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
   size_t num_bytes_consumed;
@@ -1514,7 +1497,7 @@
   creator_.set_debug_delegate(&debug);
   EXPECT_CALL(debug, OnFrameAddedToPacket(_));
   creator_.CreateAndSerializeStreamFrame(
-      GetNthClientInitiatedStreamId(0), iov_.iov_len, 0, 0, true,
+      GetNthClientInitiatedStreamId(0), data.length(), 0, 0, true,
       NOT_RETRANSMISSION, &num_bytes_consumed);
   EXPECT_EQ(4u, num_bytes_consumed);
 
@@ -1541,14 +1524,13 @@
   EXPECT_FALSE(creator_.HasPendingFrames());
 
   // Send one byte of stream data.
-  MakeIOVector("a", &iov_);
-  producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), &iov_, 1u, 0u,
-                           iov_.iov_len);
+  const std::string data("a");
+  producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), data);
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
   size_t num_bytes_consumed;
   creator_.CreateAndSerializeStreamFrame(
-      GetNthClientInitiatedStreamId(0), iov_.iov_len, 0, 0, true,
+      GetNthClientInitiatedStreamId(0), data.length(), 0, 0, true,
       NOT_RETRANSMISSION, &num_bytes_consumed);
   EXPECT_EQ(1u, num_bytes_consumed);
 
@@ -1621,16 +1603,13 @@
   std::unique_ptr<QuicData> message_data;
   message_data = framer.ConstructHandshakeMessage(message);
 
-  struct iovec iov;
-  MakeIOVector(absl::string_view(message_data->data(), message_data->length()),
-               &iov);
   QuicFrame frame;
   EXPECT_CALL(delegate_, OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, _));
   EXPECT_QUIC_BUG(
       creator_.ConsumeDataToFillCurrentPacket(
           QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
-          &iov, 1u, iov.iov_len, 0u, 0u, false, false, NOT_RETRANSMISSION,
-          &frame),
+          absl::string_view(message_data->data(), message_data->length()), 0u,
+          false, false, NOT_RETRANSMISSION, &frame),
       "Client hello won't fit in a single packet.");
 }
 
@@ -1665,11 +1644,11 @@
   creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
   creator_.AddPendingPadding(kMaxNumRandomPaddingBytes);
   QuicFrame frame;
-  MakeIOVector("test", &iov_);
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
+  const std::string data("test");
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false,
+      stream_id, data, 0u, false,
       /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
@@ -1700,18 +1679,16 @@
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
   // Send stream frame of size kStreamFramePayloadSize.
-  MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
-  creator_.ConsumeDataToFillCurrentPacket(stream_id, &iov_, 1u, iov_.iov_len,
-                                          0u, 0u, false, false,
-                                          NOT_RETRANSMISSION, &frame);
+  creator_.ConsumeDataToFillCurrentPacket(
+      stream_id, absl::string_view(buf, kStreamFramePayloadSize), 0u, false,
+      false, NOT_RETRANSMISSION, &frame);
   creator_.FlushCurrentPacket();
   // 1 byte padding is sent.
   EXPECT_EQ(pending_padding_bytes - 1, creator_.pending_padding_bytes());
   // Send stream frame of size kStreamFramePayloadSize + 1.
-  MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize + 1), &iov_);
-  creator_.ConsumeDataToFillCurrentPacket(stream_id, &iov_, 1u, iov_.iov_len,
-                                          0u, kStreamFramePayloadSize, false,
-                                          false, NOT_RETRANSMISSION, &frame);
+  creator_.ConsumeDataToFillCurrentPacket(
+      stream_id, absl::string_view(buf, kStreamFramePayloadSize + 1),
+      kStreamFramePayloadSize, false, false, NOT_RETRANSMISSION, &frame);
   // No padding is sent.
   creator_.FlushCurrentPacket();
   EXPECT_EQ(pending_padding_bytes - 1, creator_.pending_padding_bytes());
@@ -1730,11 +1707,11 @@
   EXPECT_CALL(delegate_, GetPacketBuffer()).WillOnce(Return(external_buffer));
 
   QuicFrame frame;
-  MakeIOVector("test", &iov_);
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
+  const std::string data("test");
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false,
+      stream_id, data, 0u, false,
       /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
 
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -1792,12 +1769,11 @@
   creator_.FlushCurrentPacket();
 
   QuicFrame frame;
-  MakeIOVector("test", &iov_);
   QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
       client_framer_.transport_version(), Perspective::IS_CLIENT);
+  const std::string data("test");
   EXPECT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id, data, 0u, false, false, NOT_RETRANSMISSION, &frame));
   QuicMessageFrame* frame4 =
       new QuicMessageFrame(4, MemSliceFromString("message"));
   EXPECT_TRUE(creator_.AddFrame(QuicFrame(frame4), NOT_RETRANSMISSION));
@@ -2062,43 +2038,38 @@
   StrictMock<MockDebugDelegate> debug;
   creator_.set_debug_delegate(&debug);
 
-  MakeIOVector("test", &iov_);
   QuicFrame frame;
+  const std::string data1("test");
   EXPECT_CALL(debug, OnFrameAddedToPacket(_));
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id1, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id1, data1, 0u, false, false, NOT_RETRANSMISSION, &frame));
   EXPECT_TRUE(creator_.HasPendingFrames());
   EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id1));
 
-  MakeIOVector("coalesce", &iov_);
+  const std::string data2("coalesce");
   // frame will be coalesced with the first frame.
   const auto previous_size = creator_.PacketSize();
-  QuicStreamFrame target(stream_id1, true, 0, 12);
+  QuicStreamFrame target(stream_id1, true, 0, data1.length() + data2.length());
   EXPECT_CALL(debug, OnStreamFrameCoalesced(target));
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id1, &iov_, 1u, iov_.iov_len, 0u, 4u, true, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id1, data2, 4u, true, false, NOT_RETRANSMISSION, &frame));
   EXPECT_EQ(frame.stream_frame.data_length,
             creator_.PacketSize() - previous_size);
 
   // frame is for another stream, so it won't be coalesced.
   const auto length = creator_.BytesFree() - 10u;
-  std::string large_data(length, 'x');
-  MakeIOVector(large_data, &iov_);
+  const std::string data3(length, 'x');
   EXPECT_CALL(debug, OnFrameAddedToPacket(_));
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id2, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id2, data3, 0u, false, false, NOT_RETRANSMISSION, &frame));
   EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id2));
 
   // The packet doesn't have enough free bytes for all data, but will still be
   // able to consume and coalesce part of them.
   EXPECT_CALL(debug, OnStreamFrameCoalesced(_));
-  MakeIOVector("somerandomdata", &iov_);
+  const std::string data4("somerandomdata");
   ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-      stream_id2, &iov_, 1u, iov_.iov_len, 0u, length, false, false,
-      NOT_RETRANSMISSION, &frame));
+      stream_id2, data4, length, false, false, NOT_RETRANSMISSION, &frame));
 
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
@@ -2254,14 +2225,12 @@
   // restored.
   creator_.SetSoftMaxPacketLength(overhead);
   EXPECT_EQ(overhead, creator_.max_packet_length());
-  std::string data = "crypto data";
-  MakeIOVector(data, &iov_);
+  const std::string data = "crypto data";
   QuicFrame frame;
   if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
     ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
-        QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
-        1u, iov_.iov_len, 0u, kOffset, false, true, NOT_RETRANSMISSION,
-        &frame));
+        QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), data,
+        kOffset, false, true, NOT_RETRANSMISSION, &frame));
     size_t bytes_consumed = frame.stream_frame.data_length;
     EXPECT_LT(0u, bytes_consumed);
   } else {
@@ -2417,34 +2386,28 @@
   }
 
   QuicConsumedData ConsumeDataFastPath(QuicStreamId id,
-                                       const struct iovec* iov,
-                                       int iov_count,
-                                       size_t total_length,
-                                       QuicStreamOffset offset,
-                                       bool fin) {
+                                       absl::string_view data) {
     // Save data before data is consumed.
-    if (total_length > 0) {
-      producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
+    if (!data.empty()) {
+      producer_->SaveStreamData(id, data);
     }
-    return QuicPacketCreator::ConsumeDataFastPath(id, total_length, offset, fin,
-                                                  0);
+    return QuicPacketCreator::ConsumeDataFastPath(id, data.length(),
+                                                  /* offset = */ 0,
+                                                  /* fin = */ true, 0);
   }
 
-  QuicConsumedData ConsumeData(QuicStreamId id,
-                               const struct iovec* iov,
-                               int iov_count,
-                               size_t total_length,
+  QuicConsumedData ConsumeData(QuicStreamId id, absl::string_view data,
                                QuicStreamOffset offset,
                                StreamSendingState state) {
     // Save data before data is consumed.
-    if (total_length > 0) {
-      producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
+    if (!data.empty()) {
+      producer_->SaveStreamData(id, data);
     }
     if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
                                                       NOT_HANDSHAKE)) {
       EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1);
     }
-    return QuicPacketCreator::ConsumeData(id, total_length, offset, state);
+    return QuicPacketCreator::ConsumeData(id, data.length(), offset, state);
   }
 
   MessageStatus AddMessageFrame(QuicMessageId message_id,
@@ -2591,13 +2554,6 @@
     }
   }
 
-  void CreateData(size_t len) {
-    data_array_.reset(new char[len]);
-    memset(data_array_.get(), '?', len);
-    iov_.iov_base = data_array_.get();
-    iov_.iov_len = len;
-  }
-
   QuicFramer framer_;
   MockRandom random_creator_;
   StrictMock<MockDelegate> delegate_;
@@ -2630,14 +2586,13 @@
        WrongEncryptionLevelForStreamDataFastPath) {
   creator_.set_encryption_level(ENCRYPTION_HANDSHAKE);
   delegate_.SetCanWriteAnything();
-  // Create a 10000 byte IOVector.
-  CreateData(10000);
+  const std::string data(10000, '?');
   EXPECT_CALL(delegate_, OnSerializedPacket(_)).Times(0);
   EXPECT_CALL(delegate_, OnUnrecoverableError(_, _));
   EXPECT_QUIC_BUG(creator_.ConsumeDataFastPath(
                       QuicUtils::GetFirstBidirectionalStreamId(
                           framer_.transport_version(), Perspective::IS_CLIENT),
-                      &iov_, 1u, iov_.iov_len, 0, true),
+                      data),
                   "");
 }
 
@@ -2734,11 +2689,10 @@
 TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_NotWritable) {
   delegate_.SetCanNotWrite();
 
-  MakeIOVector("foo", &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, FIN);
+      "foo", 0, FIN);
   EXPECT_EQ(0u, consumed.bytes_consumed);
   EXPECT_FALSE(consumed.fin_consumed);
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -2749,11 +2703,10 @@
        ConsumeData_WritableAndShouldNotFlush) {
   delegate_.SetCanWriteAnything();
 
-  MakeIOVector("foo", &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, FIN);
+      "foo", 0, FIN);
   EXPECT_EQ(3u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2767,11 +2720,10 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  MakeIOVector("foo", &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, FIN);
+      "foo", 0, FIN);
   creator_.Flush();
   EXPECT_EQ(3u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
@@ -2792,8 +2744,7 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  std::string data = "foo bar";
-  MakeIOVector(data, &iov_);
+  const std::string data = "foo bar";
   size_t consumed_bytes = 0;
   if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
     consumed_bytes = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
@@ -2801,8 +2752,8 @@
     consumed_bytes =
         creator_
             .ConsumeData(
-                QuicUtils::GetCryptoStreamId(framer_.transport_version()),
-                &iov_, 1u, iov_.iov_len, 0, NO_FIN)
+                QuicUtils::GetCryptoStreamId(framer_.transport_version()), data,
+                0, NO_FIN)
             .bytes_consumed;
   }
   EXPECT_EQ(7u, consumed_bytes);
@@ -2834,8 +2785,7 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  std::string data = "foo";
-  MakeIOVector(data, &iov_);
+  const std::string data = "foo";
   size_t bytes_consumed = 0;
   if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
     bytes_consumed = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
@@ -2843,8 +2793,8 @@
     bytes_consumed =
         creator_
             .ConsumeData(
-                QuicUtils::GetCryptoStreamId(framer_.transport_version()),
-                &iov_, 1u, iov_.iov_len, 0, NO_FIN)
+                QuicUtils::GetCryptoStreamId(framer_.transport_version()), data,
+                0, NO_FIN)
             .bytes_consumed;
   }
   EXPECT_EQ(3u, bytes_consumed);
@@ -2882,7 +2832,7 @@
   EXPECT_QUIC_BUG(creator_.ConsumeData(
                       QuicUtils::QuicUtils::GetFirstBidirectionalStreamId(
                           framer_.transport_version(), Perspective::IS_CLIENT),
-                      nullptr, 0, 0, 0, NO_FIN),
+                      {}, 0, NO_FIN),
                   "Attempt to consume empty data without FIN.");
 }
 
@@ -2890,13 +2840,10 @@
        ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
   delegate_.SetCanWriteAnything();
 
-  MakeIOVector("foo", &iov_);
   creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
                            framer_.transport_version(), Perspective::IS_CLIENT),
-                       &iov_, 1u, iov_.iov_len, 0, FIN);
-  MakeIOVector("quux", &iov_);
-  QuicConsumedData consumed =
-      creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN);
+                       "foo", 0, FIN);
+  QuicConsumedData consumed = creator_.ConsumeData(3, "quux", 3, NO_FIN);
   EXPECT_EQ(4u, consumed.bytes_consumed);
   EXPECT_FALSE(consumed.fin_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2906,15 +2853,13 @@
 TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_BatchOperations) {
   delegate_.SetCanWriteAnything();
 
-  MakeIOVector("foo", &iov_);
   creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
                            framer_.transport_version(), Perspective::IS_CLIENT),
-                       &iov_, 1u, iov_.iov_len, 0, NO_FIN);
-  MakeIOVector("quux", &iov_);
+                       "foo", 0, NO_FIN);
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 3, FIN);
+      "quux", 3, FIN);
   EXPECT_EQ(4u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2969,11 +2914,10 @@
   }
   // Queue enough data to prevent a stream frame with a non-zero offset from
   // fitting.
-  MakeIOVector("foo", &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+      "foo", 0, NO_FIN);
   EXPECT_EQ(3u, consumed.bytes_consumed);
   EXPECT_FALSE(consumed.fin_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2981,11 +2925,10 @@
 
   // This frame will not fit with the existing frame, causing the queued frame
   // to be serialized, and it will be added to a new open packet.
-  MakeIOVector("bar", &iov_);
   consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 3, FIN);
+      "bar", 3, FIN);
   EXPECT_EQ(3u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -3005,15 +2948,14 @@
   delegate_.SetCanWriteAnything();
   creator_.SetTransmissionType(LOSS_RETRANSMISSION);
 
-  // Create a 10000 byte IOVector.
-  CreateData(10000);
+  const std::string data(10000, '?');
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
   QuicConsumedData consumed = creator_.ConsumeDataFastPath(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, true);
+      data);
   EXPECT_EQ(10000u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3035,15 +2977,14 @@
 TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLarge) {
   delegate_.SetCanWriteAnything();
 
-  // Create a 10000 byte IOVector.
-  CreateData(10000);
+  const std::string data(10000, '?');
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, FIN);
+      data, 0, FIN);
   EXPECT_EQ(10000u, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3077,8 +3018,7 @@
   creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
                                               /*bundle_ack=*/false);
 
-  // Create a 10000 byte IOVector.
-  CreateData(10000);
+  const std::string data(10000, '?');
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
@@ -3087,7 +3027,7 @@
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, FIN);
+      data, 0, FIN);
   creator_.Flush();
 
   EXPECT_EQ(10000u, consumed.bytes_consumed);
@@ -3108,15 +3048,14 @@
   delegate_.SetCanNotWrite();
   delegate_.SetCanWriteAnything();
 
-  // Create a 10000 byte IOVector.
-  CreateData(10000);
+  const std::string data(10000, '?');
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, FIN);
+      data, 0, FIN);
   creator_.Flush();
 
   EXPECT_EQ(10000u, consumed.bytes_consumed);
@@ -3151,8 +3090,7 @@
       creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
                                                   /*bundle_ack=*/false));
   // Send some data and a control frame
-  MakeIOVector("quux", &iov_);
-  creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+  creator_.ConsumeData(3, "quux", 0, NO_FIN);
   if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
     creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateGoAwayFrame()),
                                                 /*bundle_ack=*/false);
@@ -3209,9 +3147,8 @@
                                                   /*bundle_ack=*/false));
   // Send enough data to exceed one packet
   size_t data_len = kDefaultMaxPacketSize + 100;
-  CreateData(data_len);
-  QuicConsumedData consumed =
-      creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, FIN);
+  const std::string data(data_len, '?');
+  QuicConsumedData consumed = creator_.ConsumeData(3, data, 0, FIN);
   EXPECT_EQ(data_len, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
   if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
@@ -3250,11 +3187,10 @@
   creator_.SetTransmissionType(LOSS_RETRANSMISSION);
 
   size_t data_len = 1224;
-  CreateData(data_len);
+  const std::string data(data_len, '?');
   QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId(
       framer_.transport_version(), Perspective::IS_CLIENT);
-  QuicConsumedData consumed =
-      creator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+  QuicConsumedData consumed = creator_.ConsumeData(stream1_id, data, 0, NO_FIN);
   EXPECT_EQ(data_len, consumed.bytes_consumed);
   ASSERT_EQ(0u, creator_.BytesFree())
       << "Test setup failed: Please increase data_len to "
@@ -3269,8 +3205,7 @@
 
   QuicStreamId stream2_id = stream1_id + 4;
 
-  consumed =
-      creator_.ConsumeData(stream2_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+  consumed = creator_.ConsumeData(stream2_id, data, 0, NO_FIN);
   EXPECT_EQ(data_len, consumed.bytes_consumed);
 
   // Ensure the packet is successfully created.
@@ -3319,11 +3254,11 @@
       .Times(3)
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  CreateData(data_len);
+  const std::string data(data_len, '?');
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len,
+      data,
       /*offset=*/0, FIN);
   EXPECT_EQ(data_len, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
@@ -3358,11 +3293,11 @@
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
 
   // Send two packets before packet size change.
-  CreateData(data_len);
+  const std::string data(data_len, '?');
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len,
+      data,
       /*offset=*/0, NO_FIN);
   creator_.Flush();
   EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -3378,12 +3313,11 @@
   EXPECT_EQ(packet_len, creator_.max_packet_length());
 
   // Send a packet after packet size change.
-  CreateData(data_len);
   creator_.AttachPacketFlusher();
   consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, data_len, FIN);
+      data, data_len, FIN);
   creator_.Flush();
   EXPECT_EQ(data_len, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
@@ -3411,11 +3345,11 @@
 
   // First send half of the packet worth of data.  We are in the batch mode, so
   // should not cause packet serialization.
-  CreateData(first_write_len);
+  const std::string first_write(first_write_len, '?');
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len,
+      first_write,
       /*offset=*/0, NO_FIN);
   EXPECT_EQ(first_write_len, consumed.bytes_consumed);
   EXPECT_FALSE(consumed.fin_consumed);
@@ -3447,11 +3381,11 @@
 
   // Send a more than a packet worth of data to the same stream.  This should
   // trigger serialization of one packet, and queue another one.
-  CreateData(second_write_len);
+  const std::string second_write(second_write_len, '?');
   consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len,
+      second_write,
       /*offset=*/first_write_len, FIN);
   EXPECT_EQ(second_write_len, consumed.bytes_consumed);
   EXPECT_TRUE(consumed.fin_consumed);
@@ -3541,11 +3475,11 @@
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
 
   // Send data before the MTU probe.
-  CreateData(data_len);
+  const std::string data(data_len, '?');
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len,
+      data,
       /*offset=*/0, NO_FIN);
   creator_.Flush();
   EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -3559,12 +3493,11 @@
   EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
 
   // Send data after the MTU probe.
-  CreateData(data_len);
   creator_.AttachPacketFlusher();
   consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len,
+      data,
       /*offset=*/data_len, FIN);
   creator_.Flush();
   EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -3655,9 +3588,9 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
-      kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
+      kDataStreamId, absl::string_view(buf, kStreamFramePayloadSize), 0,
+      FIN_AND_PADDING);
   creator_.Flush();
   EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3698,9 +3631,9 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
-      kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
+      kDataStreamId, absl::string_view(buf, kStreamFramePayloadSize), 0,
+      FIN_AND_PADDING);
   creator_.Flush();
   EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3753,13 +3686,13 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillRepeatedly(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
   QuicConsumedData consumed = creator_.ConsumeData(
-      kDataStreamId1, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
+      kDataStreamId1, absl::string_view(buf, kStreamFramePayloadSize), 0,
+      FIN_AND_PADDING);
   EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
-  MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
-  consumed = creator_.ConsumeData(kDataStreamId2, &iov_, 1u, iov_.iov_len, 0,
-                                  FIN_AND_PADDING);
+  consumed = creator_.ConsumeData(
+      kDataStreamId2, absl::string_view(buf, kStreamFramePayloadSize), 0,
+      FIN_AND_PADDING);
   EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
   creator_.Flush();
   EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3796,10 +3729,9 @@
       .WillOnce(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
 
-  MakeIOVector("foo", &iov_);
   creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
                            framer_.transport_version(), Perspective::IS_CLIENT),
-                       &iov_, 1u, iov_.iov_len, 0, FIN);
+                       "foo", 0, FIN);
   EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
             creator_.AddMessageFrame(1, MemSliceFromString("message")));
   EXPECT_TRUE(creator_.HasPendingFrames());
@@ -3841,10 +3773,9 @@
   EXPECT_CALL(delegate_, OnSerializedPacket(_))
       .WillOnce(
           Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
-  MakeIOVector("a", &iov_);
   creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
                            framer_.transport_version(), Perspective::IS_CLIENT),
-                       &iov_, 1u, iov_.iov_len, 0, FIN);
+                       "a", 0, FIN);
   creator_.Flush();
   ASSERT_FALSE(packets_[0].nonretransmittable_frames.empty());
   QuicFrame padding = packets_[0].nonretransmittable_frames[0];
@@ -3861,13 +3792,12 @@
   creator_.SetClientConnectionId(client_connection_id);
   creator_.SetServerConnectionId(server_connection_id);
   // Send some stream data.
-  MakeIOVector("foo", &iov_);
   EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
       .WillRepeatedly(Return(true));
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+      "foo", 0, NO_FIN);
   EXPECT_EQ(3u, consumed.bytes_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
   {
@@ -3882,7 +3812,7 @@
     QuicConsumedData consumed = creator_.ConsumeData(
         QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
                                                  Perspective::IS_CLIENT),
-        &iov_, 1u, iov_.iov_len, 0, FIN);
+        "foo", 0, FIN);
     EXPECT_EQ(3u, consumed.bytes_consumed);
   }
   // After exiting the scope, the last queued frame should be flushed.
@@ -3902,13 +3832,12 @@
   QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
   creator_.SetDefaultPeerAddress(peer_addr);
   // Send some stream data.
-  MakeIOVector("foo", &iov_);
   EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
       .WillRepeatedly(Return(true));
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+      "foo", 0, NO_FIN);
   EXPECT_EQ(3u, consumed.bytes_consumed);
 
   QuicSocketAddress peer_addr1(QuicIpAddress::Any4(), 12346);
@@ -3938,7 +3867,7 @@
     QuicConsumedData consumed = creator_.ConsumeData(
         QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
                                                  Perspective::IS_CLIENT),
-        &iov_, 1u, iov_.iov_len, 0, FIN);
+        "foo", 0, FIN);
     EXPECT_EQ(3u, consumed.bytes_consumed);
     EXPECT_TRUE(creator_.HasPendingFrames());
   }
@@ -3959,13 +3888,12 @@
   ASSERT_EQ(server_connection_id1, creator_.GetServerConnectionId());
 
   // Send some stream data.
-  MakeIOVector("foo", &iov_);
   EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
       .WillRepeatedly(Return(true));
   QuicConsumedData consumed = creator_.ConsumeData(
       QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
                                                Perspective::IS_CLIENT),
-      &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+      "foo", 0, NO_FIN);
   EXPECT_EQ(3u, consumed.bytes_consumed);
   EXPECT_TRUE(creator_.HasPendingFrames());
 
@@ -3984,13 +3912,12 @@
             /*update_connection_id=*/true);
         ASSERT_EQ(client_connection_id2, creator_.GetClientConnectionId());
         ASSERT_EQ(server_connection_id2, creator_.GetServerConnectionId());
-        MakeIOVector("foo", &iov_);
         EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
             .WillRepeatedly(Return(true));
         QuicConsumedData consumed = creator_.ConsumeData(
             QuicUtils::GetFirstBidirectionalStreamId(
                 creator_.transport_version(), Perspective::IS_CLIENT),
-            &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+            "foo", 0, NO_FIN);
         EXPECT_EQ(3u, consumed.bytes_consumed);
         EXPECT_TRUE(creator_.HasPendingFrames());
         // This should trigger another OnSerializedPacket() with the 2nd
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 68ae9f9..4d5eed5 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -352,14 +352,12 @@
   }
 
   QuicConsumedData SendStreamData(QuicStream* stream) {
-    struct iovec iov;
     if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(),
                                      stream->id()) &&
         this->connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
       this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
     }
-    MakeIOVector("not empty", &iov);
-    QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
+    QuicStreamPeer::SendBuffer(stream).SaveStreamData("not empty");
     QuicConsumedData consumed =
         WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION,
                    GetEncryptionLevelToSendApplicationData());
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index f8e00b4..8737044 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -688,7 +688,6 @@
   // Do not respect buffered data upper limit as WriteOrBufferData guarantees
   // all data to be consumed.
   if (data.length() > 0) {
-    struct iovec iov(QuicUtils::MakeIovec(data));
     QuicStreamOffset offset = send_buffer_.stream_offset();
     if (kMaxStreamLength - offset < data.length()) {
       QUIC_BUG(quic_bug_10586_4) << "Write too many data via stream " << id_;
@@ -697,7 +696,7 @@
           absl::StrCat("Write too many data via stream ", id_));
       return;
     }
-    send_buffer_.SaveStreamData(&iov, 1, 0, data.length());
+    send_buffer_.SaveStreamData(data);
     OnDataBuffered(offset, data.length(), ack_listener);
   }
   if (!had_buffered_data && (HasBufferedData() || fin_buffered_)) {
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc
index aa58ead..6017768 100644
--- a/quic/core/quic_stream_send_buffer.cc
+++ b/quic/core/quic_stream_send_buffer.cc
@@ -58,22 +58,19 @@
 
 QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
 
-void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov,
-                                          int iov_count,
-                                          size_t iov_offset,
-                                          QuicByteCount data_length) {
-  QUICHE_DCHECK_LT(0u, data_length);
+void QuicStreamSendBuffer::SaveStreamData(absl::string_view data) {
+  QUICHE_DCHECK(!data.empty());
+
   // Latch the maximum data slice size.
   const QuicByteCount max_data_slice_size =
       GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
-  while (data_length > 0) {
-    size_t slice_len = std::min(data_length, max_data_slice_size);
-    quiche::QuicheBuffer buffer(allocator_, slice_len);
-    QuicUtils::CopyToBuffer(iov, iov_count, iov_offset, slice_len,
-                            buffer.data());
+  while (!data.empty()) {
+    size_t slice_len = std::min(data.length(), max_data_slice_size);
+    auto buffer =
+        quiche::QuicheBuffer::Copy(allocator_, data.substr(0, slice_len));
     SaveMemSlice(quiche::QuicheMemSlice(std::move(buffer)));
-    data_length -= slice_len;
-    iov_offset += slice_len;
+
+    data = data.substr(slice_len);
   }
 }
 
diff --git a/quic/core/quic_stream_send_buffer.h b/quic/core/quic_stream_send_buffer.h
index 6fe7b75..cf3fa13 100644
--- a/quic/core/quic_stream_send_buffer.h
+++ b/quic/core/quic_stream_send_buffer.h
@@ -69,11 +69,8 @@
   QuicStreamSendBuffer(QuicStreamSendBuffer&& other) = delete;
   ~QuicStreamSendBuffer();
 
-  // Save |data_length| of data starts at |iov_offset| in |iov| to send buffer.
-  void SaveStreamData(const struct iovec* iov,
-                      int iov_count,
-                      size_t iov_offset,
-                      QuicByteCount data_length);
+  // Save |data| to send buffer.
+  void SaveStreamData(absl::string_view data);
 
   // Save |slice| to send buffer.
   void SaveMemSlice(quiche::QuicheMemSlice slice);
diff --git a/quic/core/quic_stream_send_buffer_test.cc b/quic/core/quic_stream_send_buffer_test.cc
index 2e0f9dc..599ebf4 100644
--- a/quic/core/quic_stream_send_buffer_test.cc
+++ b/quic/core/quic_stream_send_buffer_test.cc
@@ -20,46 +20,41 @@
 namespace test {
 namespace {
 
-struct iovec MakeIovec(absl::string_view data) {
-  struct iovec iov = {const_cast<char*>(data.data()),
-                      static_cast<size_t>(data.size())};
-  return iov;
-}
-
 class QuicStreamSendBufferTest : public QuicTest {
  public:
   QuicStreamSendBufferTest() : send_buffer_(&allocator_) {
     EXPECT_EQ(0u, send_buffer_.size());
     EXPECT_EQ(0u, send_buffer_.stream_bytes_written());
     EXPECT_EQ(0u, send_buffer_.stream_bytes_outstanding());
-    std::string data1(1536, 'a');
-    std::string data2 = std::string(256, 'b') + std::string(256, 'c');
-    struct iovec iov[2];
-    iov[0] = MakeIovec(absl::string_view(data1));
-    iov[1] = MakeIovec(absl::string_view(data2));
+    // The stream offset should be 0 since nothing is written.
+    EXPECT_EQ(0u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_));
+
+    std::string data1 = absl::StrCat(
+        std::string(1536, 'a'), std::string(256, 'b'), std::string(256, 'c'));
 
     quiche::QuicheBuffer buffer1(&allocator_, 1024);
     memset(buffer1.data(), 'c', buffer1.size());
     quiche::QuicheMemSlice slice1(std::move(buffer1));
+
     quiche::QuicheBuffer buffer2(&allocator_, 768);
     memset(buffer2.data(), 'd', buffer2.size());
     quiche::QuicheMemSlice slice2(std::move(buffer2));
 
-    // The stream offset should be 0 since nothing is written.
-    EXPECT_EQ(0u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_));
-
-    // Save all data.
+    // `data` will be split into two BufferedSlices.
     SetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size, 1024);
-    send_buffer_.SaveStreamData(iov, 2, 0, 2048);
+    send_buffer_.SaveStreamData(data1);
+
     send_buffer_.SaveMemSlice(std::move(slice1));
     EXPECT_TRUE(slice1.empty());
     send_buffer_.SaveMemSlice(std::move(slice2));
     EXPECT_TRUE(slice2.empty());
 
     EXPECT_EQ(4u, send_buffer_.size());
-    // At this point, the whole buffer looks like:
-    // |      a * 1536      |b * 256|         c * 1280        |  d * 768  |
-    // |    slice1     |     slice2       |      slice3       |   slice4  |
+    // At this point, `send_buffer_.interval_deque_` looks like this:
+    // BufferedSlice1: 'a' * 1024
+    // BufferedSlice2: 'a' * 512 + 'b' * 256 + 'c' * 256
+    // BufferedSlice3: 'c' * 1024
+    // BufferedSlice4: 'd' * 768
   }
 
   void WriteAllData() {
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index caffd7f..aa8f59e 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -290,13 +290,6 @@
 }
 
 // static
-struct iovec QuicUtils::MakeIovec(absl::string_view data) {
-  struct iovec iov = {const_cast<char*>(data.data()),
-                      static_cast<size_t>(data.size())};
-  return iov;
-}
-
-// static
 bool QuicUtils::IsAckable(SentPacketState state) {
   return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
 }
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h
index 43e6470..085f532 100644
--- a/quic/core/quic_utils.h
+++ b/quic/core/quic_utils.h
@@ -81,9 +81,6 @@
                            size_t buffer_length,
                            char* buffer);
 
-  // Creates an iovec pointing to the same data as |data|.
-  static struct iovec MakeIovec(absl::string_view data);
-
   // Returns the opposite Perspective of the |perspective| passed in.
   static constexpr Perspective InvertPerspective(Perspective perspective) {
     return perspective == Perspective::IS_CLIENT ? Perspective::IS_SERVER
diff --git a/quic/test_tools/simple_data_producer.cc b/quic/test_tools/simple_data_producer.cc
index aaab1d1..64c0a2c 100644
--- a/quic/test_tools/simple_data_producer.cc
+++ b/quic/test_tools/simple_data_producer.cc
@@ -20,17 +20,14 @@
 SimpleDataProducer::~SimpleDataProducer() {}
 
 void SimpleDataProducer::SaveStreamData(QuicStreamId id,
-                                        const struct iovec* iov,
-                                        int iov_count,
-                                        size_t iov_offset,
-                                        QuicByteCount data_length) {
-  if (data_length == 0) {
+                                        absl::string_view data) {
+  if (data.empty()) {
     return;
   }
   if (!send_buffer_map_.contains(id)) {
     send_buffer_map_[id] = std::make_unique<QuicStreamSendBuffer>(&allocator_);
   }
-  send_buffer_map_[id]->SaveStreamData(iov, iov_count, iov_offset, data_length);
+  send_buffer_map_[id]->SaveStreamData(data);
 }
 
 void SimpleDataProducer::SaveCryptoData(EncryptionLevel level,
diff --git a/quic/test_tools/simple_data_producer.h b/quic/test_tools/simple_data_producer.h
index e8dd4e4..9564f86 100644
--- a/quic/test_tools/simple_data_producer.h
+++ b/quic/test_tools/simple_data_producer.h
@@ -23,17 +23,10 @@
   SimpleDataProducer();
   ~SimpleDataProducer() override;
 
-  // Saves data to be provided when WriteStreamData is called. Data of length
-  // |data_length| is buffered to be provided for stream |id|. Multiple calls to
-  // SaveStreamData for the same stream ID append to the buffer for that stream.
-  // The data to be buffered is provided in |iov_count| iovec structs, with
-  // |iov| pointing to the first, and |iov_offset| indicating how many bytes
-  // into the iovec structs the data starts.
-  void SaveStreamData(QuicStreamId id,
-                      const struct iovec* iov,
-                      int iov_count,
-                      size_t iov_offset,
-                      QuicByteCount data_length);
+  // Saves `data` to be provided when WriteStreamData() is called. Multiple
+  // calls to SaveStreamData() for the same stream ID append to the buffer for
+  // that stream.
+  void SaveStreamData(QuicStreamId id, absl::string_view data);
 
   void SaveCryptoData(EncryptionLevel level,
                       QuicStreamOffset offset,