Removes the QUICHE_BUG that limits HTTP/2 DATA frame payload sizes to 16kB. This should fix the fuzz test failure found in b/266766513. PiperOrigin-RevId: 505787095
diff --git a/quiche/http2/adapter/oghttp2_session_test.cc b/quiche/http2/adapter/oghttp2_session_test.cc index f536cd7..2953f1e 100644 --- a/quiche/http2/adapter/oghttp2_session_test.cc +++ b/quiche/http2/adapter/oghttp2_session_test.cc
@@ -324,6 +324,82 @@ kInitialFlowControlWindowSize); } +TEST(OgHttp2SessionTest, ClientSubmitRequestWithLargePayload) { + DataSavingVisitor visitor; + OgHttp2Session::Options options; + options.perspective = Perspective::kClient; + OgHttp2Session session(visitor, options); + + EXPECT_FALSE(session.want_write()); + + EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x0)); + EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x0, 0)); + + // Even though the user has not queued any frames for the session, it should + // still send the connection preface. + int result = session.Send(); + EXPECT_EQ(0, result); + absl::string_view serialized = visitor.data(); + EXPECT_THAT(serialized, + testing::StartsWith(spdy::kHttp2ConnectionHeaderPrefix)); + serialized.remove_prefix(strlen(spdy::kHttp2ConnectionHeaderPrefix)); + // Initial SETTINGS. + EXPECT_THAT(serialized, EqualsFrames({SpdyFrameType::SETTINGS})); + visitor.Clear(); + + const std::string initial_frames = + TestFrameSequence() + .ServerPreface( + {Http2Setting{Http2KnownSettingsId::MAX_FRAME_SIZE, 32768u}}) + .Serialize(); + testing::InSequence s; + + // Server preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 6, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + EXPECT_CALL(visitor, OnSetting(Http2Setting{ + Http2KnownSettingsId::MAX_FRAME_SIZE, 32768u})); + EXPECT_CALL(visitor, OnSettingsEnd()); + + const int64_t initial_result = session.ProcessBytes(initial_frames); + EXPECT_EQ(initial_frames.size(), static_cast<size_t>(initial_result)); + + // Session will want to write a SETTINGS ack. + EXPECT_TRUE(session.want_write()); + + EXPECT_CALL(visitor, OnBeforeFrameSent(SETTINGS, 0, _, 0x1)); + EXPECT_CALL(visitor, OnFrameSent(SETTINGS, 0, _, 0x1, 0)); + + result = session.Send(); + EXPECT_EQ(0, result); + EXPECT_THAT(visitor.data(), EqualsFrames({SpdyFrameType::SETTINGS})); + visitor.Clear(); + + auto body1 = std::make_unique<TestDataFrameSource>(visitor, true); + body1->AppendPayload(std::string(20000, 'a')); + body1->EndData(); + int stream_id = + session.SubmitRequest(ToHeaders({{":method", "POST"}, + {":scheme", "http"}, + {":authority", "example.com"}, + {":path", "/this/is/request/one"}}), + std::move(body1), nullptr); + EXPECT_GT(stream_id, 0); + EXPECT_TRUE(session.want_write()); + + EXPECT_CALL(visitor, OnBeforeFrameSent(HEADERS, stream_id, _, 0x4)); + EXPECT_CALL(visitor, OnFrameSent(HEADERS, stream_id, _, 0x4, 0)); + // Single DATA frame with fin, indicating all 20k bytes fit in one frame. + EXPECT_CALL(visitor, OnFrameSent(DATA, stream_id, _, 0x1, 0)); + + result = session.Send(); + EXPECT_EQ(0, result); + EXPECT_THAT(visitor.data(), EqualsFrames({spdy::SpdyFrameType::HEADERS, + spdy::SpdyFrameType::DATA})); + visitor.Clear(); + EXPECT_FALSE(session.want_write()); +} + // This test exercises the case where the client request body source is read // blocked. TEST(OgHttp2SessionTest, ClientSubmitRequestWithReadBlock) {
diff --git a/quiche/spdy/core/spdy_frame_builder.cc b/quiche/spdy/core/spdy_frame_builder.cc index c0558ac..be6885e 100644 --- a/quiche/spdy/core/spdy_frame_builder.cc +++ b/quiche/spdy/core/spdy_frame_builder.cc
@@ -88,8 +88,10 @@ uint8_t raw_frame_type = SerializeFrameType(type); QUICHE_DCHECK(IsDefinedFrameType(raw_frame_type)); QUICHE_DCHECK_EQ(0u, stream_id & ~kStreamIdMask); - QUICHE_BUG_IF(spdy_bug_73_2, length > kHttp2DefaultFramePayloadLimit) - << "Frame length " << length_ << " is longer than frame size limit."; + // From https://www.rfc-editor.org/rfc/rfc9113#name-frame-size + const size_t kProtocolFrameSizeLimit = (1 << 24) - 1; + QUICHE_BUG_IF(spdy_bug_73_2, length > kProtocolFrameSizeLimit) + << "Frame length " << length << " is longer than frame size limit."; return BeginNewFrameInternal(raw_frame_type, flags, stream_id, length); }