Add QuicSpdySession debug visitor to help with HTTP/3 debugging.

gfe-relnote: debugging only, not protected.
PiperOrigin-RevId: 269599486
Change-Id: Icc3a31fd46a42fa113e87b45d5fd28c78acd4fc0
diff --git a/quic/core/http/quic_receive_control_stream.cc b/quic/core/http/quic_receive_control_stream.cc
index 746efdb..d6794c7 100644
--- a/quic/core/http/quic_receive_control_stream.cc
+++ b/quic/core/http/quic_receive_control_stream.cc
@@ -214,6 +214,9 @@
   QUIC_DVLOG(1) << "Control Stream " << id()
                 << " received settings frame: " << settings;
   QuicSpdySession* spdy_session = static_cast<QuicSpdySession*>(session());
+  if (spdy_session->debug_visitor() != nullptr) {
+    spdy_session->debug_visitor()->OnSettingsFrame(settings);
+  }
   for (const auto& setting : settings.values) {
     spdy_session->OnSetting(setting.first, setting.second);
   }
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 8980fc2..17c2884 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -306,6 +306,10 @@
 
 QuicHpackDebugVisitor::~QuicHpackDebugVisitor() {}
 
+Http3DebugVisitor::Http3DebugVisitor() {}
+
+Http3DebugVisitor::~Http3DebugVisitor() {}
+
 QuicSpdySession::QuicSpdySession(
     QuicConnection* connection,
     QuicSession::Visitor* visitor,
@@ -339,7 +343,8 @@
       spdy_framer_(SpdyFramer::ENABLE_COMPRESSION),
       spdy_framer_visitor_(new SpdyFramerVisitor(this)),
       max_allowed_push_id_(0),
-      destruction_indicator_(123456789) {
+      destruction_indicator_(123456789),
+      debug_visitor_(nullptr) {
   h2_deframer_.set_visitor(spdy_framer_visitor_.get());
   h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get());
   spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
@@ -913,6 +918,10 @@
       ActivateStream(std::move(receive_stream));
       receive_control_stream_->SetUnblocked();
       QUIC_DVLOG(1) << "Receive Control stream is created";
+      if (debug_visitor_ != nullptr) {
+        debug_visitor_->OnPeerControlStreamCreated(
+            receive_control_stream_->id());
+      }
       return true;
     }
     case kServerPushStream: {  // Push Stream.
@@ -931,6 +940,10 @@
       ActivateStream(std::move(encoder_receive));
       qpack_encoder_receive_stream_->SetUnblocked();
       QUIC_DVLOG(1) << "Receive QPACK Encoder stream is created";
+      if (debug_visitor_ != nullptr) {
+        debug_visitor_->OnPeerQpackEncoderStreamCreated(
+            qpack_encoder_receive_stream_->id());
+      }
       return true;
     }
     case kQpackDecoderStream: {  // QPACK decoder stream.
@@ -943,7 +956,11 @@
       qpack_decoder_receive_stream_ = decoder_receive.get();
       ActivateStream(std::move(decoder_receive));
       qpack_decoder_receive_stream_->SetUnblocked();
-      QUIC_DVLOG(1) << "Receive Qpack Decoder stream is created";
+      QUIC_DVLOG(1) << "Receive QPACK Decoder stream is created";
+      if (debug_visitor_ != nullptr) {
+        debug_visitor_->OnPeerQpackDecoderStreamCreated(
+            qpack_decoder_receive_stream_->id());
+      }
       return true;
     }
     default:
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index faba099..40ad070 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -52,6 +52,27 @@
   virtual void OnUseEntry(QuicTime::Delta elapsed) = 0;
 };
 
+class QUIC_EXPORT_PRIVATE Http3DebugVisitor {
+ public:
+  Http3DebugVisitor();
+  Http3DebugVisitor(const Http3DebugVisitor&) = delete;
+  Http3DebugVisitor& operator=(const Http3DebugVisitor&) = delete;
+
+  virtual ~Http3DebugVisitor();
+
+  // Called when peer's control stream type is received.
+  virtual void OnPeerControlStreamCreated(QuicStreamId /*stream_id*/) = 0;
+
+  // Called when peer's QPACK encoder stream type is received.
+  virtual void OnPeerQpackEncoderStreamCreated(QuicStreamId /*stream_id*/) = 0;
+
+  // Called when peer's QPACK decoder stream type is received.
+  virtual void OnPeerQpackDecoderStreamCreated(QuicStreamId /*stream_id*/) = 0;
+
+  // Called when SETTINGS frame is received.
+  virtual void OnSettingsFrame(const SettingsFrame& /*frame*/) = 0;
+};
+
 // A QUIC session for HTTP.
 class QUIC_EXPORT_PRIVATE QuicSpdySession
     : public QuicSession,
@@ -209,6 +230,12 @@
 
   int32_t destruction_indicator() const { return destruction_indicator_; }
 
