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);