mirror of https://bitbucket.org/ausocean/av.git
protocol/rtmp/amf/amf.go: improving error messaging
This commit is contained in:
parent
c4e4cc750f
commit
dd6adbf9d0
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue