Send correct STOP_SENDING/RESET_STREAM frames for different stream types.

Upon receiving RESET_STREAM for a write-only stream, the connection will be closed with error.

gfe-relnote: protected by disabled v99 flag.
PiperOrigin-RevId: 279850700
Change-Id: I9f0e6215a388dac226d430458a340e8934432662
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc
index 205f7ad..3ec2401 100644
--- a/quic/core/quic_session.cc
+++ b/quic/core/quic_session.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "net/third_party/quiche/src/quic/core/quic_connection.h"
+#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
 #include "net/third_party/quiche/src/quic/core/quic_flow_controller.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -263,6 +264,8 @@
     return;
   }
 
+  stream->OnStopSending(frame.application_error_code);
+
   stream->set_stream_error(
       static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
   SendRstStreamInner(
@@ -302,6 +305,16 @@
     return;
   }
 
+  if (VersionHasIetfQuicFrames(transport_version()) &&
+      QuicUtils::GetStreamType(stream_id, perspective(),
+                               IsIncomingStream(stream_id)) ==
+          WRITE_UNIDIRECTIONAL) {
+    connection()->CloseConnection(
+        QUIC_INVALID_STREAM_ID, "Received RESET_STREAM for a write-only stream",
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return;
+  }
+
   if (visitor_) {
     visitor_->OnRstStreamReceived(frame);
   }
@@ -690,21 +703,23 @@
                                      bool close_write_side_only) {
   if (connection()->connected()) {
     // Only send if still connected.
-    if (close_write_side_only) {
-      DCHECK(VersionHasIetfQuicFrames(transport_version()));
-      // Send a RST_STREAM frame.
-      control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
-    } else {
+    if (VersionHasIetfQuicFrames(transport_version())) {
       // Send a RST_STREAM frame plus, if version 99, an IETF
       // QUIC STOP_SENDING frame. Both sre sent to emulate
       // the two-way close that Google QUIC's RST_STREAM does.
-      if (VersionHasIetfQuicFrames(transport_version())) {
-        QuicConnection::ScopedPacketFlusher flusher(connection());
-        control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
-        control_frame_manager_.WriteOrBufferStopSending(error, id);
-      } else {
+      QuicConnection::ScopedPacketFlusher flusher(connection());
+      if (QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) !=
+          READ_UNIDIRECTIONAL) {
         control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
       }
+      if (!close_write_side_only &&
+          QuicUtils::GetStreamType(id, perspective(), IsIncomingStream(id)) !=
+              WRITE_UNIDIRECTIONAL) {
+        control_frame_manager_.WriteOrBufferStopSending(error, id);
+      }
+    } else {
+      DCHECK(!close_write_side_only);
+      control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
     }
     connection_->OnStreamReset(id, error);
   }