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) <noreply@anthropic.com>
This commit is contained in:
winlin 2026-05-24 20:22:34 -04:00
parent 26803ac4f4
commit abfb0cd8ae
2 changed files with 7 additions and 2 deletions

View File

@ -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)
}

View File

@ -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) {