Return false in QuicTransportStream::CanWrite() if the write side of the stream has been closed.

gfe-relnote: n/a (not used in production GFE code)
PiperOrigin-RevId: 288535167
Change-Id: I2ea667733f234937af671b5740c77944e5eef879
diff --git a/quic/quic_transport/quic_transport_stream.cc b/quic/quic_transport/quic_transport_stream.cc
index db90597..2852442 100644
--- a/quic/quic_transport/quic_transport_stream.cc
+++ b/quic/quic_transport/quic_transport_stream.cc
@@ -97,7 +97,8 @@
 }
 
 bool QuicTransportStream::CanWrite() const {
-  return session_interface_->IsSessionReady() && CanWriteNewData();
+  return session_interface_->IsSessionReady() && CanWriteNewData() &&
+         !write_side_closed();
 }
 
 size_t QuicTransportStream::ReadableBytes() const {
diff --git a/quic/quic_transport/quic_transport_stream_test.cc b/quic/quic_transport/quic_transport_stream_test.cc
index f4311ce..69d40f4 100644
--- a/quic/quic_transport/quic_transport_stream_test.cc
+++ b/quic/quic_transport/quic_transport_stream_test.cc
@@ -20,6 +20,7 @@
 namespace test {
 namespace {
 
+using testing::_;
 using testing::Return;
 
 ParsedQuicVersionVector GetVersions() {
@@ -136,6 +137,16 @@
   EXPECT_FALSE(stream_->Write(a_lot_of_data));
 }
 
+TEST_F(QuicTransportStreamTest, CannotSendFinTwice) {
+  EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
+  ASSERT_TRUE(stream_->CanWrite());
+
+  EXPECT_CALL(session_, WritevData(stream_, stream_->id(), _, _, _))
+      .WillOnce(Return(QuicConsumedData(0, /*fin_consumed=*/true)));
+  EXPECT_TRUE(stream_->SendFin());
+  EXPECT_FALSE(stream_->CanWrite());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic