Use IETF application error codes for STOP_SENDING frames.

Add ietf_error_code member to QuicStopSendingFrame, and use
IetfResetStreamErrorCodeToRstStreamErrorCode() and
RstStreamErrorCodeToIetfResetStreamErrorCode() to convert to and from
QuicRstStreamErrorCode.  This closely mirrors behavior of QuicRstStreamFrame.

This is the reland of cl/330521460 with
EndToEndTests/EndToEndTest.ClientRstStats fixed.  See b/168041589 for flakiness
caused by original CL.  Locally verified that 100 runs pass both with and
without FLAGS_gfe2_reloadable_flag_quic_stop_sending_uses_ietf_error_code.

Protected by FLAGS_quic_reloadable_flag_quic_stop_sending_uses_application_error_code.

PiperOrigin-RevId: 331000553
Change-Id: Ie5ac10b4e75fe98858d1e79bd07c108525452caa
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index 2b84822..3177b0c 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -96,10 +96,14 @@
   EXPECT_EQ(1u, GetControlFrameId(frame));
   stop_sending.stream_id = 321;
   stop_sending.error_code = QUIC_STREAM_CANCELLED;
+  stop_sending.ietf_error_code =
+      static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED);
   std::ostringstream stream;
   stream << stop_sending;
-  EXPECT_EQ("{ control_frame_id: 1, stream_id: 321, error_code: 6 }\n",
-            stream.str());
+  EXPECT_EQ(
+      "{ control_frame_id: 1, stream_id: 321, error_code: 6, ietf_error_code: "
+      "268 }\n",
+      stream.str());
   EXPECT_TRUE(IsControlFrame(frame.type));
 }
 
diff --git a/quic/core/frames/quic_stop_sending_frame.cc b/quic/core/frames/quic_stop_sending_frame.cc
index d3c1cdd..0a8d546 100644
--- a/quic/core/frames/quic_stop_sending_frame.cc
+++ b/quic/core/frames/quic_stop_sending_frame.cc
@@ -11,12 +11,17 @@
                                            QuicRstStreamErrorCode error_code)
     : control_frame_id(control_frame_id),
       stream_id(stream_id),
-      error_code(error_code) {}
+      error_code(error_code),
+      ietf_error_code(
+          GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)
+              ? RstStreamErrorCodeToIetfResetStreamErrorCode(error_code)
+              : error_code) {}
 
 std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) {
   os << "{ control_frame_id: " << frame.control_frame_id
      << ", stream_id: " << frame.stream_id
-     << ", error_code: " << frame.error_code << " }\n";
+     << ", error_code: " << frame.error_code
+     << ", ietf_error_code: " << frame.ietf_error_code << " }\n";
   return os;
 }
 
diff --git a/quic/core/frames/quic_stop_sending_frame.h b/quic/core/frames/quic_stop_sending_frame.h
index f54ae0e..57114d7 100644
--- a/quic/core/frames/quic_stop_sending_frame.h
+++ b/quic/core/frames/quic_stop_sending_frame.h
@@ -28,8 +28,13 @@
   QuicControlFrameId control_frame_id = kInvalidControlFrameId;
   QuicStreamId stream_id = 0;
 
-  // QuicRstStreamErrorCode associated with the frame.
+  // For an outgoing frame, the error code generated by the application that
+  // determines |ietf_error_code| to be sent on the wire; for an incoming frame,
+  // the error code inferred from |ietf_error_code| received on the wire.
   QuicRstStreamErrorCode error_code = QUIC_STREAM_NO_ERROR;
+
+  // On-the-wire application error code of the frame.
+  uint64_t ietf_error_code = 0;
 };
 
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 82bfab6..77a5a00 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -1308,9 +1308,13 @@
       return true;
     }
     default:
-      SendStopSending(static_cast<QuicRstStreamErrorCode>(
-                          QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
-                      pending->id());
+      if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+        SendStopSending(QUIC_STREAM_STREAM_CREATION_ERROR, pending->id());
+      } else {
+        SendStopSending(static_cast<QuicRstStreamErrorCode>(
+                            QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+                        pending->id());
+      }
       pending->StopReading();
   }
   return false;
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 6012638..accb2a0 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -2278,8 +2278,15 @@
 
           QuicStopSendingFrame* stop_sending = frame.stop_sending_frame;
           EXPECT_EQ(stream_id, stop_sending->stream_id);
