Detects flow control window overflow and shuts down the stream or connection as appropriate.

PiperOrigin-RevId: 429322062
diff --git a/http2/adapter/oghttp2_adapter_test.cc b/http2/adapter/oghttp2_adapter_test.cc
index 5b4637b..c00601e 100644
--- a/http2/adapter/oghttp2_adapter_test.cc
+++ b/http2/adapter/oghttp2_adapter_test.cc
@@ -3903,11 +3903,10 @@
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 16384));
   EXPECT_CALL(visitor, OnDataForStream(1, _));
   EXPECT_CALL(visitor, OnFrameHeader(1, 16384, DATA, 0x0));
-  EXPECT_CALL(visitor, OnBeginDataForStream(1, 16384));
-  EXPECT_CALL(visitor, OnDataForStream(1, _));
-  EXPECT_CALL(visitor, OnFrameHeader(1, 4464, DATA, 0x0));
-  EXPECT_CALL(visitor, OnBeginDataForStream(1, 4464));
-  EXPECT_CALL(visitor, OnDataForStream(1, _));
+  EXPECT_CALL(visitor,
+              OnConnectionError(
+                  Http2VisitorInterface::ConnectionError::kFlowControlError));
+  // No further frame data or headers are delivered.
 
   const int64_t result = adapter->ProcessBytes(frames);
   EXPECT_EQ(frames.size(), static_cast<size_t>(result));
@@ -3916,13 +3915,16 @@
 
   EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
   EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
-  EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, 0, 0x1));
-  EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, 0, 0x1, 0));
+  EXPECT_CALL(visitor, OnBeforeFrameSent(GOAWAY, 0, _, 0x0));
+  EXPECT_CALL(
+      visitor,
+      OnFrameSent(GOAWAY, 0, _, 0x0,
+                  static_cast<int>(Http2ErrorCode::FLOW_CONTROL_ERROR)));
 
   int send_result = adapter->Send();
   EXPECT_EQ(0, send_result);
   EXPECT_THAT(visitor.data(),
-              EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::SETTINGS}));
+              EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::GOAWAY}));
 }
 
 TEST(OgHttp2AdapterTest, ClientDisobeysStreamFlowControl) {
@@ -3977,6 +3979,7 @@
   EXPECT_THAT(visitor.data(),
               EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::SETTINGS,
                             SpdyFrameType::WINDOW_UPDATE}));
+  visitor.Clear();
 
   EXPECT_CALL(visitor, OnFrameHeader(1, 16384, DATA, 0x0));
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 16384));
@@ -3988,16 +3991,22 @@
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 16384));
   EXPECT_CALL(visitor, OnDataForStream(1, _));
   EXPECT_CALL(visitor, OnFrameHeader(1, 16384, DATA, 0x0));
-  EXPECT_CALL(visitor, OnBeginDataForStream(1, 16384));
-  EXPECT_CALL(visitor, OnDataForStream(1, _));
-  EXPECT_CALL(visitor, OnFrameHeader(1, 4464, DATA, 0x0));
-  EXPECT_CALL(visitor, OnBeginDataForStream(1, 4464));
-  EXPECT_CALL(visitor, OnDataForStream(1, _));
+  // No further frame data or headers are delivered.
 
   result = adapter->ProcessBytes(more_frames);
   EXPECT_EQ(more_frames.size(), static_cast<size_t>(result));
 
-  EXPECT_FALSE(adapter->want_write());
+  EXPECT_TRUE(adapter->want_write());
+  EXPECT_CALL(visitor, OnBeforeFrameSent(RST_STREAM, 1, 4, 0x0));
+  EXPECT_CALL(
+      visitor,
+      OnFrameSent(RST_STREAM, 1, 4, 0x0,
+                  static_cast<int>(Http2ErrorCode::FLOW_CONTROL_ERROR)));
+  EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::HTTP2_NO_ERROR));
+
+  send_result = adapter->Send();
+  EXPECT_EQ(0, send_result);
+  EXPECT_THAT(visitor.data(), EqualsFrames({SpdyFrameType::RST_STREAM}));
 }
 
 TEST(OgHttp2AdapterTest, ServerErrorWhileHandlingHeaders) {
diff --git a/http2/adapter/oghttp2_session.cc b/http2/adapter/oghttp2_session.cc
index b7016a5..563344b 100644
--- a/http2/adapter/oghttp2_session.cc
+++ b/http2/adapter/oghttp2_session.cc
@@ -1034,6 +1034,23 @@
     return;
   }
 
+  if (static_cast<int64_t>(length) >
+      connection_window_manager_.CurrentWindowSize()) {
+    // Peer exceeded the connection flow control limit.
+    LatchErrorAndNotify(
+        Http2ErrorCode::FLOW_CONTROL_ERROR,
+        Http2VisitorInterface::ConnectionError::kFlowControlError);
+    return;
+  }
+
+  if (static_cast<int64_t>(length) >
+      iter->second.window_manager.CurrentWindowSize()) {
+    // Peer exceeded the stream flow control limit.
+    EnqueueFrame(absl::make_unique<spdy::SpdyRstStreamIR>(
+        stream_id, spdy::ERROR_CODE_FLOW_CONTROL_ERROR));
+    return;
+  }
+
   const bool result = visitor_.OnBeginDataForStream(stream_id, length);
   if (!result) {
     fatal_visitor_callback_failure_ = true;
diff --git a/http2/adapter/oghttp2_session.h b/http2/adapter/oghttp2_session.h
index cdffd4f..6f02d2c 100644
--- a/http2/adapter/oghttp2_session.h
+++ b/http2/adapter/oghttp2_session.h
@@ -402,6 +402,7 @@
 
   void HandleContentLengthError(Http2StreamId stream_id);
 
+  // Invoked when sending a flow control window update to the peer.
   void UpdateReceiveWindow(Http2StreamId stream_id, int32_t delta);
 
   void UpdateInitialWindowSize(uint32_t new_value);