Adds an OnFrameHeader() callback to Http2VisitorInterface.

PiperOrigin-RevId: 371390069
Change-Id: Icb2bb06ac19b42077e61c45c8d89ae7255030ee3
diff --git a/http2/adapter/http2_visitor_interface.h b/http2/adapter/http2_visitor_interface.h
index a14f434..12729e7 100644
--- a/http2/adapter/http2_visitor_interface.h
+++ b/http2/adapter/http2_visitor_interface.h
@@ -53,6 +53,12 @@
   // Called when a connection-level processing error has been encountered.
   virtual void OnConnectionError() = 0;
 
+  // Called when the header for a frame is received.
+  virtual void OnFrameHeader(Http2StreamId stream_id,
+                             size_t length,
+                             uint8_t type,
+                             uint8_t flags) {}
+
   // Called when a non-ack SETTINGS frame is received.
   virtual void OnSettingsStart() = 0;
 
diff --git a/http2/adapter/mock_http2_visitor.h b/http2/adapter/mock_http2_visitor.h
index 378faea..171d40f 100644
--- a/http2/adapter/mock_http2_visitor.h
+++ b/http2/adapter/mock_http2_visitor.h
@@ -14,6 +14,11 @@
   MockHttp2Visitor() = default;
 
   MOCK_METHOD(void, OnConnectionError, (), (override));
+  MOCK_METHOD(
+      void,
+      OnFrameHeader,
+      (Http2StreamId stream_id, size_t length, uint8_t type, uint8_t flags),
+      (override));
   MOCK_METHOD(void, OnSettingsStart, (), (override));
   MOCK_METHOD(void, OnSetting, (Http2Setting setting), (override));
   MOCK_METHOD(void, OnSettingsEnd, (), (override));
diff --git a/http2/adapter/nghttp2_callbacks.cc b/http2/adapter/nghttp2_callbacks.cc
index dc4962a..2568179 100644
--- a/http2/adapter/nghttp2_callbacks.cc
+++ b/http2/adapter/nghttp2_callbacks.cc
@@ -20,6 +20,8 @@
                  const nghttp2_frame_hd* header,
                  void* user_data) {
   auto* visitor = static_cast<Http2VisitorInterface*>(user_data);
+  visitor->OnFrameHeader(header->stream_id, header->length, header->type,
+                         header->flags);
   if (header->type == NGHTTP2_DATA) {
     visitor->OnBeginDataForStream(header->stream_id, header->length);
   }
diff --git a/http2/adapter/nghttp2_session_test.cc b/http2/adapter/nghttp2_session_test.cc
index bfb54bf..62a255e 100644
--- a/http2/adapter/nghttp2_session_test.cc
+++ b/http2/adapter/nghttp2_session_test.cc
@@ -12,6 +12,20 @@
 namespace test {
 namespace {
 
+using testing::_;
+
+enum FrameType {
+  DATA,
+  HEADERS,
+  PRIORITY,
+  RST_STREAM,
+  SETTINGS,
+  PUSH_PROMISE,
+  PING,
+  GOAWAY,
+  WINDOW_UPDATE,
+};
+
 class DataSavingVisitor : public testing::StrictMock<MockHttp2Visitor> {
  public:
   void Save(absl::string_view data) { absl::StrAppend(&data_, data); }
@@ -75,10 +89,13 @@
   testing::InSequence s;
 
   // Server preface (empty SETTINGS)
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0));
   EXPECT_CALL(visitor_, OnSettingsStart());
   EXPECT_CALL(visitor_, OnSettingsEnd());
 
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
   EXPECT_CALL(visitor_, OnPing(42, false));
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
   EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000));
 
   const ssize_t initial_result = session.ProcessBytes(initial_frames);
@@ -148,16 +165,20 @@
           .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!")
           .Serialize();
 
