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	eg := &encoderGRPC{
166		buf: make([]byte, len(m.m)),
167	}
168	eg.writeByte(byte(tagsVersionID))
169	for k, v := range m.m {
170		eg.writeByte(byte(keyTypeString))
171		eg.writeStringWithVarintLen(k.name)
172		eg.writeBytesWithVarintLen([]byte(v))
173	}
174	return eg.bytes()
175}
176
177// Decode decodes the given []byte into a tag map.
178func Decode(bytes []byte) (*Map, error) {
179	ts := newMap()
180
181	eg := &encoderGRPC{
182		buf: bytes,
183	}
184	if len(eg.buf) == 0 {
185		return ts, nil
186	}
187
188	version := eg.readByte()
189	if version > tagsVersionID {
190		return nil, fmt.Errorf("cannot decode: unsupported version: %q; supports only up to: %q", version, tagsVersionID)
191	}
192
193	for !eg.readEnded() {
194		typ := keyType(eg.readByte())
195
196		if typ != keyTypeString {
197			return nil, fmt.Errorf("cannot decode: invalid key type: %q", typ)
198		}
199
200		k, err := eg.readBytesWithVarintLen()
201		if err != nil {
202			return nil, err
203		}
204
205		v, err := eg.readBytesWithVarintLen()
206		if err != nil {
207			return nil, err
208		}
209
210		key, err := NewKey(string(k))
211		if err != nil {
212			return nil, err // no partial failures
213		}
214		val := string(v)
215		if !checkValue(val) {
216			return nil, errInvalidValue // no partial failures
217		}
218		ts.upsert(key, val)
219	}
220	return ts, nil
221}
222