Parse subscribe counts for long channel names

Extract subscription counts from the response tail to avoid truncation.

Adds pubsub_long_name test and runs it in the harness.
This commit is contained in:
Julien Letessier 2026-01-15 09:13:09 +01:00
parent 220772824c
commit c73d4056e2
3 changed files with 79 additions and 8 deletions

View File

@ -41,14 +41,18 @@ SubscribeParser::Status SubscribeParser::parse(const Segment& body, int& chs)
st = String;
}
if (chs < 0) {
if (!str.complete()) {
int len = body.length();
int tailLen = len < 64 ? len : 64;
Segment tmp(body);
tmp.rewind();
tmp.cut(body.length() - 12);
str.set(tmp);
if (len > tailLen) {
tmp.use(len - tailLen);
}
const char* p = str.data() + str.length();
for (int i = 0; i < str.length(); ++i) {
char buf[64 + 1];
int n = tmp.dump(buf, tailLen);
buf[n] = '\0';
const char* p = buf + n;
while (p > buf) {
if (*--p == ':') {
chs = atoi(p + 1);
break;

65
test/pubsub_long_name.py Normal file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
#
# Verify subscribe/psubscribe confirmation with long channel/pattern names
#
import argparse
import sys
import redis
def normalize_bytes(value):
if isinstance(value, bytes):
return value.decode("utf-8")
return value
def run_test(host, port):
long_name = "ch_" + ("x" * 200)
pattern = long_name + "*"
c1 = redis.StrictRedis(host=host, port=port)
ps = c1.pubsub()
ps.subscribe(long_name)
msg = ps.get_message(timeout=1.0)
if not msg or msg.get("type") != "subscribe":
print("FAIL: subscribe confirmation missing:", msg)
return False
if normalize_bytes(msg.get("channel")) != long_name:
print("FAIL: subscribe channel mismatch:", msg)
return False
if msg.get("data") != 1:
print("FAIL: subscribe count mismatch:", msg)
return False
ps.psubscribe(pattern)
msg = ps.get_message(timeout=1.0)
if not msg or msg.get("type") != "psubscribe":
print("FAIL: psubscribe confirmation missing:", msg)
return False
if normalize_bytes(msg.get("channel")) != pattern:
print("FAIL: psubscribe channel mismatch:", msg)
return False
if msg.get("data") != 2:
print("FAIL: psubscribe count mismatch:", msg)
return False
return True
if __name__ == "__main__":
parser = argparse.ArgumentParser(conflict_handler='resolve', description="Long pubsub name test")
parser.add_argument("-h", "--host", default="127.0.0.1")
parser.add_argument("-p", "--port", type=int, default=7617)
args = parser.parse_args()
if run_test(args.host, args.port):
print("PASS: long pubsub name")
sys.exit(0)
print("FAIL: long pubsub name")
sys.exit(1)

View File

@ -63,6 +63,7 @@ PUBSUB_MESSAGE_EXIT=0
PUBSUB_ORDER_EXIT=0
PUBSUB_RESET_EXIT=0
NULL_RESPONSE_EXIT=0
PUBSUB_LONG_EXIT=0
uv run python3 test/basic.py || BASIC_EXIT=$?
uv run python3 test/pubsub_minimal.py -p 7617 || PUBSUB_REDIS_EXIT=$?
@ -70,8 +71,9 @@ uv run python3 test/pubsub_minimal.py -p 6379 || PUBSUB_MINIMAL_EXIT=$?
uv run python3 test/pubsub.py || PUBSUB_EXIT=$?
uv run python3 test/pubsub_subscription_order.py -p 7617 || PUBSUB_ORDER_EXIT=$?
uv run python3 test/pubsub_parser_reset.py -p 7617 || PUBSUB_RESET_EXIT=$?
uv run python3 test/pubsub_long_name.py -p 7617 || PUBSUB_LONG_EXIT=$?
uv run python3 test/null_response_handling.py -p 7617 || NULL_RESPONSE_EXIT=$?
uv run python3 test/pubsub_message_response.py -p 7617 || PUBSUB_MESSAGE_EXIT=$?
TEST_EXIT=$((BASIC_EXIT + PUBSUB_REDIS_EXIT + PUBSUB_MINIMAL_EXIT + PUBSUB_EXIT + PUBSUB_MESSAGE_EXIT + PUBSUB_ORDER_EXIT + PUBSUB_RESET_EXIT + NULL_RESPONSE_EXIT))
TEST_EXIT=$((BASIC_EXIT + PUBSUB_REDIS_EXIT + PUBSUB_MINIMAL_EXIT + PUBSUB_EXIT + PUBSUB_MESSAGE_EXIT + PUBSUB_ORDER_EXIT + PUBSUB_RESET_EXIT + NULL_RESPONSE_EXIT + PUBSUB_LONG_EXIT))
exit $TEST_EXIT