+  EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 4));
   EXPECT_CALL(visitor_, OnBeginHeadersForStream(1));
   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":status", "200"));
   EXPECT_CALL(visitor_, OnHeaderForStream(1, "server", "my-fake-server"));
   EXPECT_CALL(visitor_,
               OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
   EXPECT_CALL(visitor_, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor_, OnFrameHeader(1, 26, DATA, 0));
   EXPECT_CALL(visitor_, OnBeginDataForStream(1, 26));
   EXPECT_CALL(visitor_, OnDataForStream(1, "This is the response body."));
+  EXPECT_CALL(visitor_, OnFrameHeader(3, 4, RST_STREAM, 0));
   EXPECT_CALL(visitor_, OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR));
   EXPECT_CALL(visitor_, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR));
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 19, GOAWAY, 0));
   EXPECT_CALL(visitor_,
               OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!"));
   const ssize_t stream_result = session.ProcessBytes(stream_frames);
@@ -166,9 +187,11 @@
   // Even though the client recieved a GOAWAY, streams 1 and 5 are still active.
   EXPECT_TRUE(session.want_read());
 
+  EXPECT_CALL(visitor_, OnFrameHeader(1, 0, DATA, 1));
   EXPECT_CALL(visitor_, OnBeginDataForStream(1, 0));
   EXPECT_CALL(visitor_, OnEndStream(1));
   EXPECT_CALL(visitor_, OnCloseStream(1, Http2ErrorCode::NO_ERROR));
+  EXPECT_CALL(visitor_, OnFrameHeader(5, 4, RST_STREAM, 0));
   EXPECT_CALL(visitor_, OnRstStream(5, Http2ErrorCode::REFUSED_STREAM));
   EXPECT_CALL(visitor_, OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM));
   session.ProcessBytes(TestFrameSequence()
@@ -223,20 +246,27 @@
   testing::InSequence s;
 
   // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0));
   EXPECT_CALL(visitor_, OnSettingsStart());
   EXPECT_CALL(visitor_, OnSettingsEnd());
 
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
   EXPECT_CALL(visitor_, OnPing(42, false));
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
   EXPECT_CALL(visitor_, OnWindowUpdate(0, 1000));
+  EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 4));
   EXPECT_CALL(visitor_, OnBeginHeadersForStream(1));
   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":method", "POST"));
   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":scheme", "https"));
   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":authority", "example.com"));
   EXPECT_CALL(visitor_, OnHeaderForStream(1, ":path", "/this/is/request/one"));
   EXPECT_CALL(visitor_, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor_, OnFrameHeader(1, 4, WINDOW_UPDATE, 0));
   EXPECT_CALL(visitor_, OnWindowUpdate(1, 2000));
+  EXPECT_CALL(visitor_, OnFrameHeader(1, 25, DATA, 0));
   EXPECT_CALL(visitor_, OnBeginDataForStream(1, 25));
   EXPECT_CALL(visitor_, OnDataForStream(1, "This is the request body."));
+  EXPECT_CALL(visitor_, OnFrameHeader(3, _, HEADERS, 5));
   EXPECT_CALL(visitor_, OnBeginHeadersForStream(3));
   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":method", "GET"));
   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":scheme", "http"));
@@ -244,8 +274,10 @@
   EXPECT_CALL(visitor_, OnHeaderForStream(3, ":path", "/this/is/request/two"));
   EXPECT_CALL(visitor_, OnEndHeadersForStream(3));
   EXPECT_CALL(visitor_, OnEndStream(3));
+  EXPECT_CALL(visitor_, OnFrameHeader(3, 4, RST_STREAM, 0));
   EXPECT_CALL(visitor_, OnRstStream(3, Http2ErrorCode::CANCEL));
   EXPECT_CALL(visitor_, OnCloseStream(3, Http2ErrorCode::CANCEL));
+  EXPECT_CALL(visitor_, OnFrameHeader(0, 8, PING, 0));
   EXPECT_CALL(visitor_, OnPing(47, false));
 
   const ssize_t result = session.ProcessBytes(frames);
diff --git a/http2/adapter/oghttp2_adapter_test.cc b/http2/adapter/oghttp2_adapter_test.cc
index d5e7b1d..4c849f6 100644
--- a/http2/adapter/oghttp2_adapter_test.cc
+++ b/http2/adapter/oghttp2_adapter_test.cc
@@ -23,8 +23,11 @@
 };
 
 TEST_F(OgHttp2AdapterTest, ProcessBytes) {
+  testing::InSequence seq;
+  EXPECT_CALL(http2_visitor_, OnFrameHeader(0, 0, 4, 0));
   EXPECT_CALL(http2_visitor_, OnSettingsStart());
   EXPECT_CALL(http2_visitor_, OnSettingsEnd());
+  EXPECT_CALL(http2_visitor_, OnFrameHeader(0, 8, 6, 0));
   EXPECT_CALL(http2_visitor_, OnPing(17, false));
   adapter_->ProcessBytes(
       TestFrameSequence().ClientPreface().Ping(17).Serialize());
diff --git a/http2/adapter/oghttp2_session.cc b/http2/adapter/oghttp2_session.cc
index 2582544..ea3e0aa 100644
--- a/http2/adapter/oghttp2_session.cc
+++ b/http2/adapter/oghttp2_session.cc
@@ -97,10 +97,12 @@
   visitor_.OnConnectionError();
 }
 
