Adds unit test cases covering the case where a content-length undershoot causes a PROTOCOL_ERROR.

Both nghttp2 and oghttp2 appear to treat this case the same.

PiperOrigin-RevId: 701960516
diff --git a/quiche/http2/adapter/nghttp2_adapter_test.cc b/quiche/http2/adapter/nghttp2_adapter_test.cc
index 99cab9e..8eaff06 100644
--- a/quiche/http2/adapter/nghttp2_adapter_test.cc
+++ b/quiche/http2/adapter/nghttp2_adapter_test.cc
@@ -7519,6 +7519,12 @@
                        {":path", "/this/is/request/one"},
                        {"content-length", "4"}})
           .Data(1, "ok", /*fin=*/false)
+          .Headers(3, {{":method", "GET"},
+                       {":scheme", "https"},
+                       {":authority", "example.com"},
+                       {":path", "/this/is/request/three"},
+                       {"content-length", "4"}})
+          .Data(3, "ok", /*fin=*/false)
           .Serialize();
 
   // Client preface (empty SETTINGS)
@@ -7526,7 +7532,7 @@
   EXPECT_CALL(visitor, OnSettingsStart());
   EXPECT_CALL(visitor, OnSettingsEnd());
 
-  // Stream 1: content-length is smaller than actual data, but not yet
+  // Stream 1
   // Headers and the beginning of data is delivered to the visitor.
   EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
   EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
@@ -7536,6 +7542,16 @@
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 2));
   EXPECT_CALL(visitor, OnDataForStream(1, _));
 
+  // Stream 3
+  // Headers and the beginning of data is delivered to the visitor.
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 4));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(3));
+  EXPECT_CALL(visitor, OnFrameHeader(3, 2, DATA, 0));
+  EXPECT_CALL(visitor, OnBeginDataForStream(3, 2));
+  EXPECT_CALL(visitor, OnDataForStream(3, _));
+
   const int64_t stream_result = adapter->ProcessBytes(stream_frames);
   EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
 
@@ -7544,23 +7560,34 @@
       1, "Here is some response data, and there will be more. ");
   adapter->SubmitResponse(1, ToHeaders({{":status", "200"}}), false);
 
+  // Initial response data for stream 3.
+  visitor.AppendPayloadForStream(
+      3, "Here is some response data, and there will be more. ");
+  adapter->SubmitResponse(3, ToHeaders({{":status", "200"}}), false);
+
   // Server preface (SETTINGS)
   EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
   EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
   // SETTINGS ack
   EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, ACK_FLAG));
   EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, ACK_FLAG, 0));
-  // Stream 1, with some DATA
+  // Stream 1 HEADERS
   EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 1, _, 0x4));
   EXPECT_CALL(visitor, OnFrameSent(HEADERS, 1, _, 0x4, 0));
+  // Stream 3 HEADERS
+  EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 3, _, 0x4));
+  EXPECT_CALL(visitor, OnFrameSent(HEADERS, 3, _, 0x4, 0));
+  // DATA
   EXPECT_CALL(visitor, OnFrameSent(DATA, 1, _, 0x0, 0));
+  EXPECT_CALL(visitor, OnFrameSent(DATA, 3, _, 0x0, 0));
 
   EXPECT_TRUE(adapter->want_write());
   int result = adapter->Send();
   EXPECT_EQ(0, result);
   EXPECT_THAT(visitor.data(),
               EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::SETTINGS,
-                            SpdyFrameType::HEADERS, SpdyFrameType::DATA}));
+                            SpdyFrameType::HEADERS, SpdyFrameType::HEADERS,
+                            SpdyFrameType::DATA, SpdyFrameType::DATA}));
 
   visitor.Clear();
 
@@ -7569,14 +7596,28 @@
   visitor.SetEndData(1, true);
   adapter->ResumeStream(1);
 
