1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package trace
16
17 import (
18 "encoding/json"
19 "fmt"
20 "regexp"
21 "strings"
22 )
23
24 const (
25 maxListMembers = 32
26
27 listDelimiter = ","
28
29
30
31 noTenantKeyFormat = `[a-z][_0-9a-z\-\*\/]*`
32 withTenantKeyFormat = `[a-z0-9][_0-9a-z\-\*\/]*@[a-z][_0-9a-z\-\*\/]*`
33 valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]*[\x21-\x2b\x2d-\x3c\x3e-\x7e]`
34
35 errInvalidKey errorConst = "invalid tracestate key"
36 errInvalidValue errorConst = "invalid tracestate value"
37 errInvalidMember errorConst = "invalid tracestate list-member"
38 errMemberNumber errorConst = "too many list-members in tracestate"
39 errDuplicate errorConst = "duplicate list-member in tracestate"
40 )
41
42 var (
43 noTenantKeyRe = regexp.MustCompile(`^` + noTenantKeyFormat + `$`)
44 withTenantKeyRe = regexp.MustCompile(`^` + withTenantKeyFormat + `$`)
45 valueRe = regexp.MustCompile(`^` + valueFormat + `$`)
46 memberRe = regexp.MustCompile(`^\s*((?:` + noTenantKeyFormat + `)|(?:` + withTenantKeyFormat + `))=(` + valueFormat + `)\s*$`)
47 )
48
49 type member struct {
50 Key string
51 Value string
52 }
53
54 func newMember(key, value string) (member, error) {
55 if len(key) > 256 {
56 return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
57 }
58 if !noTenantKeyRe.MatchString(key) {
59 if !withTenantKeyRe.MatchString(key) {
60 return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
61 }
62 atIndex := strings.LastIndex(key, "@")
63 if atIndex > 241 || len(key)-1-atIndex > 14 {
64 return member{}, fmt.Errorf("%w: %s", errInvalidKey, key)
65 }
66 }
67 if len(value) > 256 || !valueRe.MatchString(value) {
68 return member{}, fmt.Errorf("%w: %s", errInvalidValue, value)
69 }
70 return member{Key: key, Value: value}, nil
71 }
72
73 func parseMember(m string) (member, error) {
74 matches := memberRe.FindStringSubmatch(m)
75 if len(matches) != 3 {
76 return member{}, fmt.Errorf("%w: %s", errInvalidMember, m)
77 }
78 result, e := newMember(matches[1], matches[2])
79 if e != nil {
80 return member{}, fmt.Errorf("%w: %s", errInvalidMember, m)
81 }
82 return result, nil
83 }
84
85
86
87 func (m member) String() string {
88 return fmt.Sprintf("%s=%s", m.Key, m.Value)
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102 type TraceState struct {
103
104 list []member
105 }
106
107 var _ json.Marshaler = TraceState{}
108
109
110
111
112 func ParseTraceState(tracestate string) (TraceState, error) {
113 if tracestate == "" {
114 return TraceState{}, nil
115 }
116
117 wrapErr := func(err error) error {
118 return fmt.Errorf("failed to parse tracestate: %w", err)
119 }
120
121 var members []member
122 found := make(map[string]struct{})
123 for _, memberStr := range strings.Split(tracestate, listDelimiter) {
124 if len(memberStr) == 0 {
125 continue
126 }
127
128 m, err := parseMember(memberStr)
129 if err != nil {
130 return TraceState{}, wrapErr(err)
131 }
132
133 if _, ok := found[m.Key]; ok {
134 return TraceState{}, wrapErr(errDuplicate)
135 }
136 found[m.Key] = struct{}{}
137
138 members = append(members, m)
139 if n := len(members); n > maxListMembers {
140 return TraceState{}, wrapErr(errMemberNumber)
141 }
142 }
143
144 return TraceState{list: members}, nil
145 }
146
147
148 func (ts TraceState) MarshalJSON() ([]byte, error) {
149 return json.Marshal(ts.String())
150 }
151
152
153
154
155 func (ts TraceState) String() string {
156 members := make([]string, len(ts.list))
157 for i, m := range ts.list {
158 members[i] = m.String()
159 }
160 return strings.Join(members, listDelimiter)
161 }
162
163
164
165 func (ts TraceState) Get(key string) string {
166 for _, member := range ts.list {
167 if member.Key == key {
168 return member.Value
169 }
170 }
171
172 return ""
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186
187 func (ts TraceState) Insert(key, value string) (TraceState, error) {
188 m, err := newMember(key, value)
189 if err != nil {
190 return ts, err
191 }
192
193 cTS := ts.Delete(key)
194 if cTS.Len()+1 <= maxListMembers {
195 cTS.list = append(cTS.list, member{})
196 }
197
198 copy(cTS.list[1:], cTS.list)
199 cTS.list[0] = m
200
201 return cTS, nil
202 }
203
204
205
206 func (ts TraceState) Delete(key string) TraceState {
207 members := make([]member, ts.Len())
208 copy(members, ts.list)
209 for i, member := range ts.list {
210 if member.Key == key {
211 members = append(members[:i], members[i+1:]...)
212
213 break
214 }
215 }
216 return TraceState{list: members}
217 }
218
219
220 func (ts TraceState) Len() int {
221 return len(ts.list)
222 }
223
View as plain text