Adds a `OgHttp2Session` unit test exercising the case where the visitor returns false in `OnEndStream()`. PiperOrigin-RevId: 488664335
diff --git a/quiche/http2/adapter/nghttp2_session_test.cc b/quiche/http2/adapter/nghttp2_session_test.cc index 61500bb..f11c490 100644 --- a/quiche/http2/adapter/nghttp2_session_test.cc +++ b/quiche/http2/adapter/nghttp2_session_test.cc
@@ -319,6 +319,55 @@ "Extension frame payload for stream 1 is null!"); } +TEST_F(NgHttp2SessionTest, ServerSeesErrorOnEndStream) { + NgHttp2Session session(Perspective::kServer, CreateCallbacks(), options_, + &visitor_); + + const std::string frames = TestFrameSequence() + .ClientPreface() + .Headers(1, + {{":method", "POST"}, + {":scheme", "https"}, + {":authority", "example.com"}, + {":path", "/"}}, + /*fin=*/false) + .Data(1, "Request body", true) + .Serialize(); + testing::InSequence s; + + // Client preface (empty SETTINGS) + EXPECT_CALL(visitor_, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor_, OnSettingsStart()); + EXPECT_CALL(visitor_, OnSettingsEnd()); + // Stream 1 + EXPECT_CALL(visitor_, OnFrameHeader(1, _, HEADERS, 0x4)); + 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", "/")); + EXPECT_CALL(visitor_, OnEndHeadersForStream(1)); + + EXPECT_CALL(visitor_, OnFrameHeader(1, _, DATA, 0x1)); + EXPECT_CALL(visitor_, OnBeginDataForStream(1, _)); + EXPECT_CALL(visitor_, OnDataForStream(1, "Request body")); + EXPECT_CALL(visitor_, OnEndStream(1)).WillOnce(testing::Return(false)); + + const int64_t result = session.ProcessBytes(frames); + EXPECT_EQ(NGHTTP2_ERR_CALLBACK_FAILURE, result); + + EXPECT_TRUE(session.want_write()); + + EXPECT_CALL(visitor_, OnBeforeFrameSent(SETTINGS, 0, _, 0x1)); + EXPECT_CALL(visitor_, OnFrameSent(SETTINGS, 0, _, 0x1, 0)); + + ASSERT_EQ(0, nghttp2_session_send(session.raw_ptr())); + EXPECT_THAT(visitor_.data(), EqualsFrames({spdy::SpdyFrameType::SETTINGS})); + visitor_.Clear(); + + EXPECT_FALSE(session.want_write()); +} + } // namespace } // namespace test } // namespace adapter
diff --git a/quiche/http2/adapter/oghttp2_session_test.cc b/quiche/http2/adapter/oghttp2_session_test.cc index 59f5c4b..f536cd7 100644 --- a/quiche/http2/adapter/oghttp2_session_test.cc +++ b/quiche/http2/adapter/oghttp2_session_test.cc
@@ -933,6 +933,68 @@ SpdyFrameType::HEADERS})); } +TEST(OgHttp2SessionTest, ServerSeesErrorOnEndStream) { + DataSavingVisitor visitor; + OgHttp2Session::Options options; + options.perspective = Perspective::kServer; + OgHttp2Session session(visitor, options); + + const std::string frames = TestFrameSequence() + .ClientPreface() + .Headers(1, + {{":method", "POST"}, + {":scheme", "https"}, + {":authority", "example.com"}, + {":path", "/"}}, + /*fin=*/false) + .Data(1, "Request body", true) + .Serialize(); + testing::InSequence s; + + // Client preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 0, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + EXPECT_CALL(visitor, OnSettingsEnd()); + // Stream 1 + EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 0x4)); + 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", "/")); + EXPECT_CALL(visitor, OnEndHeadersForStream(1)); + + EXPECT_CALL(visitor, OnFrameHeader(1, _, DATA, 0x1)); + EXPECT_CALL(visitor, OnBeginDataForStream(1, _)); + EXPECT_CALL(visitor, OnDataForStream(1, "Request body")); + EXPECT_CALL(visitor, OnEndStream(1)).WillOnce(testing::Return(false)); + EXPECT_CALL( + visitor, + OnConnectionError(Http2VisitorInterface::ConnectionError::kParseError)); + + const int64_t result = session.ProcessBytes(frames); + EXPECT_EQ(/*NGHTTP2_ERR_CALLBACK_FAILURE=*/-902, result); + + EXPECT_TRUE(session.want_write()); + + EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0)); + EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0)); + EXPECT_CALL(visitor, OnBeforeFrameSent(GOAWAY, 0, _, 0x0)); + EXPECT_CALL( + visitor, + OnFrameSent(GOAWAY, 0, _, 0x0, + static_cast<int>( + Http2VisitorInterface::ConnectionError::kParseError))); + + int send_result = session.Send(); + EXPECT_EQ(0, send_result); + EXPECT_THAT(visitor.data(), + EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::GOAWAY})); + visitor.Clear(); + + EXPECT_FALSE(session.want_write()); +} + } // namespace test } // namespace adapter } // namespace http2