Add text outputter for IETF stream types

Adds an overloaded << operator to pretty-print IETF stream types.

gfe-relnote: N/A just for debug/logging, IETF QUIC/V99 only.
PiperOrigin-RevId: 263749354
Change-Id: Ifdc257910bdfe066842948d8090636e7f31991fe
diff --git a/quic/core/frames/quic_connection_close_frame.cc b/quic/core/frames/quic_connection_close_frame.cc
index d436499..3e37073 100644
--- a/quic/core/frames/quic_connection_close_frame.cc
+++ b/quic/core/frames/quic_connection_close_frame.cc
@@ -6,6 +6,8 @@
 
 #include <memory>
 
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
 namespace quic {
 
 QuicConnectionCloseFrame::QuicConnectionCloseFrame()
@@ -49,21 +51,28 @@
     std::ostream& os,
     const QuicConnectionCloseFrame& connection_close_frame) {
   os << "{ Close type: " << connection_close_frame.close_type
-     << ", error_code: "
-     << ((connection_close_frame.close_type ==
-          IETF_QUIC_TRANSPORT_CONNECTION_CLOSE)
-             ? static_cast<uint16_t>(
-                   connection_close_frame.transport_error_code)
-             : ((connection_close_frame.close_type ==
-                 IETF_QUIC_APPLICATION_CONNECTION_CLOSE)
-                    ? connection_close_frame.application_error_code
-                    : static_cast<uint16_t>(
-                          connection_close_frame.quic_error_code)))
-     << ", extracted_error_code: "
-     << connection_close_frame.extracted_error_code << ", error_details: '"
-     << connection_close_frame.error_details
-     << "', frame_type: " << connection_close_frame.transport_close_frame_type
-     << "}\n";
+     << ", error_code: ";
+  switch (connection_close_frame.close_type) {
+    case IETF_QUIC_TRANSPORT_CONNECTION_CLOSE:
+      os << connection_close_frame.transport_error_code;
+      break;
+    case IETF_QUIC_APPLICATION_CONNECTION_CLOSE:
+      os << connection_close_frame.application_error_code;
+      break;
+    case GOOGLE_QUIC_CONNECTION_CLOSE:
+      os << connection_close_frame.quic_error_code;
+      break;
+  }
+  os << ", extracted_error_code: "
+     << QuicErrorCodeToString(connection_close_frame.extracted_error_code)
+     << ", error_details: '" << connection_close_frame.error_details << "'";
+  if (connection_close_frame.close_type ==
+      IETF_QUIC_TRANSPORT_CONNECTION_CLOSE) {
+    os << ", frame_type: "
+       << static_cast<QuicIetfFrameType>(
+              connection_close_frame.transport_close_frame_type);
+  }
+  os << "}\n";
   return os;
 }
 
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc
index 3467c78..b1030ee 100644
--- a/quic/core/frames/quic_frames_test.cc
+++ b/quic/core/frames/quic_frames_test.cc
@@ -148,10 +148,31 @@
   // underlying frame.
   EXPECT_EQ(
       "{ Close type: GOOGLE_QUIC_CONNECTION_CLOSE, error_code: 25, "
-      "extracted_error_code: 122, "
+      "extracted_error_code: QUIC_IETF_GQUIC_ERROR_MISSING, "
+      "error_details: 'No recent "
+      "network activity.'"
+      "}\n",
+      stream.str());
+  QuicFrame quic_frame(&frame);
+  EXPECT_FALSE(IsControlFrame(quic_frame.type));
+}
+
+TEST_F(QuicFramesTest, TransportConnectionCloseFrameToString) {
+  QuicConnectionCloseFrame frame;
+  frame.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE;
+  frame.transport_error_code = FINAL_SIZE_ERROR;
+  frame.extracted_error_code = QUIC_NETWORK_IDLE_TIMEOUT;
+  frame.error_details = "No recent network activity.";
+  frame.transport_close_frame_type = IETF_STREAM;
+  std::ostringstream stream;
+  stream << frame;
+  EXPECT_EQ(
+      "{ Close type: IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, error_code: "
+      "FINAL_SIZE_ERROR, "
+      "extracted_error_code: QUIC_NETWORK_IDLE_TIMEOUT, "
       "error_details: 'No recent "
       "network activity.', "
-      "frame_type: 0"
+      "frame_type: IETF_STREAM"
       "}\n",
       stream.str());
   QuicFrame quic_frame(&frame);
diff --git a/quic/core/quic_types.cc b/quic/core/quic_types.cc
index 38572f1..2fe951b 100644
--- a/quic/core/quic_types.cc
+++ b/quic/core/quic_types.cc
@@ -4,6 +4,8 @@
 
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+
 namespace quic {
 
 QuicConsumedData::QuicConsumedData(size_t bytes_consumed, bool fin_consumed)
@@ -75,52 +77,35 @@
 MessageResult::MessageResult(MessageStatus status, QuicMessageId message_id)
     : status(status), message_id(message_id) {}
 
-std::ostream& operator<<(std::ostream& os,
-                         const QuicIetfTransportErrorCodes& c) {
+#define RETURN_STRING_LITERAL(x) \
+  case x:                        \
+    return #x;
+
+std::string QuicIetfTransportErrorCodeString(QuicIetfTransportErrorCodes c) {
   if (static_cast<uint16_t>(c) >= 0xff00u) {
-    os << "Private value: " << c;
-    return os;
+    return QuicStrCat("Private value: ", c);
   }
 
   switch (c) {
-    case NO_IETF_QUIC_ERROR:
-      os << "NO_IETF_QUIC_ERROR";
-      break;
-    case INTERNAL_ERROR:
-      os << "INTERNAL_ERROR";
-      break;
-    case SERVER_BUSY_ERROR:
-      os << "SERVER_BUSY_ERROR";
-      break;
-    case FLOW_CONTROL_ERROR:
-      os << "FLOW_CONTROL_ERROR";
-      break;
-    case STREAM_LIMIT_ERROR:
-      os << "STREAM_LIMIT_ERROR";
-      break;
-    case STREAM_STATE_ERROR:
-      os << "STREAM_STATE_ERROR";
-      break;
-    case FINAL_SIZE_ERROR:
-      os << "FINAL_SIZE_ERROR";
-      break;
-    case FRAME_ENCODING_ERROR:
-      os << "FRAME_ENCODING_ERROR";
-      break;
-    case TRANSPORT_PARAMETER_ERROR:
-      os << "TRANSPORT_PARAMETER_ERROR";
-      break;
-    case VERSION_NEGOTIATION_ERROR:
-      os << "VERSION_NEGOTIATION_ERROR";
-      break;
-    case PROTOCOL_VIOLATION:
-      os << "PROTOCOL_VIOLATION";
-      break;
-    case INVALID_MIGRATION:
-      os << "INVALID_MIGRATION";
-      break;
-      // No default -- compiler will catch any adds/changes then.
+    RETURN_STRING_LITERAL(NO_IETF_QUIC_ERROR);
+    RETURN_STRING_LITERAL(INTERNAL_ERROR);
+    RETURN_STRING_LITERAL(SERVER_BUSY_ERROR);
+    RETURN_STRING_LITERAL(FLOW_CONTROL_ERROR);
+    RETURN_STRING_LITERAL(STREAM_LIMIT_ERROR);
+    RETURN_STRING_LITERAL(STREAM_STATE_ERROR);
+    RETURN_STRING_LITERAL(FINAL_SIZE_ERROR);
+    RETURN_STRING_LITERAL(FRAME_ENCODING_ERROR);
+    RETURN_STRING_LITERAL(TRANSPORT_PARAMETER_ERROR);
+    RETURN_STRING_LITERAL(VERSION_NEGOTIATION_ERROR);
+    RETURN_STRING_LITERAL(PROTOCOL_VIOLATION);
+    RETURN_STRING_LITERAL(INVALID_MIGRATION);
+    // No default -- compiler will catch any adds/changes then.
   }
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         const QuicIetfTransportErrorCodes& c) {
+  os << QuicIetfTransportErrorCodeString(c);
   return os;
 }
 
@@ -429,4 +414,43 @@
   return {false, {NO_IETF_QUIC_ERROR}};
 }
 
+std::string QuicIetfFrameTypeString(QuicIetfFrameType t) {
+  if (IS_IETF_STREAM_FRAME(t)) {
+    return "IETF_STREAM";
+  }
+
+  switch (t) {
+    RETURN_STRING_LITERAL(IETF_PADDING);
+    RETURN_STRING_LITERAL(IETF_PING);
+    RETURN_STRING_LITERAL(IETF_ACK);
+    RETURN_STRING_LITERAL(IETF_ACK_ECN);
+    RETURN_STRING_LITERAL(IETF_RST_STREAM);
+    RETURN_STRING_LITERAL(IETF_STOP_SENDING);
+    RETURN_STRING_LITERAL(IETF_CRYPTO);
+    RETURN_STRING_LITERAL(IETF_NEW_TOKEN);
+    RETURN_STRING_LITERAL(IETF_MAX_DATA);
+    RETURN_STRING_LITERAL(IETF_MAX_STREAM_DATA);
+    RETURN_STRING_LITERAL(IETF_MAX_STREAMS_BIDIRECTIONAL);
+    RETURN_STRING_LITERAL(IETF_MAX_STREAMS_UNIDIRECTIONAL);
+    RETURN_STRING_LITERAL(IETF_BLOCKED);
+    RETURN_STRING_LITERAL(IETF_STREAM_BLOCKED);
+    RETURN_STRING_LITERAL(IETF_STREAMS_BLOCKED_BIDIRECTIONAL);
+    RETURN_STRING_LITERAL(IETF_STREAMS_BLOCKED_UNIDIRECTIONAL);
+    RETURN_STRING_LITERAL(IETF_NEW_CONNECTION_ID);
+    RETURN_STRING_LITERAL(IETF_RETIRE_CONNECTION_ID);
+    RETURN_STRING_LITERAL(IETF_PATH_CHALLENGE);
+    RETURN_STRING_LITERAL(IETF_PATH_RESPONSE);
+    RETURN_STRING_LITERAL(IETF_CONNECTION_CLOSE);
+    RETURN_STRING_LITERAL(IETF_APPLICATION_CLOSE);
+    RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE_NO_LENGTH);
+    RETURN_STRING_LITERAL(IETF_EXTENSION_MESSAGE);
+    default:
+      return QuicStrCat("Private value (", t, ")");
+  }
+}
+std::ostream& operator<<(std::ostream& os, const QuicIetfFrameType& c) {
+  os << QuicIetfFrameTypeString(c);
+  return os;
+}
+
 }  // namespace quic
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h
index 8a5434e..524d5ec 100644
--- a/quic/core/quic_types.h
+++ b/quic/core/quic_types.h
@@ -267,6 +267,10 @@
   IETF_EXTENSION_MESSAGE_NO_LENGTH = 0x20,
   IETF_EXTENSION_MESSAGE = 0x21,
 };
+QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
+                                             const QuicIetfFrameType& c);
+QUIC_EXPORT_PRIVATE std::string QuicIetfFrameTypeString(QuicIetfFrameType t);
+
 // Masks for the bits that indicate the frame is a Stream frame vs the
 // bits used as flags.
 #define IETF_STREAM_FRAME_TYPE_MASK 0xfffffffffffffff8
@@ -519,6 +523,9 @@
   PROTOCOL_VIOLATION = 0xA,
   INVALID_MIGRATION = 0xC,
 };
+QUIC_EXPORT_PRIVATE std::string QuicIetfTransportErrorCodeString(
+    QuicIetfTransportErrorCodes c);
+
 QUIC_EXPORT_PRIVATE std::ostream& operator<<(
     std::ostream& os,
     const QuicIetfTransportErrorCodes& c);