From abfb0cd8aea0fcaf3eda0cb9fbdbe2d8b9300507 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 24 May 2026 20:22:34 -0400 Subject: [PATCH] Claude: RTMP: Fix 3-byte chunk basic header decode in proxy. readBasicHeader overwrote cid with the 2-byte form (64 + byte2) before testing whether the 3-byte form was in use, so the `cid == 1` check could never be true and the 3-byte branch was dead code. Chunk basic headers with marker == 1 (chunk stream IDs 320-65599) consumed only one of the two trailing bytes, leaving the high-order byte in the stream and desyncing the chunk parser. Keep the original marker before cid is overwritten and branch on it, matching the C++ reference (srs_protocol_rtmp_stack.cpp, read_basic_header). The arithmetic inside the branch was already correct. Also correct the unit test, which had encoded the buggy result (expected cid=65 instead of 577, leaving a byte unread); it now guards the 3-byte path. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/rtmp/rtmp.go | 7 ++++++- internal/rtmp/rtmp_test.go | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/rtmp/rtmp.go b/internal/rtmp/rtmp.go index 2eaa12cbe..29826f46b 100644 --- a/internal/rtmp/rtmp.go +++ b/internal/rtmp/rtmp.go @@ -714,6 +714,11 @@ func (v *protocol) readBasicHeader(ctx context.Context) (format formatType, cid return } + // Here cid is 0 or 1: a marker selecting the 2B or 3B form, not the real cid. Keep it, + // because cid is overwritten below and the marker decides whether a third byte (the + // high-order part of the cid) follows. Do not test the overwritten cid for this. + marker := cid + // 64-319, 2B chunk header if err = binary.Read(v.r, binary.BigEndian, &t); err != nil { return format, cid, errors.Wrapf(err, "read basic header for cid=%v", cid) @@ -721,7 +726,7 @@ func (v *protocol) readBasicHeader(ctx context.Context) (format formatType, cid cid = chunkID(64 + uint32(t)) // 64-65599, 3B chunk header - if cid == 1 { + if marker == 1 { if err = binary.Read(v.r, binary.BigEndian, &t); err != nil { return format, cid, errors.Wrapf(err, "read basic header for cid=%v", cid) } diff --git a/internal/rtmp/rtmp_test.go b/internal/rtmp/rtmp_test.go index 09dc4c5f4..b23268842 100644 --- a/internal/rtmp/rtmp_test.go +++ b/internal/rtmp/rtmp_test.go @@ -98,7 +98,7 @@ func TestBasicHeaderVariantsAndErrors(t *testing.T) { }{ {"one-byte", []byte{0x85}, formatType2, 5}, {"two-byte", []byte{0x40, 0x0a}, formatType1, 74}, - {"three-byte-code-path", []byte{0xc1, 0x01, 0x02}, formatType3, 65}, + {"three-byte", []byte{0xc1, 0x01, 0x02}, formatType3, 577}, } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) {