Use WriteMemSlices() instead of WriteOrBufferData() in QuicTransportStream.

Originally, this was supposed to fix the fact that WriteOrBufferData() has unlimited buffering.  However, as I wrote a test for that, I discovered that I've already added a check for this by accident when I originally wrote this code.  I'm still switching this code to use WriteMemSlices() as it actually returns whether it has succeeded.

gfe-relnote: n/a (not used in production)
PiperOrigin-RevId: 288496889
Change-Id: I801c2f870dd04b9fa478e12452834ec38e20a870
diff --git a/quic/quic_transport/quic_transport_stream.cc b/quic/quic_transport/quic_transport_stream.cc
index ac54fa3..db90597 100644
--- a/quic/quic_transport/quic_transport_stream.cc
+++ b/quic/quic_transport/quic_transport_stream.cc
@@ -6,6 +6,8 @@
 
 #include <sys/types.h>
 
+#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
@@ -54,9 +56,32 @@
     return false;
   }
 
-  // TODO(vasilvv): use WriteMemSlices()
-  WriteOrBufferData(data, /*fin=*/false, nullptr);
-  return true;
+  QuicUniqueBufferPtr buffer = MakeUniqueBuffer(
+      session()->connection()->helper()->GetStreamSendBufferAllocator(),
+      data.size());
+  memcpy(buffer.get(), data.data(), data.size());
+  QuicMemSlice memslice(std::move(buffer), data.size());
+  QuicConsumedData consumed =
+      WriteMemSlices(QuicMemSliceSpan(&memslice), /*fin=*/false);
+
+  if (consumed.bytes_consumed == data.size()) {
+    return true;
+  }
+  if (consumed.bytes_consumed == 0) {
+    return false;
+  }
+  // QuicTransportStream::Write() is an all-or-nothing write API.  To achieve
+  // that property, it relies on WriteMemSlices() being an all-or-nothing API.
+  // If WriteMemSlices() fails to provide that guarantee, we have no way to
+  // communicate a partial write to the caller, and thus it's safer to just
+  // close the connection.
+  QUIC_BUG << "WriteMemSlices() unexpectedly partially consumed the input "
+              "data, provided: "
+           << data.size() << ", written: " << consumed.bytes_consumed;
+  CloseConnectionWithDetails(
+      QUIC_INTERNAL_ERROR,
+      "WriteMemSlices() unexpectedly partially consumed the input data");
+  return false;
 }
 
 bool QuicTransportStream::SendFin() {
@@ -64,8 +89,11 @@
     return false;
   }
 
-  WriteOrBufferData(quiche::QuicheStringPiece(), /*fin=*/true, nullptr);
-  return true;
+  QuicMemSlice empty;
+  QuicConsumedData consumed =
+      WriteMemSlices(QuicMemSliceSpan(&empty), /*fin=*/true);
+  DCHECK_EQ(consumed.bytes_consumed, 0u);
+  return consumed.fin_consumed;
 }
 
 bool QuicTransportStream::CanWrite() const {
diff --git a/quic/quic_transport/quic_transport_stream_test.cc b/quic/quic_transport/quic_transport_stream_test.cc
index eda6af6..f4311ce 100644
--- a/quic/quic_transport/quic_transport_stream_test.cc
+++ b/quic/quic_transport/quic_transport_stream_test.cc
@@ -120,6 +120,22 @@
   ASSERT_EQ(stream_->Read(&buffer), 4u);
 }
 
+TEST_F(QuicTransportStreamTest, WritingTooMuchData) {
+  EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
+  ASSERT_TRUE(stream_->CanWrite());
+
+  std::string a_little_bit_of_data(128, 'A');
+  std::string a_lot_of_data(GetQuicFlag(FLAGS_quic_buffered_data_threshold) * 2,
+                            'a');
+
+  EXPECT_TRUE(stream_->Write(a_little_bit_of_data));
+  EXPECT_TRUE(stream_->Write(a_little_bit_of_data));
+  EXPECT_TRUE(stream_->Write(a_little_bit_of_data));
+
+  EXPECT_TRUE(stream_->Write(a_lot_of_data));
+  EXPECT_FALSE(stream_->Write(a_lot_of_data));
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic