Adds a method to Http2Adapter to fetch the highest received stream ID. PiperOrigin-RevId: 378176441
diff --git a/http2/adapter/http2_adapter.h b/http2/adapter/http2_adapter.h index 0dbb54a..293e2fb 100644 --- a/http2/adapter/http2_adapter.h +++ b/http2/adapter/http2_adapter.h
@@ -72,6 +72,10 @@ // Returns the connection-level flow control window for the peer. virtual int GetPeerConnectionWindow() const = 0; + // Gets the highest stream ID value seen in a frame received by this endpoint. + // This method is only guaranteed to work for server endpoints. + virtual Http2StreamId GetHighestReceivedStreamId() const = 0; + // Marks the given amount of data as consumed for the given stream, which // enables the implementation layer to send WINDOW_UPDATEs as appropriate. virtual void MarkDataConsumedForStream(Http2StreamId stream_id,
diff --git a/http2/adapter/nghttp2_adapter.cc b/http2/adapter/nghttp2_adapter.cc index 947bb1f..deb4468 100644 --- a/http2/adapter/nghttp2_adapter.cc +++ b/http2/adapter/nghttp2_adapter.cc
@@ -106,6 +106,10 @@ return session_->GetRemoteWindowSize(); } +Http2StreamId NgHttp2Adapter::GetHighestReceivedStreamId() const { + return nghttp2_session_get_last_proc_stream_id(session_->raw_ptr()); +} + void NgHttp2Adapter::MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes) { int rc = session_->Consume(stream_id, num_bytes);
diff --git a/http2/adapter/nghttp2_adapter.h b/http2/adapter/nghttp2_adapter.h index 61b906e..d37e3c9 100644 --- a/http2/adapter/nghttp2_adapter.h +++ b/http2/adapter/nghttp2_adapter.h
@@ -51,6 +51,8 @@ int GetPeerConnectionWindow() const override; + Http2StreamId GetHighestReceivedStreamId() const override; + void MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes) override;
diff --git a/http2/adapter/nghttp2_adapter_test.cc b/http2/adapter/nghttp2_adapter_test.cc index 90b0166..2e2a1bf 100644 --- a/http2/adapter/nghttp2_adapter_test.cc +++ b/http2/adapter/nghttp2_adapter_test.cc
@@ -41,6 +41,8 @@ testing::StrEq(spdy::kHttp2ConnectionHeaderPrefix)); visitor.Clear(); + EXPECT_EQ(0, adapter->GetHighestReceivedStreamId()); + const std::string initial_frames = TestFrameSequence() .ServerPreface() .Ping(42) @@ -114,6 +116,8 @@ spdy::SpdyFrameType::HEADERS})); visitor.Clear(); + EXPECT_EQ(0, adapter->GetHighestReceivedStreamId()); + const std::string stream_frames = TestFrameSequence() .Headers(1, @@ -145,6 +149,9 @@ const ssize_t stream_result = adapter->ProcessBytes(stream_frames); EXPECT_EQ(stream_frames.size(), stream_result); + // Should be 3, but this method only works for server adapters. + EXPECT_EQ(0, adapter->GetHighestReceivedStreamId()); + // Even though the client recieved a GOAWAY, streams 1 and 5 are still active. EXPECT_TRUE(adapter->session().want_read()); @@ -159,6 +166,10 @@ .Data(1, "", true) .RstStream(5, Http2ErrorCode::REFUSED_STREAM) .Serialize()); + + // Should be 5, but this method only works for server adapters. + EXPECT_EQ(0, adapter->GetHighestReceivedStreamId()); + // After receiving END_STREAM for 1 and RST_STREAM for 5, the session no // longer expects reads. EXPECT_FALSE(adapter->session().want_read()); @@ -296,6 +307,8 @@ DataSavingVisitor visitor; auto adapter = NgHttp2Adapter::CreateServerAdapter(visitor); + EXPECT_EQ(0, adapter->GetHighestReceivedStreamId()); + const std::string frames = TestFrameSequence() .ClientPreface() .Ping(42) @@ -357,6 +370,8 @@ const ssize_t result = adapter->ProcessBytes(frames); EXPECT_EQ(frames.size(), result); + EXPECT_EQ(3, adapter->GetHighestReceivedStreamId()); + EXPECT_EQ(adapter->GetPeerConnectionWindow(), kDefaultInitialStreamWindowSize + 1000); @@ -402,6 +417,8 @@ const ssize_t result = adapter->ProcessBytes(frames); EXPECT_EQ(frames.size(), result); + EXPECT_EQ(1, adapter->GetHighestReceivedStreamId()); + // Server will want to send a SETTINGS ack. EXPECT_TRUE(adapter->session().want_write()); adapter->Send();
diff --git a/http2/adapter/oghttp2_adapter.cc b/http2/adapter/oghttp2_adapter.cc index 6334e4f..a71a71e 100644 --- a/http2/adapter/oghttp2_adapter.cc +++ b/http2/adapter/oghttp2_adapter.cc
@@ -87,6 +87,10 @@ return session_->GetRemoteWindowSize(); } +Http2StreamId OgHttp2Adapter::GetHighestReceivedStreamId() const { + return session_->GetHighestReceivedStreamId(); +} + void OgHttp2Adapter::MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes) { session_->Consume(stream_id, num_bytes);
diff --git a/http2/adapter/oghttp2_adapter.h b/http2/adapter/oghttp2_adapter.h index 26d5743..1b9d90d 100644 --- a/http2/adapter/oghttp2_adapter.h +++ b/http2/adapter/oghttp2_adapter.h
@@ -36,6 +36,7 @@ void SubmitMetadata(Http2StreamId stream_id, bool fin) override; void Send() override; int GetPeerConnectionWindow() const override; + Http2StreamId GetHighestReceivedStreamId() const override; void MarkDataConsumedForStream(Http2StreamId stream_id, size_t num_bytes) override; void SubmitRst(Http2StreamId stream_id, Http2ErrorCode error_code) override;
diff --git a/http2/adapter/oghttp2_session.cc b/http2/adapter/oghttp2_session.cc index 05fc467..aa135ff 100644 --- a/http2/adapter/oghttp2_session.cc +++ b/http2/adapter/oghttp2_session.cc
@@ -304,6 +304,8 @@ size_t length, uint8_t type, uint8_t flags) { + highest_received_stream_id_ = std::max(static_cast<Http2StreamId>(stream_id), + highest_received_stream_id_); visitor_.OnFrameHeader(stream_id, length, type, flags); }
diff --git a/http2/adapter/oghttp2_session.h b/http2/adapter/oghttp2_session.h index 778af35..8655820 100644 --- a/http2/adapter/oghttp2_session.h +++ b/http2/adapter/oghttp2_session.h
@@ -48,6 +48,9 @@ bool IsServerSession() const { return options_.perspective == Perspective::kServer; } + Http2StreamId GetHighestReceivedStreamId() const { + return highest_received_stream_id_; + } // From Http2Session. ssize_t ProcessBytes(absl::string_view bytes) override; @@ -191,6 +194,7 @@ absl::string_view remaining_preface_; Http2StreamId next_stream_id_ = 1; + Http2StreamId highest_received_stream_id_ = 0; int peer_window_ = 65535; int stream_receive_window_limit_ = 65535; int max_frame_payload_ = 16384;
diff --git a/http2/adapter/oghttp2_session_test.cc b/http2/adapter/oghttp2_session_test.cc index 28ddb57..c6525fa 100644 --- a/http2/adapter/oghttp2_session_test.cc +++ b/http2/adapter/oghttp2_session_test.cc
@@ -35,6 +35,7 @@ EXPECT_FALSE(session.want_write()); EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize); EXPECT_FALSE(session.IsServerSession()); + EXPECT_EQ(0, session.GetHighestReceivedStreamId()); } TEST(OgHttp2SessionTest, ClientHandlesFrames) { @@ -64,6 +65,7 @@ EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize + 1000); + EXPECT_EQ(0, session.GetHighestReceivedStreamId()); // Should OgHttp2Session require that streams 1 and 3 have been created? @@ -96,6 +98,7 @@ 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); + EXPECT_EQ(3, session.GetHighestReceivedStreamId()); } // Verifies that a client session enqueues initial SETTINGS if Send() is called @@ -227,6 +230,7 @@ EXPECT_FALSE(session.want_write()); EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize); EXPECT_TRUE(session.IsServerSession()); + EXPECT_EQ(0, session.GetHighestReceivedStreamId()); } TEST(OgHttp2SessionTest, ServerHandlesFrames) { @@ -297,6 +301,7 @@ EXPECT_EQ(session.GetRemoteWindowSize(), kDefaultInitialStreamWindowSize + 1000); + EXPECT_EQ(3, session.GetHighestReceivedStreamId()); } // Verifies that a server session enqueues initial SETTINGS before whatever @@ -361,6 +366,8 @@ const ssize_t result = session.ProcessBytes(frames); EXPECT_EQ(frames.size(), result); + EXPECT_EQ(1, session.GetHighestReceivedStreamId()); + // Server will want to send initial SETTINGS, and a SETTINGS ack. EXPECT_TRUE(session.want_write()); session.Send();