Adds a WindowManager constructor parameter to disable automatic updates to internal window state.
By default, internal window state is updated when invoking the WindowUpdateListener. The `oghttp2` library needs the capability to disable this behavior.
PiperOrigin-RevId: 429263683
diff --git a/http2/adapter/window_manager.cc b/http2/adapter/window_manager.cc
index 76bde18..3dd9baf 100644
--- a/http2/adapter/window_manager.cc
+++ b/http2/adapter/window_manager.cc
@@ -9,11 +9,13 @@
namespace adapter {
WindowManager::WindowManager(int64_t window_size_limit,
- WindowUpdateListener listener)
+ WindowUpdateListener listener,
+ bool update_window_on_notify)
: limit_(window_size_limit),
window_(window_size_limit),
buffered_(0),
- listener_(std::move(listener)) {}
+ listener_(std::move(listener)),
+ update_window_on_notify_(update_window_on_notify) {}
void WindowManager::OnWindowSizeLimitChange(const int64_t new_limit) {
QUICHE_VLOG(2) << "WindowManager@" << this
@@ -82,7 +84,9 @@
QUICHE_VLOG(2) << "WindowManager@" << this
<< " Informing listener of delta: " << delta;
listener_(delta);
- window_ += delta;
+ if (update_window_on_notify_) {
+ window_ += delta;
+ }
}
}
diff --git a/http2/adapter/window_manager.h b/http2/adapter/window_manager.h
index f4ee23f..45a6ddd 100644
--- a/http2/adapter/window_manager.h
+++ b/http2/adapter/window_manager.h
@@ -21,7 +21,8 @@
// A WindowUpdateListener is invoked when it is time to send a window update.
typedef std::function<void(int64_t)> WindowUpdateListener;
- WindowManager(int64_t window_size_limit, WindowUpdateListener listener);
+ WindowManager(int64_t window_size_limit, WindowUpdateListener listener,
+ bool update_window_on_notify = true);
int64_t CurrentWindowSize() const { return window_; }
int64_t WindowSizeLimit() const { return limit_; }
@@ -73,6 +74,8 @@
int64_t buffered_;
WindowUpdateListener listener_;
+
+ bool update_window_on_notify_;
};
} // namespace adapter
diff --git a/http2/adapter/window_manager_test.cc b/http2/adapter/window_manager_test.cc
index 191ebe9..c5a9ffb 100644
--- a/http2/adapter/window_manager_test.cc
+++ b/http2/adapter/window_manager_test.cc
@@ -208,6 +208,61 @@
EXPECT_EQ(wm_.CurrentWindowSize(), kDefaultLimit - 1000);
}
+// This test verifies that when the constructor option is specified,
+// WindowManager does not update its internal accounting of the flow control
+// window when notifying the listener.
+TEST(WindowManagerNoUpdateTest, NoWindowUpdateOnListener) {
+ const int64_t kDefaultLimit = 65535;
+
+ std::list<int64_t> call_sequence1;
+ WindowManager wm1(
+ kDefaultLimit,
+ [&call_sequence1](int64_t delta) { call_sequence1.push_back(delta); },
+ /*update_window_on_notify=*/true); // default
+ std::list<int64_t> call_sequence2;
+ WindowManager wm2(
+ kDefaultLimit,
+ [&call_sequence2](int64_t delta) { call_sequence2.push_back(delta); },
+ /*update_window_on_notify=*/false);
+
+ const int64_t consumed = kDefaultLimit / 3 - 1;
+
+ wm1.MarkWindowConsumed(consumed);
+ EXPECT_TRUE(call_sequence1.empty());
+ wm2.MarkWindowConsumed(consumed);
+ EXPECT_TRUE(call_sequence2.empty());
+
+ EXPECT_EQ(wm1.CurrentWindowSize(), kDefaultLimit - consumed);
+ EXPECT_EQ(wm2.CurrentWindowSize(), kDefaultLimit - consumed);
+
+ const int64_t extra = 1;
+ wm1.MarkWindowConsumed(extra);
+ EXPECT_THAT(call_sequence1, testing::ElementsAre(consumed + extra));
+ // Window size *is* updated after invoking the listener.
+ EXPECT_EQ(wm1.CurrentWindowSize(), kDefaultLimit);
+ call_sequence1.clear();
+
+ wm2.MarkWindowConsumed(extra);
+ EXPECT_THAT(call_sequence2, testing::ElementsAre(consumed + extra));
+ // Window size is *not* updated after invoking the listener.
+ EXPECT_EQ(wm2.CurrentWindowSize(), kDefaultLimit - (consumed + extra));
+ call_sequence2.clear();
+
+ // Manually increase the window by the listener notification amount.
+ wm2.IncreaseWindow(consumed + extra);
+ EXPECT_EQ(wm2.CurrentWindowSize(), kDefaultLimit);
+
+ wm1.SetWindowSizeLimit(kDefaultLimit * 5);
+ EXPECT_THAT(call_sequence1, testing::ElementsAre(kDefaultLimit * 4));
+ // *Does* update the window size.
+ EXPECT_EQ(wm1.CurrentWindowSize(), kDefaultLimit * 5);
+
+ wm2.SetWindowSizeLimit(kDefaultLimit * 5);
+ EXPECT_THAT(call_sequence2, testing::ElementsAre(kDefaultLimit * 4));
+ // Does *not* update the window size.
+ EXPECT_EQ(wm2.CurrentWindowSize(), kDefaultLimit);
+}
+
} // namespace
} // namespace test
} // namespace adapter