1// Copyright 2017, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16package tag
17
18import (
19	"encoding/binary"
20	"fmt"
21)
22
23// KeyType defines the types of keys allowed. Currently only keyTypeString is
24// supported.
25type keyType byte
26
27const (
28	keyTypeString keyType = iota
29	keyTypeInt64
30	keyTypeTrue
31	keyTypeFalse
32
33	tagsVersionID = byte(0)
34)
35
36type encoderGRPC struct {
37	buf               []byte
38	writeIdx, readIdx int
39}
40
41// writeKeyString writes the fieldID '0' followed by the key string and value
42// string.
43func (eg *encoderGRPC) writeTagString(k, v string) {
44	eg.writeByte(byte(keyTypeString))
45	eg.writeStringWithVarintLen(k)
46	eg.writeStringWithVarintLen(v)
47}
48
49func (eg *encoderGRPC) writeTagUint64(k string, i uint64) {
50	eg.writeByte(byte(keyTypeInt64))
51	eg.writeStringWithVarintLen(k)
52	eg.writeUint64(i)
53}
54
55func (eg *encoderGRPC) writeTagTrue(k string) {
56	eg.writeByte(byte(keyTypeTrue))
57	eg.writeStringWithVarintLen(k)
58}
59
60func (eg *encoderGRPC) writeTagFalse(k string) {
61	eg.writeByte(byte(keyTypeFalse))
62	eg.writeStringWithVarintLen(k)
63}
64
65func (eg *encoderGRPC) writeBytesWithVarintLen(bytes []byte) {
66	length := len(bytes)
67
68	eg.growIfRequired(binary.MaxVarintLen64 + length)
69	eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length))
70	copy(eg.buf[eg.writeIdx:], bytes)
71	eg.writeIdx += length
72}
73
74func (eg *encoderGRPC) writeStringWithVarintLen(s string) {
75	length := len(s)
76
77	eg.growIfRequired(binary.MaxVarintLen64 + length)
78	eg.writeIdx += binary.PutUvarint(eg.buf[eg.writeIdx:], uint64(length))
79	copy(eg.buf[eg.writeIdx:], s)
80	eg.writeIdx += length
81}
82
83func (eg *encoderGRPC) writeByte(v byte) {
84	eg.growIfRequired(1)
85	eg.buf[eg.writeIdx] = v
86	eg.writeIdx++
87}
88
89func (eg *encoderGRPC) writeUint32(i uint32) {
90	eg.growIfRequired(4)
91	binary.LittleEndian.PutUint32(eg.buf[eg.writeIdx:], i)
92	eg.writeIdx += 4
93}
94
95func (eg *encoderGRPC) writeUint64(i uint64) {
96	eg.growIfRequired(8)
97	binary.LittleEndian.PutUint64(eg.buf[eg.writeIdx:], i)
98	eg.writeIdx += 8
99}
100
101func (eg *encoderGRPC) readByte() byte {
102	b := eg.buf[eg.readIdx]
103	eg.readIdx++
104	return b
105}
106
107func (eg *encoderGRPC) readUint32() uint32 {
108	i := binary.LittleEndian.Uint32(eg.buf[eg.readIdx:])
109	eg.readIdx += 4
110	return i
111}
112
113func (eg *encoderGRPC) readUint64() uint64 {
114	i := binary.LittleEndian.Uint64(eg.buf[eg.readIdx:])
115	eg.readIdx += 8
116	return i
117}
118
119func (eg *encoderGRPC) readBytesWithVarintLen() ([]byte, error) {
120	if eg.readEnded() {
121		return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx)
122	}
123	length, valueStart := binary.Uvarint(eg.buf[eg.readIdx:])
124	if valueStart <= 0 {
125		return nil, fmt.Errorf("unexpected end while readBytesWithVarintLen '%x' starting at idx '%v'", eg.buf, eg.readIdx)
126	}
127
128	valueStart += eg.readIdx
129	valueEnd := valueStart + int(length)
130	if valueEnd > len(eg.buf) {
131		return nil, fmt.Errorf("malformed encoding: length:%v, upper:%v, maxLength:%v", length, valueEnd, len(eg.buf))
132	}
133
134	eg.readIdx = valueEnd
135	return eg.buf[valueStart:valueEnd], nil
136}
137
138func (eg *encoderGRPC) readStringWithVarintLen() (string, error) {
139	bytes, err := eg.readBytesWithVarintLen()
140	if err != nil {
141		return "", err
142	}
143	return string(bytes), nil
144}
145
146func (eg *encoderGRPC) growIfRequired(expected int) {
147	if len(eg.buf)-eg.writeIdx < expected {
148		tmp := make([]byte, 2*(len(eg.buf)+1)+expected)
149		copy(tmp, eg.buf)
150		eg.buf = tmp
151	}
152}
153
154func (eg *encoderGRPC) readEnded() bool {
155	return eg.readIdx >= len(eg.buf)
156}
157
158func (eg *encoderGRPC) bytes() []byte {
159	return eg.buf[:eg.writeIdx]
160}
161
162// Encode encodes the tag map into a []byte. It is useful to propagate
163// the tag maps on wire in binary format.
164func Encode(m *Map) []byte {
165	if m == nil {
166		return nil
167	}
168	eg := &encoderGRPC{
169		buf: make([]byte, len(m.m)),
170	}
171	eg.writeByte(tagsVersionID)
172	for k, v := range m.m {
173		if v.m.ttl.ttl == valueTTLUnlimitedPropagation {
174			eg.writeByte(byte(keyTypeString))
175			eg.writeStringWithVarintLen(k.name)
176			eg.writeBytesWithVarintLen([]byte(v.value))
177		}
178	}
179	return eg.bytes()
180}
181
182// Decode decodes the given []byte into a tag map.
183func Decode(bytes []byte) (*Map, error) {
184	ts := newMap()
185	err := DecodeEach(bytes, ts.upsert)
186	if err != nil {
187		// no partial failures
188		return nil, err
189	}
190	return ts, nil
191}
192
193// DecodeEach decodes the given serialized tag map, calling handler for each
194// tag key and value decoded.
195func DecodeEach(bytes []byte, fn func(key Key, val string, md metadatas)) error {
196	eg := &encoderGRPC{
197		buf: bytes,
198	}
199	if len(eg.buf) == 0 {
200		return nil
201	}
202
203	version := eg.readByte()
204	if version > tagsVersionID {
205		return fmt.Errorf("cannot decode: unsupported version: %q; supports only up to: %q", version, tagsVersionID)
206	}
207
208	for !eg.readEnded() {
209		typ := keyType(eg.readByte())
210
211		if typ != keyTypeString {
212			return fmt.Errorf("cannot decode: invalid key type: %q", typ)
213		}
214
215		k, err := eg.readBytesWithVarintLen()
216		if err != nil {
217			return err
218		}
219
220		v, err := eg.readBytesWithVarintLen()
221		if err != nil {
222			return err
223		}
224
225		key, err := NewKey(string(k))
226		if err != nil {
227			return err
228		}
229		val := string(v)
230		if !checkValue(val) {
231			return errInvalidValue
232		}
233		fn(key, val, createMetadatas(WithTTL(TTLUnlimitedPropagation)))
234		if err != nil {
235			return err
236		}
237	}
238	return nil
239}
240