Uses the new `HpackEncoder` dynamic table upper bound added in a previous commit. This will only affect behavior for users who set `OgHttp2Session::Options::max_hpack_encoding_table_capacity`. This should fix https://github.com/envoyproxy/envoy/issues/38689. Protected by does not affect the GFE2 binary; not protected. PiperOrigin-RevId: 757879310
diff --git a/quiche/http2/adapter/oghttp2_session.cc b/quiche/http2/adapter/oghttp2_session.cc index 2a5ec62..c25b291 100644 --- a/quiche/http2/adapter/oghttp2_session.cc +++ b/quiche/http2/adapter/oghttp2_session.cc
@@ -187,13 +187,6 @@ return status.size() == 3 && status[0] == '1'; } -// Returns the upper bound on HPACK encoder table capacity. If not specified in -// the Options, a reasonable default upper bound is used. -uint32_t HpackCapacityBound(const OgHttp2Session::Options& o) { - return o.max_hpack_encoding_table_capacity.value_or( - kMaximumHpackTableCapacity); -} - bool IsNonAckSettings(const spdy::SpdyFrameIR& frame) { return frame.frame_type() == spdy::SpdyFrameType::SETTINGS && !reinterpret_cast<const SpdySettingsIR&>(frame).is_ack(); @@ -381,7 +374,7 @@ max_outbound_concurrent_streams_( options.remote_max_concurrent_streams.value_or(100u)) { decoder_.set_visitor(&receive_logger_); - if (options_.max_header_list_bytes) { + if (options_.max_header_list_bytes.has_value()) { // Limit buffering of encoded HPACK data to 2x the decoded limit. decoder_.GetHpackDecoder().set_max_decode_buffer_size_bytes( 2 * *options_.max_header_list_bytes); @@ -389,9 +382,9 @@ decoder_.GetHpackDecoder().set_max_header_block_bytes( 4 * *options_.max_header_list_bytes); } - if (IsServerSession()) { - remaining_preface_ = {spdy::kHttp2ConnectionHeaderPrefix, - spdy::kHttp2ConnectionHeaderPrefixSize}; + if (options_.max_hpack_encoding_table_capacity.has_value()) { + framer_.GetHpackEncoder()->SetHeaderTableSizeBound( + *options_.max_hpack_encoding_table_capacity); } if (options_.max_header_field_size.has_value()) { headers_handler_.SetMaxFieldSize(*options_.max_header_field_size); @@ -402,6 +395,10 @@ // endpoints don't properly handle multiple `Cookie` header fields. framer_.GetHpackEncoder()->DisableCookieCrumbling(); } + if (IsServerSession()) { + remaining_preface_ = {spdy::kHttp2ConnectionHeaderPrefix, + spdy::kHttp2ConnectionHeaderPrefixSize}; + } } OgHttp2Session::~OgHttp2Session() {} @@ -1309,7 +1306,7 @@ void OgHttp2Session::OnSetting(spdy::SpdySettingsId id, uint32_t value) { switch (id) { case HEADER_TABLE_SIZE: - value = std::min(value, HpackCapacityBound(options_)); + value = std::min(value, kMaximumHpackTableCapacity); if (value < framer_.GetHpackEncoder()->CurrentHeaderTableSizeSetting()) { // Safe to apply a smaller table capacity immediately. QUICHE_VLOG(3) << TracePerspectiveAsString(options_.perspective)
diff --git a/quiche/http2/adapter/oghttp2_session_test.cc b/quiche/http2/adapter/oghttp2_session_test.cc index 58da30e..34a387b 100644 --- a/quiche/http2/adapter/oghttp2_session_test.cc +++ b/quiche/http2/adapter/oghttp2_session_test.cc
@@ -395,8 +395,8 @@ true, nullptr); int result = session.Send(); ASSERT_EQ(result, 0); - // BUG: the encoder table size should not have grown beyond zero. - EXPECT_LT(0, session.GetHpackEncoderDynamicTableSize()); + // The encoder table size should not have grown beyond zero. + EXPECT_EQ(session.GetHpackEncoderDynamicTableSize(), 0); } TEST(OgHttp2SessionTest, ClientSubmitRequestWithLargePayload) { @@ -801,6 +801,32 @@ EXPECT_THAT(visitor.data(), EqualsFrames({SpdyFrameType::SETTINGS})); } +// Demonstrates that the dynamic table size setting interpreted from the peer +// won't exceed the hardcoded 64kB upper bound. +TEST(OgHttp2SessionTest, ServerDynamicTableSizeAboveUpperBound) { + TestVisitor visitor; + OgHttp2Session::Options options; + options.perspective = Perspective::kServer; + OgHttp2Session session(visitor, options); + + const std::string frames = + TestFrameSequence() + .ClientPreface({{HEADER_TABLE_SIZE, 100u * 1024u}}) + .Serialize(); + testing::InSequence s; + + // Client preface (empty SETTINGS) + EXPECT_CALL(visitor, OnFrameHeader(0, 6, SETTINGS, 0)); + EXPECT_CALL(visitor, OnSettingsStart()); + // Although the peer adverised 100kB, the server interprets the setting value + // with a 64kB upper bound. + EXPECT_CALL(visitor, OnSetting(Http2Setting{HEADER_TABLE_SIZE, 64u * 1024u})); + EXPECT_CALL(visitor, OnSettingsEnd()); + + const int64_t result = session.ProcessBytes(frames); + EXPECT_EQ(frames.size(), static_cast<size_t>(result)); +} + TEST(OgHttp2SessionTest, ServerSubmitResponse) { TestVisitor visitor; OgHttp2Session::Options options;