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 17258960 Fix HPACK dynamic table size update recursive decoding (#3343)
17258960 is described below
commit 172589604ffbb5c970b9bcd3c1df0441a9614dd6
Author: Weibing Wang <[email protected]>
AuthorDate: Sun Jun 14 18:56:24 2026 +0800
Fix HPACK dynamic table size update recursive decoding (#3343)
---
src/brpc/details/hpack.cpp | 19 ++++++++----
test/brpc_hpack_unittest.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/src/brpc/details/hpack.cpp b/src/brpc/details/hpack.cpp
index 687a6145..e4e7890e 100644
--- a/src/brpc/details/hpack.cpp
+++ b/src/brpc/details/hpack.cpp
@@ -763,6 +763,8 @@ inline ssize_t HPacker::DecodeWithKnownPrefix(
}
ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter, Header* h) {
+ ssize_t skipped_bytes = 0;
+decode_next:
if (iter == NULL) {
return 0;
}
@@ -791,7 +793,7 @@ ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter,
Header* h) {
return -1;
}
*h = *indexed_header;
- return index_bytes;
+ return skipped_bytes + index_bytes;
}
break;
case 7:
@@ -806,7 +808,7 @@ ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter,
Header* h) {
return -1;
}
_decode_table->AddHeader(*h);
- return bytes_consumed;
+ return skipped_bytes + bytes_consumed;
}
break;
case 3:
@@ -824,17 +826,24 @@ ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter,
Header* h) {
return -1;
}
_decode_table->ResetMaxSize(max_size);
- return Decode(iter, h);
+ skipped_bytes += read_bytes;
+ goto decode_next;
}
case 1:
// (0001) Literal Header Field Never Indexed
// https://tools.ietf.org/html/rfc7541#section-6.2.3
- return DecodeWithKnownPrefix(iter, h, 4);
+ {
+ const ssize_t bytes_consumed = DecodeWithKnownPrefix(iter, h, 4);
+ return bytes_consumed > 0 ? skipped_bytes + bytes_consumed :
bytes_consumed;
+ }
// TODO: Expose NeverIndex to the caller.
case 0:
// (0000) Literal Header Field without Indexing
// https://tools.ietf.org/html/rfc7541#section-6.2.1
- return DecodeWithKnownPrefix(iter, h, 4);
+ {
+ const ssize_t bytes_consumed = DecodeWithKnownPrefix(iter, h, 4);
+ return bytes_consumed > 0 ? skipped_bytes + bytes_consumed :
bytes_consumed;
+ }
// TODO: Expose NeverIndex to the caller.
default:
CHECK(false) << "Can't reach here";
diff --git a/test/brpc_hpack_unittest.cpp b/test/brpc_hpack_unittest.cpp
index f30a7128..d6a0bd02 100644
--- a/test/brpc_hpack_unittest.cpp
+++ b/test/brpc_hpack_unittest.cpp
@@ -20,12 +20,82 @@
// Date: 2017/04/25 00:23:12
#include <gtest/gtest.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include "brpc/details/hpack.h"
#include "butil/logging.h"
class HPackTest : public testing::Test {
};
+static void* DecodeManyDynamicTableSizeUpdates(void*) {
+ brpc::HPacker p;
+ if (p.Init(4096) != 0) {
+ return (void*)1;
+ }
+
+ butil::IOBuf buf;
+ std::string updates(200000, '\x20');
+ buf.append(updates);
+
+ brpc::HPacker::Header h;
+ return (void*)(p.Decode(&buf, &h) != 0);
+}
+
+TEST_F(HPackTest, many_dynamic_table_size_updates) {
+ const pid_t pid = fork();
+ ASSERT_GE(pid, 0);
+ if (pid == 0) {
+ if (freopen("/dev/null", "w", stdout) == NULL ||
+ freopen("/dev/null", "w", stderr) == NULL) {
+ exit(1);
+ }
+
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr) != 0) {
+ exit(2);
+ }
+ if (pthread_attr_setstacksize(&attr, 64 * 1024) != 0) {
+ exit(3);
+ }
+ pthread_t tid;
+ if (pthread_create(&tid, &attr, DecodeManyDynamicTableSizeUpdates,
NULL) != 0) {
+ exit(4);
+ }
+ pthread_attr_destroy(&attr);
+ void* ret = NULL;
+ if (pthread_join(tid, &ret) != 0) {
+ exit(5);
+ }
+ exit(ret == NULL ? 0 : 6);
+ }
+ int status = 0;
+ ASSERT_EQ(pid, waitpid(pid, &status, 0));
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(0, WEXITSTATUS(status));
+}
+
+TEST_F(HPackTest, dynamic_table_size_update_before_header) {
+ brpc::HPacker p;
+ ASSERT_EQ(0, p.Init(4096));
+
+ butil::IOBuf buf;
+ uint8_t encoded[] = {
+ 0x20, // Dynamic table size update to 0.
+ 0x82, // Indexed :method: GET.
+ };
+ buf.append(encoded, sizeof(encoded));
+
+ brpc::HPacker::Header h;
+ ASSERT_EQ((ssize_t)sizeof(encoded), p.Decode(&buf, &h));
+ ASSERT_TRUE(buf.empty());
+ ASSERT_EQ(":method", h.name);
+ ASSERT_EQ("GET", h.value);
+}
+
// Copied test cases from example of rfc7541
TEST_F(HPackTest, header_with_indexing) {
brpc::HPacker p1;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]