This is an automated email from the ASF dual-hosted git repository.

wwbmmm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new a5c3365a size hpack dynamic table for the 33-byte minimum entry (#3462)
a5c3365a is described below

commit a5c3365af1902caf0158975363868d99f5705bfa
Author: UB <[email protected]>
AuthorDate: Sat Aug 22 09:39:36 2026 +0530

    size hpack dynamic table for the 33-byte minimum entry (#3462)
    
    * size hpack dynamic table for the 33-byte minimum entry
    
    * keep at least one dynamic-table slot when max_size < 33
---
 src/brpc/details/hpack.cpp   | 16 ++++++++++++++--
 test/brpc_hpack_unittest.cpp | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/src/brpc/details/hpack.cpp b/src/brpc/details/hpack.cpp
index c9c707c9..7a7bb366 100644
--- a/src/brpc/details/hpack.cpp
+++ b/src/brpc/details/hpack.cpp
@@ -223,11 +223,23 @@ int IndexTable::Init(const IndexTableOptions& options) {
         num_headers = options.static_table_size;
         _max_size = UINT_MAX;
     } else {
-        num_headers = options.max_size / (32 + 2);
+        num_headers = options.max_size / (32 + 1);
         //                                     ^
-        // name and value both have at least one byte in.
+        // AddHeader() only requires a non-empty name; the value may be empty,
+        // so the smallest possible entry is name(1) + value(0) + 32 = 33 bytes
+        // (rfc7541 section 4.1). Sizing the queue for 34-byte entries under-
+        // provisions it and lets a peer sending many 33-byte entries fill the
+        // queue before eviction triggers, tripping CHECK(!full()) in 
AddHeader.
         _max_size = options.max_size;
     }
+    // A dynamic table smaller than the 33-byte minimum entry (including the
+    // valid max_size == 0 case that disables it) yields num_headers == 0.
+    // malloc(0) may return NULL and make Init fail on some platforms, so keep
+    // at least one slot. No entry can actually be stored since entry_size >
+    // _max_size still holds in AddHeader().
+    if (num_headers == 0) {
+        num_headers = 1;
+    }
     void *header_queue_storage = malloc(num_headers * sizeof(Header));
     if (!header_queue_storage) {
         LOG(ERROR) << "Fail to malloc space for " << num_headers << " headers";
diff --git a/test/brpc_hpack_unittest.cpp b/test/brpc_hpack_unittest.cpp
index 98d86648..191bf003 100644
--- a/test/brpc_hpack_unittest.cpp
+++ b/test/brpc_hpack_unittest.cpp
@@ -639,3 +639,37 @@ TEST_F(HPackTest, responses_with_huffman) {
     }
     ASSERT_TRUE(buf.buf().empty());
 }
+
+TEST_F(HPackTest, many_small_indexed_headers) {
+    // Each entry below is a "literal header field with incremental indexing"
+    // (0x40) with a 1-byte name ("a") and an empty value, costing
+    // name(1) + value(0) + 32 = 33 bytes in the dynamic table (rfc7541 4.1).
+    // 121 of them stay under the default 4096-byte table (121*33 = 3993) so
+    // none are evicted and all must decode. The decode table's ring buffer was
+    // previously sized for 34-byte entries (4096/34 = 120), so the 121st
+    // AddHeader() tripped CHECK(!full()) and aborted the process.
+    brpc::HPacker p;
+    ASSERT_EQ(0, p.Init(4096));
+
+    const int num_headers = 121;
+    butil::IOBuf buf;
+    for (int i = 0; i < num_headers; ++i) {
+        const uint8_t entry[] = {0x40, 0x01, (uint8_t)'a', 0x00};
+        buf.append(entry, sizeof(entry));
+    }
+    for (int i = 0; i < num_headers; ++i) {
+        brpc::HPacker::Header h;
+        ASSERT_GT(p.Decode(&buf, &h), 0) << "failed at header " << i;
+        ASSERT_EQ("a", h.name);
+        ASSERT_TRUE(h.value.empty());
+    }
+    ASSERT_TRUE(buf.empty());
+}
+
+TEST_F(HPackTest, zero_size_dynamic_table) {
+    // max_size == 0 disables the dynamic table. num_headers then rounds down 
to
+    // 0, and malloc(0) may return NULL, so Init must still keep one slot and
+    // succeed. No entry is ever stored because entry_size > max_size.
+    brpc::HPacker p;
+    ASSERT_EQ(0, p.Init(0));
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to