Skip to content

size hpack dynamic table for the 33-byte minimum entry - #3462

Open
ubeddulla wants to merge 2 commits into
apache:masterfrom
ubeddulla:hpack-dynamic-table-underprovision
Open

size hpack dynamic table for the 33-byte minimum entry#3462
ubeddulla wants to merge 2 commits into
apache:masterfrom
ubeddulla:hpack-dynamic-table-underprovision

Conversation

@ubeddulla

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number:

Problem Summary:
IndexTable::Init sizes the HPACK dynamic-table ring buffer as max_size / (32 + 2), assuming every entry is at least 34 bytes. But AddHeader() only requires a non-empty name, so a header with an empty value costs name(1) + value(0) + 32 = 33 bytes (rfc7541 section 4.1). With the default 4096-byte table that leaves room for 124 such entries before eviction fires, while the queue only holds 120, so the 121st AddHeader() from a peer trips CHECK(!_header_queue.full()). That is a fatal log plus stack trace on every crafted HEADERS block, and a process abort when -crash_on_fatal_log is set, all driven straight from HTTP/2 header bytes.

What is changed and the side effects?

Changed:
Provision the queue for the real 33-byte minimum entry (max_size / (32 + 1)) so eviction always fires before the ring buffer fills. Added a regression test that decodes 121 one-byte-name/empty-value indexed headers, which previously tripped the CHECK.

Side effects:

  • Performance effects: negligible, a few more slots in the dynamic-table ring buffer.

  • Breaking backward compatibility: none.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens brpc’s HTTP/2 HPACK dynamic table implementation by sizing the dynamic-table header ring buffer for the RFC7541 minimum 33-byte entry, preventing a peer from triggering a fatal CHECK(!_header_queue.full()) via many small indexed headers.

Changes:

  • Adjust IndexTable::Init capacity calculation from assuming 34-byte minimum entries to the correct 33-byte minimum.
  • Add a regression unit test that decodes 121 minimal (1-byte name, empty value) “literal with incremental indexing” headers to ensure decode does not abort.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/brpc/details/hpack.cpp Fixes dynamic-table queue sizing to avoid ring-buffer overflow before eviction for 33-byte minimum entries.
test/brpc_hpack_unittest.cpp Adds regression coverage for decoding many minimal indexed headers without triggering fatal checks.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

_max_size = UINT_MAX;
} else {
num_headers = options.max_size / (32 + 2);
num_headers = options.max_size / (32 + 1);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Pushed a guard that keeps num_headers at 1 when max_size is below 33 (including the max_size == 0 disable case), so we don't hit malloc(0). Nothing actually lands in that slot since entry_size > _max_size still holds in AddHeader. Added a test that Init(0) succeeds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants