Deletes a stream entry from CallbackVisitor's stream map in OnCloseStream().
This should fix the memory consumption bug reported in Envoy:
https://github.com/envoyproxy/envoy/issues/19761
PiperOrigin-RevId: 425673006
diff --git a/http2/adapter/callback_visitor.cc b/http2/adapter/callback_visitor.cc
index 1dd082e..7d59c6d 100644
--- a/http2/adapter/callback_visitor.cc
+++ b/http2/adapter/callback_visitor.cc
@@ -262,6 +262,7 @@
callbacks_->on_stream_close_callback(
nullptr, stream_id, static_cast<uint32_t>(error_code), user_data_);
}
+ stream_map_.erase(stream_id);
}
void CallbackVisitor::OnPriorityForStream(Http2StreamId /*stream_id*/,
diff --git a/http2/adapter/callback_visitor.h b/http2/adapter/callback_visitor.h
index fa0c770..1f7452b 100644
--- a/http2/adapter/callback_visitor.h
+++ b/http2/adapter/callback_visitor.h
@@ -69,6 +69,8 @@
bool OnMetadataEndForStream(Http2StreamId stream_id) override;
void OnErrorDebug(absl::string_view message) override;
+ size_t stream_map_size() const { return stream_map_.size(); }
+
private:
struct QUICHE_EXPORT_PRIVATE StreamInfo {
bool before_sent_headers = false;
@@ -82,9 +84,12 @@
void PopulateFrame(nghttp2_frame& frame, uint8_t frame_type,
Http2StreamId stream_id, size_t length, uint8_t flags,
uint32_t error_code, bool sent_headers);
+
// Creates the StreamInfoMap entry if it doesn't exist.
StreamInfoMap::iterator GetStreamInfo(Http2StreamId stream_id);
+ StreamInfoMap stream_map_;
+
Perspective perspective_;
nghttp2_session_callbacks_unique_ptr callbacks_;
void* user_data_;
@@ -92,8 +97,6 @@
nghttp2_frame current_frame_;
std::vector<nghttp2_settings_entry> settings_;
size_t remaining_data_ = 0;
-
- StreamInfoMap stream_map_;
};
} // namespace adapter
diff --git a/http2/adapter/callback_visitor_test.cc b/http2/adapter/callback_visitor_test.cc
index 9ed28f0..8f83da5 100644
--- a/http2/adapter/callback_visitor_test.cc
+++ b/http2/adapter/callback_visitor_test.cc
@@ -70,6 +70,8 @@
EXPECT_CALL(callbacks, OnFrameRecv(IsGoAway(5, NGHTTP2_ENHANCE_YOUR_CALM,
"calm down!!")));
visitor.OnGoAway(5, Http2ErrorCode::ENHANCE_YOUR_CALM, "calm down!!");
+
+ EXPECT_EQ(visitor.stream_map_size(), 0);
}
TEST(ClientCallbackVisitorUnitTest, StreamFrames) {
@@ -79,6 +81,8 @@
testing::InSequence seq;
+ EXPECT_EQ(visitor.stream_map_size(), 0);
+
// HEADERS on stream 1
EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(1, HEADERS, _)));
visitor.OnFrameHeader(1, 23, HEADERS, 4);
@@ -87,6 +91,8 @@
OnBeginHeaders(IsHeaders(1, _, NGHTTP2_HCAT_RESPONSE)));
visitor.OnBeginHeadersForStream(1);
+ EXPECT_EQ(visitor.stream_map_size(), 1);
+
EXPECT_CALL(callbacks, OnHeader(_, ":status", "200", _));
visitor.OnHeaderForStream(1, ":status", "200");
@@ -129,6 +135,9 @@
EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(3, RST_STREAM, 0)));
visitor.OnFrameHeader(3, 4, RST_STREAM, 0);
+ // No change in stream map size.
+ EXPECT_EQ(visitor.stream_map_size(), 1);
+
EXPECT_CALL(callbacks, OnFrameRecv(IsRstStream(3, NGHTTP2_INTERNAL_ERROR)));
visitor.OnRstStream(3, Http2ErrorCode::INTERNAL_ERROR);
@@ -147,6 +156,9 @@
EXPECT_CALL(callbacks, OnStreamClose(1, NGHTTP2_NO_ERROR));
visitor.OnCloseStream(1, Http2ErrorCode::HTTP2_NO_ERROR);
+ // Stream map is empty again.
+ EXPECT_EQ(visitor.stream_map_size(), 0);
+
EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(5, RST_STREAM, _)));
visitor.OnFrameHeader(5, 4, RST_STREAM, 0);
@@ -155,6 +167,8 @@
EXPECT_CALL(callbacks, OnStreamClose(5, NGHTTP2_REFUSED_STREAM));
visitor.OnCloseStream(5, Http2ErrorCode::REFUSED_STREAM);
+
+ EXPECT_EQ(visitor.stream_map_size(), 0);
}
TEST(ClientCallbackVisitorUnitTest, HeadersWithContinuation) {
@@ -228,6 +242,8 @@
EXPECT_CALL(callbacks, OnFrameRecv(IsPingAck(247)));
visitor.OnPing(247, true);
+
+ EXPECT_EQ(visitor.stream_map_size(), 0);
}
TEST(ServerCallbackVisitorUnitTest, StreamFrames) {
@@ -246,6 +262,8 @@
NGHTTP2_HCAT_REQUEST)));
visitor.OnBeginHeadersForStream(1);
+ EXPECT_EQ(visitor.stream_map_size(), 1);
+
EXPECT_CALL(callbacks, OnHeader(_, ":method", "POST", _));
visitor.OnHeaderForStream(1, ":method", "POST");
@@ -280,6 +298,8 @@
EXPECT_CALL(callbacks, OnStreamClose(1, NGHTTP2_NO_ERROR));
visitor.OnCloseStream(1, Http2ErrorCode::HTTP2_NO_ERROR);
+ EXPECT_EQ(visitor.stream_map_size(), 0);
+
// RST_STREAM on stream 3
EXPECT_CALL(callbacks, OnBeginFrame(HasFrameHeader(3, RST_STREAM, 0)));
visitor.OnFrameHeader(3, 4, RST_STREAM, 0);
@@ -289,6 +309,8 @@
EXPECT_CALL(callbacks, OnStreamClose(3, NGHTTP2_INTERNAL_ERROR));
visitor.OnCloseStream(3, Http2ErrorCode::INTERNAL_ERROR);
+
+ EXPECT_EQ(visitor.stream_map_size(), 0);
}
TEST(ServerCallbackVisitorUnitTest, DataWithPadding) {