protocol/rtmp/amf/amf.go: improving error messaging

This commit is contained in:
Saxon Nelson-Milton 2022-03-15 15:35:04 +10:30
parent c4e4cc750f
commit dd6adbf9d0
1 changed files with 74 additions and 30 deletions

View File

@ -43,6 +43,7 @@ package amf
import (
"encoding/binary"
"errors"
"fmt"
"math"
)
@ -163,11 +164,7 @@ func EncodeInt32(buf []byte, val uint32) ([]byte, error) {
// Strings less than 65536 in length are encoded as TypeString, while longer strings are ecodeded as typeLongString.
func EncodeString(buf []byte, val string) ([]byte, error) {
const typeSize = 1
if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(0)) > len(buf) {
return nil, ErrShortBuffer
}
if len(val)+typeSize+binary.Size(uint32(0)) > len(buf) {
if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(0)) > len(buf) || len(val)+typeSize+binary.Size(uint32(0)) > len(buf) {
return nil, ErrShortBuffer
}
@ -222,7 +219,11 @@ func EncodeNamedString(buf []byte, key, val string) ([]byte, error) {
binary.BigEndian.PutUint16(buf[:2], uint16(len(key)))
buf = buf[2:]
copy(buf, key)
return EncodeString(buf[len(key):], val)
b, err := EncodeString(buf[len(key):], val)
if err != nil {
return nil, fmt.Errorf("could not encode string: %w", err)
}
return b, nil
}
// EncodeNamedNumber encodes a named number, where key is the name and val is the number value.
@ -233,7 +234,11 @@ func EncodeNamedNumber(buf []byte, key string, val float64) ([]byte, error) {
binary.BigEndian.PutUint16(buf[:2], uint16(len(key)))
buf = buf[2:]
copy(buf, key)
return EncodeNumber(buf[len(key):], val)
b, err := EncodeNumber(buf[len(key):], val)
if err != nil {
return nil, fmt.Errorf("could not encode number: %w", err)
}
return b, nil
}
// EncodeNamedNumber encodes a named boolean, where key is the name and val is the boolean value.
@ -244,14 +249,18 @@ func EncodeNamedBoolean(buf []byte, key string, val bool) ([]byte, error) {
binary.BigEndian.PutUint16(buf[:2], uint16(len(key)))
buf = buf[2:]
copy(buf, key)
return EncodeBoolean(buf[len(key):], val)
b, err := EncodeBoolean(buf[len(key):], val)
if err != nil {
return nil, fmt.Errorf("could not encode boolean: %w", err)
}
return b, nil
}
// EncodeProperty encodes a property.
func EncodeProperty(prop *Property, buf []byte) ([]byte, error) {
if prop.Type != TypeNull && prop.Name != "" {
if len(buf) < 2+len(prop.Name) {
return nil, ErrShortBuffer
return nil, fmt.Errorf("not type null, short buffer: %w", ErrShortBuffer)
}
binary.BigEndian.PutUint16(buf[:2], uint16(len(prop.Name)))
buf = buf[2:]
@ -261,23 +270,47 @@ func EncodeProperty(prop *Property, buf []byte) ([]byte, error) {
switch prop.Type {
case typeNumber:
return EncodeNumber(buf, prop.Number)
b, err := EncodeNumber(buf, prop.Number)
if err != nil {
return nil, fmt.Errorf("could not encode number: %w", err)
}
return b, nil
case typeBoolean:
return EncodeBoolean(buf, prop.Number != 0)
b, err := EncodeBoolean(buf, prop.Number != 0)
if err != nil {
return nil, fmt.Errorf("could not encode boolean: %w", err)
}
return b, nil
case TypeString:
return EncodeString(buf, prop.String)
b, err := EncodeString(buf, prop.String)
if err != nil {
return nil, fmt.Errorf("could not encode string: %w", err)
}
return b, nil
case TypeNull:
if len(buf) < 2 {
return nil, ErrShortBuffer
return nil, fmt.Errorf("type null, short buffer: %w", ErrShortBuffer)
}
buf[0] = TypeNull
buf = buf[1:]
case TypeObject:
return Encode(&prop.Object, buf)
b, err := Encode(&prop.Object, buf)
if err != nil {
return nil, fmt.Errorf("could not encode: %w", err)
}
return b, nil
case typeEcmaArray:
return EncodeEcmaArray(&prop.Object, buf)
b, err := EncodeEcmaArray(&prop.Object, buf)
if err != nil {
return nil, fmt.Errorf("could not encode ecma array: %w", err)
}
return b, nil
case typeStrictArray:
return EncodeArray(&prop.Object, buf)
b, err := EncodeArray(&prop.Object, buf)
if err != nil {
return nil, fmt.Errorf("could not encode array: %w", err)
}
return b, nil
default:
return nil, ErrInvalidType
}
@ -294,7 +327,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
}
n := DecodeInt16(buf[:2])
if int(n) > len(buf)-2 {
return 0, ErrShortBuffer
return 0, fmt.Errorf("short buffer after decode of int 16: %w", ErrShortBuffer)
}
prop.Name = DecodeString(buf)
@ -309,14 +342,14 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
switch prop.Type {
case typeNumber:
if len(buf) < 8 {
return 0, ErrShortBuffer
return 0, fmt.Errorf("type number short buffer: %w", ErrShortBuffer)
}
prop.Number = DecodeNumber(buf[:8])
buf = buf[8:]
case typeBoolean:
if len(buf) < 1 {
return 0, ErrShortBuffer
return 0, fmt.Errorf("type boolean short buffer: %w", ErrShortBuffer)
}
prop.Number = float64(buf[0])
buf = buf[1:]
@ -324,7 +357,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
case TypeString:
n := DecodeInt16(buf[:2])
if len(buf) < int(n+2) {
return 0, ErrShortBuffer
return 0, fmt.Errorf("type string: %w", ErrShortBuffer)
}
prop.String = DecodeString(buf)
buf = buf[2+n:]
@ -332,7 +365,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
case TypeObject:
n, err := Decode(&prop.Object, buf, true)
if err != nil {
return 0, err
return 0, fmt.Errorf("could not decode type object: %w", err)
}
buf = buf[n:]
@ -343,7 +376,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
buf = buf[4:]
n, err := Decode(&prop.Object, buf, true)
if err != nil {
return 0, err
return 0, fmt.Errorf("could not decode type ecma array: %w", err)
}
buf = buf[n:]
@ -367,14 +400,19 @@ func Encode(obj *Object, buf []byte) ([]byte, error) {
var err error
buf, err = EncodeProperty(&obj.Properties[i], buf)
if err != nil {
return nil, err
return nil, fmt.Errorf("could not encode property no. %d: %w", i, err)
}
}
if len(buf) < 3 {
return nil, ErrShortBuffer
return nil, fmt.Errorf("short buffer after property encoding: %w", ErrShortBuffer)
}
return EncodeInt24(buf, TypeObjectEnd)
b, err := EncodeInt24(buf, TypeObjectEnd)
if err != nil {
return nil, fmt.Errorf("could not encode int 24: %w", err)
}
return b, err
}
// EncodeEcmaArray encodes an ECMA array.
@ -392,14 +430,20 @@ func EncodeEcmaArray(obj *Object, buf []byte) ([]byte, error) {
var err error
buf, err = EncodeProperty(&obj.Properties[i], buf)
if err != nil {
return nil, err
return nil, fmt.Errorf("could not encode property no. %d: %w", i, err)
}
}
if len(buf) < 3 {
return nil, ErrShortBuffer
return nil, fmt.Errorf("short buffer after property encoding: %w", ErrShortBuffer)
}
return EncodeInt24(buf, TypeObjectEnd)
b, err := EncodeInt24(buf, TypeObjectEnd)
if err != nil {
return nil, fmt.Errorf("could not encode int 24: %w", err)
}
return b, nil
}
// EncodeArray encodes an array.
@ -417,7 +461,7 @@ func EncodeArray(obj *Object, buf []byte) ([]byte, error) {
var err error
buf, err = EncodeProperty(&obj.Properties[i], buf)
if err != nil {
return nil, err
return nil, fmt.Errorf("could not encode property no. %d: %w", i, err)
}
}
@ -437,7 +481,7 @@ func Decode(obj *Object, buf []byte, decodeName bool) (int, error) {
var prop Property
n, err := DecodeProperty(&prop, buf, decodeName)
if err != nil {
return 0, err
return 0, fmt.Errorf("could not decode property: %w", err)
}
buf = buf[n:]
obj.Properties = append(obj.Properties, prop)