blob: 2d678063f74cd674f3f9ffbf2eee94b9fb329581 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package iggcon
import (
"encoding/binary"
"errors"
)
type HeaderValue struct {
Kind HeaderKind
Value []byte
}
type HeaderKey struct {
Kind HeaderKind
Value []byte
}
type HeaderEntry struct {
Key HeaderKey
Value HeaderValue
}
func NewHeaderKeyString(val string) (HeaderKey, error) {
if len(val) == 0 || len(val) > 255 {
return HeaderKey{}, errors.New("value has incorrect size, must be between 1 and 255")
}
return HeaderKey{Kind: String, Value: []byte(val)}, nil
}
func NewHeaderKeyRaw(val []byte) (HeaderKey, error) {
if len(val) == 0 || len(val) > 255 {
return HeaderKey{}, errors.New("value has incorrect size, must be between 1 and 255")
}
return HeaderKey{Kind: Raw, Value: val}, nil
}
func NewHeaderKeyInt32(val int32) HeaderKey {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(val))
return HeaderKey{Kind: Int32, Value: buf}
}
type HeaderKind int
const (
Raw HeaderKind = 1
String HeaderKind = 2
Bool HeaderKind = 3
Int8 HeaderKind = 4
Int16 HeaderKind = 5
Int32 HeaderKind = 6
Int64 HeaderKind = 7
Int128 HeaderKind = 8
Uint8 HeaderKind = 9
Uint16 HeaderKind = 10
Uint32 HeaderKind = 11
Uint64 HeaderKind = 12
Uint128 HeaderKind = 13
Float HeaderKind = 14
Double HeaderKind = 15
)
func (k HeaderKind) ExpectedSize() int {
switch k {
case Bool, Int8, Uint8:
return 1
case Int16, Uint16:
return 2
case Int32, Uint32, Float:
return 4
case Int64, Uint64, Double:
return 8
case Int128, Uint128:
return 16
default:
return -1
}
}
func GetHeadersBytes(headers []HeaderEntry) []byte {
headersLength := 0
for _, entry := range headers {
headersLength += 1 + 4 + len(entry.Key.Value) + 1 + 4 + len(entry.Value.Value)
}
headersBytes := make([]byte, headersLength)
position := 0
for _, entry := range headers {
headerBytes := getBytesFromHeader(entry.Key, entry.Value)
copy(headersBytes[position:position+len(headerBytes)], headerBytes)
position += len(headerBytes)
}
return headersBytes
}
func getBytesFromHeader(key HeaderKey, value HeaderValue) []byte {
headerBytesLength := 1 + 4 + len(key.Value) + 1 + 4 + len(value.Value)
headerBytes := make([]byte, headerBytesLength)
pos := 0
headerBytes[pos] = byte(key.Kind)
pos++
binary.LittleEndian.PutUint32(headerBytes[pos:pos+4], uint32(len(key.Value)))
pos += 4
copy(headerBytes[pos:pos+len(key.Value)], key.Value)
pos += len(key.Value)
headerBytes[pos] = byte(value.Kind)
pos++
binary.LittleEndian.PutUint32(headerBytes[pos:pos+4], uint32(len(value.Value)))
pos += 4
copy(headerBytes[pos:], value.Value)
return headerBytes
}
func DeserializeHeaders(userHeadersBytes []byte) ([]HeaderEntry, error) {
var headers []HeaderEntry
position := 0
for position < len(userHeadersBytes) {
keyKind, err := deserializeHeaderKind(userHeadersBytes, position)
if err != nil {
return nil, err
}
position++
if len(userHeadersBytes) <= position+4 {
return nil, errors.New("invalid header key length")
}
keyLength := binary.LittleEndian.Uint32(userHeadersBytes[position : position+4])
if keyLength == 0 || 255 < keyLength {
return nil, errors.New("key has incorrect size, must be between 1 and 255")
}
position += 4
if len(userHeadersBytes) < position+int(keyLength) {
return nil, errors.New("invalid header key")
}
if expected := keyKind.ExpectedSize(); expected != -1 && int(keyLength) != expected {
return nil, errors.New("invalid header key size for kind")
}
keyValue := make([]byte, keyLength)
copy(keyValue, userHeadersBytes[position:position+int(keyLength)])
position += int(keyLength)
valueKind, err := deserializeHeaderKind(userHeadersBytes, position)
if err != nil {
return nil, err
}
position++
if len(userHeadersBytes) <= position+4 {
return nil, errors.New("invalid header value length")
}
valueLength := binary.LittleEndian.Uint32(userHeadersBytes[position : position+4])
position += 4
if valueLength == 0 || 255 < valueLength {
return nil, errors.New("value has incorrect size, must be between 1 and 255")
}
if len(userHeadersBytes) < position+int(valueLength) {
return nil, errors.New("invalid header value")
}
if expected := valueKind.ExpectedSize(); expected != -1 && int(valueLength) != expected {
return nil, errors.New("invalid header value size for kind")
}
valueBytes := make([]byte, valueLength)
copy(valueBytes, userHeadersBytes[position:position+int(valueLength)])
position += int(valueLength)
headers = append(headers, HeaderEntry{
Key: HeaderKey{Kind: keyKind, Value: keyValue},
Value: HeaderValue{Kind: valueKind, Value: valueBytes},
})
}
return headers, nil
}
func deserializeHeaderKind(payload []byte, position int) (HeaderKind, error) {
if position >= len(payload) {
return 0, errors.New("invalid header kind position")
}
return HeaderKind(payload[position]), nil
}