-  const std::string client_fin =
-      TestFrameSequence().Data(1, "ay!", /*fin=*/true).Serialize();
+  // Final response data and fin for stream 3.
+  visitor.AppendPayloadForStream(3, "Last data!");
+  visitor.SetEndData(3, true);
+  adapter->ResumeStream(3);
+
+  // Stream 1: actual data overshoots the content-length from request headers.
+  // Stream 3: actual data undershoots the content-length from request headers.
+  const std::string client_fin = TestFrameSequence()
+                                     .Data(1, "ay!", /*fin=*/true)
+                                     .Data(3, "", /*fin=*/true)
+                                     .Serialize();
 
   // The library does not deliver the actual data or fin from the client to the
   // visitor.
   EXPECT_CALL(visitor, OnFrameHeader(1, 3, DATA, 0x1));
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 3));
 
+  // The library does not deliver the actual data or fin from the client to the
+  // visitor.
+  EXPECT_CALL(visitor, OnFrameHeader(3, 0, DATA, 0x1));
+  EXPECT_CALL(visitor, OnBeginDataForStream(3, 0));
+
   const int64_t fin_result = adapter->ProcessBytes(client_fin);
   ASSERT_EQ(client_fin.size(), fin_result);
 
@@ -7586,6 +7627,13 @@
               OnFrameSent(RST_STREAM, 1, _, 0x0,
                           static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
   EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::PROTOCOL_ERROR));
+  // The library sends the RST_STREAM but not the end of data.
+  EXPECT_CALL(visitor, OnBeforeFrameSent(RST_STREAM, 3, _, 0x0));
+  EXPECT_CALL(visitor,
+              OnFrameSent(RST_STREAM, 3, _, 0x0,
+                          static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
+  EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::PROTOCOL_ERROR));
+
   result = adapter->Send();
   EXPECT_EQ(0, result);
 }
diff --git a/quiche/http2/adapter/oghttp2_adapter_test.cc b/quiche/http2/adapter/oghttp2_adapter_test.cc
index bf11371..d692c4b 100644
--- a/quiche/http2/adapter/oghttp2_adapter_test.cc
+++ b/quiche/http2/adapter/oghttp2_adapter_test.cc
@@ -8296,6 +8296,12 @@
                        {":path", "/this/is/request/one"},
                        {"content-length", "4"}})
           .Data(1, "ok", /*fin=*/false)
+          .Headers(3, {{":method", "GET"},
+                       {":scheme", "https"},
+                       {":authority", "example.com"},
+                       {":path", "/this/is/request/three"},
+                       {"content-length", "4"}})
+          .Data(3, "ok", /*fin=*/false)
           .Serialize();
 
   // Client preface (empty SETTINGS)
@@ -8303,7 +8309,7 @@
   EXPECT_CALL(visitor, OnSettingsStart());
   EXPECT_CALL(visitor, OnSettingsEnd());
 
-  // Stream 1: content-length is smaller than actual data, but not yet
+  // Stream 1
   // Headers and the beginning of data is delivered to the visitor.
   EXPECT_CALL(visitor, OnFrameHeader(1, _, HEADERS, 4));
   EXPECT_CALL(visitor, OnBeginHeadersForStream(1));
@@ -8313,6 +8319,16 @@
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 2));
   EXPECT_CALL(visitor, OnDataForStream(1, _));
 
+  // Stream 3
+  // Headers and the beginning of data is delivered to the visitor.
+  EXPECT_CALL(visitor, OnFrameHeader(3, _, HEADERS, 4));
+  EXPECT_CALL(visitor, OnBeginHeadersForStream(3));
+  EXPECT_CALL(visitor, OnHeaderForStream(3, _, _)).Times(5);
+  EXPECT_CALL(visitor, OnEndHeadersForStream(3));
+  EXPECT_CALL(visitor, OnFrameHeader(3, 2, DATA, 0));
+  EXPECT_CALL(visitor, OnBeginDataForStream(3, 2));
+  EXPECT_CALL(visitor, OnDataForStream(3, _));
+
   const int64_t stream_result = adapter->ProcessBytes(stream_frames);
   EXPECT_EQ(stream_frames.size(), static_cast<size_t>(stream_result));
 
@@ -8321,23 +8337,34 @@
       1, "Here is some response data, and there will be more. ");
   adapter->SubmitResponse(1, ToHeaders({{":status", "200"}}), false);
 
+  // Initial response data for stream 3.
+  visitor.AppendPayloadForStream(
+      3, "Here is some response data, and there will be more. ");
+  adapter->SubmitResponse(3, ToHeaders({{":status", "200"}}), false);
+
   // Server preface (SETTINGS)
   EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0));
   EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0));
   // SETTINGS ack
   EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, ACK_FLAG));
   EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, ACK_FLAG, 0));
-  // Stream 1, with some DATA
+  // Stream 1 HEADERS
   EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 1, _, 0x4));
   EXPECT_CALL(visitor, OnFrameSent(HEADERS, 1, _, 0x4, 0));
+  // Stream 3 HEADERS
+  EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, 3, _, 0x4));
+  EXPECT_CALL(visitor, OnFrameSent(HEADERS, 3, _, 0x4, 0));
+  // DATA
   EXPECT_CALL(visitor, OnFrameSent(DATA, 1, _, 0x0, 0));
+  EXPECT_CALL(visitor, OnFrameSent(DATA, 3, _, 0x0, 0));
 
   EXPECT_TRUE(adapter->want_write());
   int result = adapter->Send();
   EXPECT_EQ(0, result);
   EXPECT_THAT(visitor.data(),
               EqualsFrames({SpdyFrameType::SETTINGS, SpdyFrameType::SETTINGS,
-                            SpdyFrameType::HEADERS, SpdyFrameType::DATA}));
+                            SpdyFrameType::HEADERS, SpdyFrameType::HEADERS,
+                            SpdyFrameType::DATA, SpdyFrameType::DATA}));
 
   visitor.Clear();
 
@@ -8346,14 +8373,28 @@
   visitor.SetEndData(1, true);
   adapter->ResumeStream(1);
 
-  const std::string client_fin =
-      TestFrameSequence().Data(1, "ay!", /*fin=*/true).Serialize();
+  // Final response data and fin for stream 3.
+  visitor.AppendPayloadForStream(3, "Last data!");
+  visitor.SetEndData(3, true);
+  adapter->ResumeStream(3);
+
+  // Stream 1: actual data overshoots the content-length from request headers.
+  // Stream 3: actual data undershoots the content-length from request headers.
+  const std::string client_fin = TestFrameSequence()
+                                     .Data(1, "ay!", /*fin=*/true)
+                                     .Data(3, "", /*fin=*/true)
+                                     .Serialize();
 
   // The library does not deliver the actual data or fin from the client to the
   // visitor.
   EXPECT_CALL(visitor, OnFrameHeader(1, 3, DATA, 0x1));
   EXPECT_CALL(visitor, OnBeginDataForStream(1, 3));
 
+  // The library does not deliver the actual data or fin from the client to the
+  // visitor.
+  EXPECT_CALL(visitor, OnFrameHeader(3, 0, DATA, 0x1));
+  EXPECT_CALL(visitor, OnBeginDataForStream(3, 0));
+
   const int64_t fin_result = adapter->ProcessBytes(client_fin);
   ASSERT_EQ(client_fin.size(), fin_result);
 
@@ -8363,6 +8404,13 @@
               OnFrameSent(RST_STREAM, 1, _, 0x0,
                           static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
   EXPECT_CALL(visitor, OnCloseStream(1, Http2ErrorCode::HTTP2_NO_ERROR));
+  // The library sends the RST_STREAM but not the end of data.
+  EXPECT_CALL(visitor, OnBeforeFrameSent(RST_STREAM, 3, _, 0x0));
+  EXPECT_CALL(visitor,
+              OnFrameSent(RST_STREAM, 3, _, 0x0,
+                          static_cast<int>(Http2ErrorCode::PROTOCOL_ERROR)));
+  EXPECT_CALL(visitor, OnCloseStream(3, Http2ErrorCode::HTTP2_NO_ERROR));
+
   result = adapter->Send();
   EXPECT_EQ(0, result);
 }