Fix a potential Http2WriteQueue overflow scenario. This CL addresses the overflow scenario described in cl/608648082 by adding two bytes of HPACK per-header overhead when estimating the serialized size in bytes of a HEADERS frame. In particular, the length of a header name will be expected to fit within 2 bytes (vs. 1 byte before), and the length of a header value will be expected to fit within 3 bytes (vs. 2 bytes before). Protected by FLAGS_gfe2_reloadable_flag_http2_add_hpack_overhead_bytes. PiperOrigin-RevId: 610447560
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h index 9c116cb..e565066 100644 --- a/quiche/quic/core/quic_flags_list.h +++ b/quiche/quic/core/quic_flags_list.h
@@ -35,6 +35,8 @@ QUIC_FLAG(quic_reloadable_flag_quic_block_until_settings_received_copt, true) // If trrue, early return before write control frame in OnCanWrite() if the connection is already closed. QUIC_FLAG(quic_reloadable_flag_quic_no_write_control_frame_upon_connection_close, true) +// If true, HTTP/2 HEADERS frames will use two additional bytes of HPACK overhead per header in their SpdyFrameIR::size() estimate. +QUIC_FLAG(quic_reloadable_flag_http2_add_hpack_overhead_bytes, true) // If true, QUIC server will not respond to gQUIC probing packet(PING + PADDING) but treat it as a regular packet. QUIC_FLAG(quic_reloadable_flag_quic_ignore_gquic_probing, true) // If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes.
diff --git a/quiche/spdy/core/spdy_protocol.cc b/quiche/spdy/core/spdy_protocol.cc index fc5f43d..1e5dd9e 100644 --- a/quiche/spdy/core/spdy_protocol.cc +++ b/quiche/spdy/core/spdy_protocol.cc
@@ -15,6 +15,8 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "quiche/common/platform/api/quiche_bug_tracker.h" +#include "quiche/common/platform/api/quiche_flag_utils.h" +#include "quiche/common/platform/api/quiche_flags.h" #include "quiche/common/platform/api/quiche_logging.h" #include "quiche/spdy/core/http2_header_block.h" #include "quiche/spdy/core/spdy_alt_svc_wire_format.h" @@ -473,9 +475,16 @@ size += 5; } + // TODO(b/322146543): Remove `hpack_overhead` with deprecation of + // --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes. + size_t hpack_overhead = kPerHeaderHpackOverheadOld; + if (GetQuicheReloadableFlag(http2, http2_add_hpack_overhead_bytes)) { + QUICHE_RELOADABLE_FLAG_COUNT(http2_add_hpack_overhead_bytes); + hpack_overhead = kPerHeaderHpackOverheadNew; + } // Assume no hpack encoding is applied. - size += header_block().TotalBytesUsed() + - header_block().size() * kPerHeaderHpackOverhead; + size += + header_block().TotalBytesUsed() + header_block().size() * hpack_overhead; if (size > kHttp2MaxControlFrameSendSize) { size += GetNumberRequiredContinuationFrames(size) * kContinuationFrameMinimumSize;
diff --git a/quiche/spdy/core/spdy_protocol.h b/quiche/spdy/core/spdy_protocol.h index 36268b0..8501c94 100644 --- a/quiche/spdy/core/spdy_protocol.h +++ b/quiche/spdy/core/spdy_protocol.h
@@ -331,10 +331,21 @@ inline constexpr int32_t kInitialSessionWindowSize = 64 * 1024 - 1; // The NPN string for HTTP2, "h2". QUICHE_EXPORT extern const char* const kHttp2Npn; +// An estimate of the HPACK overhead for each header field in bytes, intended to +// be no smaller than actual overhead, based on the literal header field +// representation in RFC 7541 Section 6.2 (with or without indexing): +// - 1 byte for the opcode. +// - 2 bytes for the name length (assuming new name). +// - 3 bytes for the value length. +// TODO(b/322146543): Remove the `New` suffix with deprecation of +// --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes. +inline constexpr size_t kPerHeaderHpackOverheadNew = 6; // An estimate size of the HPACK overhead for each header field. 1 bytes for // indexed literal, 1 bytes for key literal and length encoding, and 2 bytes for // value literal and length encoding. -inline constexpr size_t kPerHeaderHpackOverhead = 4; +// TODO(b/322146543): Remove with deprecation of +// --gfe2_reloadable_flag_http2_add_hpack_overhead_bytes. +inline constexpr size_t kPerHeaderHpackOverheadOld = 4; // Names of pseudo-headers defined for HTTP/2 requests. QUICHE_EXPORT extern const char* const kHttp2AuthorityHeader;