+  void set_debug_visitor(Http3DebugVisitor* debug_visitor) {
+    debug_visitor_ = debug_visitor;
+  }
+
+  Http3DebugVisitor* debug_visitor() { return debug_visitor_; }
+
  protected:
   // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
   // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -363,6 +390,9 @@
   // constructor. As long as it is not the assigned value, that would indicate
   // an use-after-free.
   int32_t destruction_indicator_;
+
+  // Not owned by the session.
+  Http3DebugVisitor* debug_visitor_;
 };
 
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 9311af5..310081c 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -127,6 +127,17 @@
   MOCK_METHOD0(OnCanWrite, void());
 };
 
+class MockHttp3DebugVisitor : public Http3DebugVisitor {
+ public:
+  MOCK_METHOD1(OnPeerControlStreamCreated, void(QuicStreamId));
+
+  MOCK_METHOD1(OnPeerQpackEncoderStreamCreated, void(QuicStreamId));
+
+  MOCK_METHOD1(OnPeerQpackDecoderStreamCreated, void(QuicStreamId));
+
+  MOCK_METHOD1(OnSettingsFrame, void(const SettingsFrame&));
+};
+
 class TestStream : public QuicSpdyStream {
  public:
   TestStream(QuicStreamId id, QuicSpdySession* session, StreamType type)
@@ -2177,16 +2188,19 @@
   if (!VersionHasStreamType(transport_version())) {
     return;
   }
+  MockHttp3DebugVisitor debug_visitor;
   // Use an arbitrary stream id.
   QuicStreamId stream_id =
       GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3);
   char type[] = {kControlStream};
 
   QuicStreamFrame data1(stream_id, false, 0, QuicStringPiece(type, 1));
+  EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(stream_id)).Times(0);
   session_.OnStreamFrame(data1);
   EXPECT_EQ(stream_id,
             QuicSpdySessionPeer::GetReceiveControlStream(&session_)->id());
 
+  session_.set_debug_visitor(&debug_visitor);
   SettingsFrame settings;
   settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 512;
   settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5;
@@ -2203,6 +2217,7 @@
   EXPECT_NE(5u, session_.max_outbound_header_list_size());
   EXPECT_NE(42u, QpackEncoderPeer::maximum_blocked_streams(qpack_encoder));
 
+  EXPECT_CALL(debug_visitor, OnSettingsFrame(settings));
   session_.OnStreamFrame(frame);
 
   EXPECT_EQ(512u,
@@ -2379,15 +2394,21 @@
   if (!VersionHasStreamType(transport_version())) {
     return;
   }
+
+  MockHttp3DebugVisitor debug_visitor;
+  session_.set_debug_visitor(&debug_visitor);
+
   QuicStreamId id1 =
       GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0);
   char type1[] = {kControlStream};
 
   QuicStreamFrame data1(id1, false, 0, QuicStringPiece(type1, 1));
+  EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(id1));
   session_.OnStreamFrame(data1);
   QuicStreamId id2 =
       GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 1);
   QuicStreamFrame data2(id2, false, 0, QuicStringPiece(type1, 1));
+  EXPECT_CALL(debug_visitor, OnPeerControlStreamCreated(id2)).Times(0);
   EXPECT_CALL(*connection_,
               CloseConnection(QUIC_INVALID_STREAM_ID,
                               "Control stream is received twice.", _));
@@ -2400,11 +2421,13 @@
   char type2[]{kQpackEncoderStream};
 
   QuicStreamFrame data3(id3, false, 0, QuicStringPiece(type2, 1));
+  EXPECT_CALL(debug_visitor, OnPeerQpackEncoderStreamCreated(id3));
   session_.OnStreamFrame(data3);
 
   QuicStreamId id4 =
       GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 3);
   QuicStreamFrame data4(id4, false, 0, QuicStringPiece(type2, 1));
+  EXPECT_CALL(debug_visitor, OnPeerQpackEncoderStreamCreated(id4)).Times(0);
   EXPECT_CALL(*connection_,
               CloseConnection(QUIC_INVALID_STREAM_ID,
                               "QPACK encoder stream is received twice.", _));
@@ -2417,11 +2440,13 @@
   char type3[]{kQpackDecoderStream};
 
   QuicStreamFrame data5(id5, false, 0, QuicStringPiece(type3, 1));
+  EXPECT_CALL(debug_visitor, OnPeerQpackDecoderStreamCreated(id5));
   session_.OnStreamFrame(data5);
 
   QuicStreamId id6 =
       GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 5);
   QuicStreamFrame data6(id6, false, 0, QuicStringPiece(type3, 1));
+  EXPECT_CALL(debug_visitor, OnPeerQpackDecoderStreamCreated(id6)).Times(0);
   EXPECT_CALL(*connection_,
               CloseConnection(QUIC_INVALID_STREAM_ID,
                               "QPACK decoder stream is received twice.", _));