-          EXPECT_EQ(QuicHttp3ErrorCode::STREAM_CREATION_ERROR,
-                    static_cast<QuicHttp3ErrorCode>(stop_sending->error_code));
+          EXPECT_EQ(
+              GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)
+                  ? QUIC_STREAM_STREAM_CREATION_ERROR
+                  : static_cast<QuicRstStreamErrorCode>(
+                        QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+              stop_sending->error_code);
+          EXPECT_EQ(
+              static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR),
+              stop_sending->ietf_error_code);
 
           return ClearControlFrame(frame);
         }));
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 6be7633..b30e564 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -1476,7 +1476,8 @@
   }
 
   QUIC_DLOG(INFO) << ENDPOINT << "STOP_SENDING frame received for stream: "
-                  << frame.stream_id << " with error: " << frame.error_code;
+                  << frame.stream_id
+                  << " with error: " << frame.ietf_error_code;
 
   visitor_->OnStopSendingFrame(frame);
   return connected_;
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index 5bfccb2..07ea943 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -621,7 +621,7 @@
 // static
 size_t QuicFramer::GetStopSendingFrameSize(const QuicStopSendingFrame& frame) {
   return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.stream_id) +
-         QuicDataWriter::GetVarInt62Len(frame.error_code);
+         QuicDataWriter::GetVarInt62Len(frame.ietf_error_code);
 }
 
 // static
@@ -5907,20 +5907,27 @@
     return false;
   }
 
-  uint64_t error_code;
-  if (!reader->ReadVarInt62(&error_code)) {
+  if (!reader->ReadVarInt62(&stop_sending_frame->ietf_error_code)) {
     set_detailed_error("Unable to read stop sending application error code.");
     return false;
   }
+
+  if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+    stop_sending_frame->error_code =
+        IetfResetStreamErrorCodeToRstStreamErrorCode(
+            stop_sending_frame->ietf_error_code);
+    return true;
+  }
+
   // TODO(fkastenholz): when error codes go to uint64_t, remove this.
-  if (error_code > 0xffff) {
+  if (stop_sending_frame->ietf_error_code > 0xffff) {
     stop_sending_frame->error_code =
         static_cast<QuicRstStreamErrorCode>(0xffff);
-    QUIC_DLOG(ERROR) << "Stop sending error code (" << error_code
-                     << ") > 0xffff";
+    QUIC_DLOG(ERROR) << "Stop sending error code ("
+                     << stop_sending_frame->ietf_error_code << ") > 0xffff";
   } else {
-    stop_sending_frame->error_code =
-        static_cast<QuicRstStreamErrorCode>(error_code);
+    stop_sending_frame->error_code = static_cast<QuicRstStreamErrorCode>(
+        stop_sending_frame->ietf_error_code);
   }
   return true;
 }
@@ -5933,7 +5940,7 @@
     return false;
   }
   if (!writer->WriteVarInt62(
-          static_cast<uint64_t>(stop_sending_frame.error_code))) {
+          static_cast<uint64_t>(stop_sending_frame.ietf_error_code))) {
     set_detailed_error("Can not write application error code");
     return false;
   }
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index b67eaf3..46cfe61 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -10977,7 +10977,14 @@
       PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID));
 
   EXPECT_EQ(kStreamId, visitor_.stop_sending_frame_.stream_id);
-  EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.error_code);
+  if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) {
+    EXPECT_EQ(QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE,
+              visitor_.stop_sending_frame_.error_code);
+  } else {
+    EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.error_code);
+  }
+  EXPECT_EQ(static_cast<uint64_t>(0x7654),
+            visitor_.stop_sending_frame_.ietf_error_code);
 
   CheckFramingBoundaries(packet99, QUIC_INVALID_STOP_SENDING_FRAME_DATA);
 }
@@ -10996,7 +11003,9 @@
 
   QuicStopSendingFrame frame;
   frame.stream_id = kStreamId;
-  frame.error_code = static_cast<QuicRstStreamErrorCode>(0xffff);
+  frame.error_code = QUIC_STREAM_ENCODER_STREAM_ERROR;
+  frame.ietf_error_code =
+      static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR);
   QuicFrames frames = {QuicFrame(&frame)};
 
   // clang-format off
@@ -11013,7 +11022,7 @@
     // Stream ID
     kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04,
     // Application error code
-    kVarInt62FourBytes + 0x00, 0x00, 0xff, 0xff
+    kVarInt62TwoBytes + 0x02, 0x01,
   };
   // clang-format on