aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/header.go
blob: 3b44dde2f3230ca5847c72e6e3169f0497bb7c7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package eventstream

import (
	"encoding/binary"
	"fmt"
	"io"
)

// Headers are a collection of EventStream header values.
type Headers []Header

// Header is a single EventStream Key Value header pair.
type Header struct {
	Name  string
	Value Value
}

// Set associates the name with a value. If the header name already exists in
// the Headers the value will be replaced with the new one.
func (hs *Headers) Set(name string, value Value) {
	var i int
	for ; i < len(*hs); i++ {
		if (*hs)[i].Name == name {
			(*hs)[i].Value = value
			return
		}
	}

	*hs = append(*hs, Header{
		Name: name, Value: value,
	})
}

// Get returns the Value associated with the header. Nil is returned if the
// value does not exist.
func (hs Headers) Get(name string) Value {
	for i := 0; i < len(hs); i++ {
		if h := hs[i]; h.Name == name {
			return h.Value
		}
	}
	return nil
}

// Del deletes the value in the Headers if it exists.
func (hs *Headers) Del(name string) {
	for i := 0; i < len(*hs); i++ {
		if (*hs)[i].Name == name {
			copy((*hs)[i:], (*hs)[i+1:])
			(*hs) = (*hs)[:len(*hs)-1]
		}
	}
}

func decodeHeaders(r io.Reader) (Headers, error) {
	hs := Headers{}

	for {
		name, err := decodeHeaderName(r)
		if err != nil {
			if err == io.EOF {
				// EOF while getting header name means no more headers
				break
			}
			return nil, err
		}

		value, err := decodeHeaderValue(r)
		if err != nil {
			return nil, err
		}

		hs.Set(name, value)
	}

	return hs, nil
}

func decodeHeaderName(r io.Reader) (string, error) {
	var n headerName

	var err error
	n.Len, err = decodeUint8(r)
	if err != nil {
		return "", err
	}

	name := n.Name[:n.Len]
	if _, err := io.ReadFull(r, name); err != nil {
		return "", err
	}

	return string(name), nil
}

func decodeHeaderValue(r io.Reader) (Value, error) {
	var raw rawValue

	typ, err := decodeUint8(r)
	if err != nil {
		return nil, err
	}
	raw.Type = valueType(typ)

	var v Value

	switch raw.Type {
	case trueValueType:
		v = BoolValue(true)
	case falseValueType:
		v = BoolValue(false)
	case int8ValueType:
		var tv Int8Value
		err = tv.decode(r)
		v = tv
	case int16ValueType:
		var tv Int16Value
		err = tv.decode(r)
		v = tv
	case int32ValueType:
		var tv Int32Value
		err = tv.decode(r)
		v = tv
	case int64ValueType:
		var tv Int64Value
		err = tv.decode(r)
		v = tv
	case bytesValueType:
		var tv BytesValue
		err = tv.decode(r)
		v = tv
	case stringValueType:
		var tv StringValue
		err = tv.decode(r)
		v = tv
	case timestampValueType:
		var tv TimestampValue
		err = tv.decode(r)
		v = tv
	case uuidValueType:
		var tv UUIDValue
		err = tv.decode(r)
		v = tv
	default:
		panic(fmt.Sprintf("unknown value type %d", raw.Type))
	}

	// Error could be EOF, let caller deal with it
	return v, err
}

const maxHeaderNameLen = 255

type headerName struct {
	Len  uint8
	Name [maxHeaderNameLen]byte
}

func (v headerName) encode(w io.Writer) error {
	if err := binary.Write(w, binary.BigEndian, v.Len); err != nil {
		return err
	}

	_, err := w.Write(v.Name[:v.Len])
	return err
}