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 ( import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"math" "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. // 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) { func EncodeString(buf []byte, val string) ([]byte, error) {
const typeSize = 1 const typeSize = 1
if len(val) < 65536 && len(val)+typeSize+binary.Size(int16(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
}
if len(val)+typeSize+binary.Size(uint32(0)) > len(buf) {
return nil, ErrShortBuffer return nil, ErrShortBuffer
} }
@ -222,7 +219,11 @@ func EncodeNamedString(buf []byte, key, val string) ([]byte, error) {
binary.BigEndian.PutUint16(buf[:2], uint16(len(key))) binary.BigEndian.PutUint16(buf[:2], uint16(len(key)))
buf = buf[2:] buf = buf[2:]
copy(buf, key) 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. // 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))) binary.BigEndian.PutUint16(buf[:2], uint16(len(key)))
buf = buf[2:] buf = buf[2:]
copy(buf, key) 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. // 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))) binary.BigEndian.PutUint16(buf[:2], uint16(len(key)))
buf = buf[2:] buf = buf[2:]
copy(buf, key) 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. // EncodeProperty encodes a property.
func EncodeProperty(prop *Property, buf []byte) ([]byte, error) { func EncodeProperty(prop *Property, buf []byte) ([]byte, error) {
if prop.Type != TypeNull && prop.Name != "" { if prop.Type != TypeNull && prop.Name != "" {
if len(buf) < 2+len(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))) binary.BigEndian.PutUint16(buf[:2], uint16(len(prop.Name)))
buf = buf[2:] buf = buf[2:]
@ -261,23 +270,47 @@ func EncodeProperty(prop *Property, buf []byte) ([]byte, error) {
switch prop.Type { switch prop.Type {
case typeNumber: 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: 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: 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: case TypeNull:
if len(buf) < 2 { if len(buf) < 2 {
return nil, ErrShortBuffer return nil, fmt.Errorf("type null, short buffer: %w", ErrShortBuffer)
} }
buf[0] = TypeNull buf[0] = TypeNull
buf = buf[1:] buf = buf[1:]
case TypeObject: 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: 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: 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: default:
return nil, ErrInvalidType return nil, ErrInvalidType
} }
@ -294,7 +327,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
} }
n := DecodeInt16(buf[:2]) n := DecodeInt16(buf[:2])
if int(n) > len(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) prop.Name = DecodeString(buf)
@ -309,14 +342,14 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
switch prop.Type { switch prop.Type {
case typeNumber: case typeNumber:
if len(buf) < 8 { if len(buf) < 8 {
return 0, ErrShortBuffer return 0, fmt.Errorf("type number short buffer: %w", ErrShortBuffer)
} }
prop.Number = DecodeNumber(buf[:8]) prop.Number = DecodeNumber(buf[:8])
buf = buf[8:] buf = buf[8:]
case typeBoolean: case typeBoolean:
if len(buf) < 1 { if len(buf) < 1 {
return 0, ErrShortBuffer return 0, fmt.Errorf("type boolean short buffer: %w", ErrShortBuffer)
} }
prop.Number = float64(buf[0]) prop.Number = float64(buf[0])
buf = buf[1:] buf = buf[1:]
@ -324,7 +357,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
case TypeString: case TypeString:
n := DecodeInt16(buf[:2]) n := DecodeInt16(buf[:2])
if len(buf) < int(n+2) { if len(buf) < int(n+2) {
return 0, ErrShortBuffer return 0, fmt.Errorf("type string: %w", ErrShortBuffer)
} }
prop.String = DecodeString(buf) prop.String = DecodeString(buf)
buf = buf[2+n:] buf = buf[2+n:]
@ -332,7 +365,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
case TypeObject: case TypeObject:
n, err := Decode(&prop.Object, buf, true) n, err := Decode(&prop.Object, buf, true)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not decode type object: %w", err)
} }
buf = buf[n:] buf = buf[n:]
@ -343,7 +376,7 @@ func DecodeProperty(prop *Property, buf []byte, decodeName bool) (int, error) {
buf = buf[4:] buf = buf[4:]
n, err := Decode(&prop.Object, buf, true) n, err := Decode(&prop.Object, buf, true)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not decode type ecma array: %w", err)
} }
buf = buf[n:] buf = buf[n:]
@ -367,14 +400,19 @@ func Encode(obj *Object, buf []byte) ([]byte, error) {
var err error var err error
buf, err = EncodeProperty(&obj.Properties[i], buf) buf, err = EncodeProperty(&obj.Properties[i], buf)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("could not encode property no. %d: %w", i, err)
} }
} }
if len(buf) < 3 { 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. // EncodeEcmaArray encodes an ECMA array.
@ -392,14 +430,20 @@ func EncodeEcmaArray(obj *Object, buf []byte) ([]byte, error) {
var err error var err error
buf, err = EncodeProperty(&obj.Properties[i], buf) buf, err = EncodeProperty(&obj.Properties[i], buf)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("could not encode property no. %d: %w", i, err)
} }
} }
if len(buf) < 3 { 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. // EncodeArray encodes an array.
@ -417,7 +461,7 @@ func EncodeArray(obj *Object, buf []byte) ([]byte, error) {
var err error var err error
buf, err = EncodeProperty(&obj.Properties[i], buf) buf, err = EncodeProperty(&obj.Properties[i], buf)
if err != nil { 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 var prop Property
n, err := DecodeProperty(&prop, buf, decodeName) n, err := DecodeProperty(&prop, buf, decodeName)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("could not decode property: %w", err)
} }
buf = buf[n:] buf = buf[n:]
obj.Properties = append(obj.Properties, prop) obj.Properties = append(obj.Properties, prop)