-void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId /*stream_id*/,
-                                    size_t /*length*/,
-                                    uint8_t /*type*/,
-                                    uint8_t /*flags*/) {}
+void OgHttp2Session::OnCommonHeader(spdy::SpdyStreamId stream_id,
+                                    size_t length,
+                                    uint8_t type,
+                                    uint8_t flags) {
+  visitor_.OnFrameHeader(stream_id, length, type, flags);
+}
 
 void OgHttp2Session::OnDataFrameHeader(spdy::SpdyStreamId stream_id,
                                        size_t length,
@@ -119,9 +121,12 @@
 }
 
 void OgHttp2Session::OnStreamPadLength(spdy::SpdyStreamId /*stream_id*/,
-                                       size_t /*value*/) {}
+                                       size_t /*value*/) {
+  // TODO(181586191): handle padding
+}
 
 void OgHttp2Session::OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) {
+  // TODO(181586191): handle padding
 }
 
 spdy::SpdyHeadersHandlerInterface* OgHttp2Session::OnHeaderFrameStart(
diff --git a/http2/adapter/oghttp2_session_test.cc b/http2/adapter/oghttp2_session_test.cc
index 5896c72..ab15569 100644
--- a/http2/adapter/oghttp2_session_test.cc
+++ b/http2/adapter/oghttp2_session_test.cc
@@ -7,6 +7,23 @@
 namespace http2 {
 namespace adapter {
 namespace test {
+namespace {
+
+using testing::_;
+
+enum FrameType {
+  DATA,
+  HEADERS,
+  PRIORITY,
+  RST_STREAM,
+  SETTINGS,
+  PUSH_PROMISE,
+  PING,
+  GOAWAY,
+  WINDOW_UPDATE,
+};
+
+}  // namespace
 
 TEST(OgHttp2SessionTest, ClientConstruction) {
   testing::StrictMock<MockHttp2Visitor> visitor;
@@ -30,10 +47,13 @@
   testing::InSequence s;
 
   // Server preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
   EXPECT_CALL(visitor, OnSettingsStart());
   EXPECT_CALL(visitor, OnSettingsEnd());
 
+  EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0));
   EXPECT_CALL(visitor, OnPing(42, false));
+  EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
   EXPECT_CALL(visitor, OnWindowUpdate(0, 1000));
 
   const ssize_t initial_result = session.ProcessBytes(initial_frames);
@@ -56,16 +76,20 @@
           .GoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!")
           .Serialize();
 
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
   EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
   EXPECT_CALL(visitor, OnHeaderForStream(1, ":status", "200"));
   EXPECT_CALL(visitor, OnHeaderForStream(1, "server", "my-fake-server"));
   EXPECT_CALL(visitor,
               OnHeaderForStream(1, "date", "Tue, 6 Apr 2021 12:54:01 GMT"));
   EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnFrameHeader(1, 26, DATA, 0));
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 26));
   EXPECT_CALL(visitor, OnDataForStream(1, "This is the response body."));
+  EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0));
   EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR));
   EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR));
+  EXPECT_CALL(visitor, OnFrameHeader(0, 19, GOAWAY, 0));
   EXPECT_CALL(visitor, OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, ""));
   const ssize_t stream_result = session.ProcessBytes(stream_frames);
   EXPECT_EQ(stream_frames.size(), stream_result);
@@ -109,20 +133,27 @@
   testing::InSequence s;
 
   // Client preface (empty SETTINGS)
+  EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0));
   EXPECT_CALL(visitor, OnSettingsStart());
   EXPECT_CALL(visitor, OnSettingsEnd());
 
+  EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0));
   EXPECT_CALL(visitor, OnPing(42, false));
+  EXPECT_CALL(visitor, OnFrameHeader(0, 4, WINDOW_UPDATE, 0));
   EXPECT_CALL(visitor, OnWindowUpdate(0, 1000));
+  EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
   EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
   EXPECT_CALL(visitor, OnHeaderForStream(1, ":method", "POST"));
   EXPECT_CALL(visitor, OnHeaderForStream(1, ":scheme", "https"));
   EXPECT_CALL(visitor, OnHeaderForStream(1, ":authority", "example.com"));
   EXPECT_CALL(visitor, OnHeaderForStream(1, ":path", "/this/is/request/one"));
   EXPECT_CALL(visitor, OnEndHeadersForStream(1));
+  EXPECT_CALL(visitor, OnFrameHeader(1, 4, WINDOW_UPDATE, 0));
   EXPECT_CALL(visitor, OnWindowUpdate(1, 2000));
+  EXPECT_CALL(visitor, OnFrameHeader(1, 25, DATA, 0));
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 25));
   EXPECT_CALL(visitor, OnDataForStream(1, "This is the request body."));
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 5));
   EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
   EXPECT_CALL(visitor, OnHeaderForStream(3, ":method", "GET"));
   EXPECT_CALL(visitor, OnHeaderForStream(3, ":scheme", "http"));
@@ -130,8 +161,10 @@
   EXPECT_CALL(visitor, OnHeaderForStream(3, ":path", "/this/is/request/two"));
   EXPECT_CALL(visitor, OnEndHeadersForStream(3));
   EXPECT_CALL(visitor, OnEndStream(3));
+  EXPECT_CALL(visitor, OnFrameHeader(3, 4, RST_STREAM, 0));
   EXPECT_CALL(visitor, OnRstStream(3, Http2ErrorCode::CANCEL));
   EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::CANCEL));
+  EXPECT_CALL(visitor, OnFrameHeader(0, 8, PING, 0));
   EXPECT_CALL(visitor, OnPing(47, false));
 
   const ssize_t result = session.ProcessBytes(frames);