@@ -44,9 +44,15 @@ type Property struct {
44
44
45
45
// NewKeyProperty returns a new Property for key.
46
46
//
47
+ // The passed key must be valid, non-empty UTF-8 string.
47
48
// If key is invalid, an error will be returned.
49
+ // However, the specific Propagators that are used to transmit baggage entries across
50
+ // component boundaries may impose their own restrictions on Property key.
51
+ // For example, the W3C Baggage specification restricts the Property keys to strings that
52
+ // satisfy the token definition from RFC7230, Section 3.2.6.
53
+ // For maximum compatibility, alpha-numeric value are strongly recommended to be used as Property key.
48
54
func NewKeyProperty (key string ) (Property , error ) {
49
- if ! validateKey (key ) {
55
+ if ! validateBaggageName (key ) {
50
56
return newInvalidProperty (), fmt .Errorf ("%w: %q" , errInvalidKey , key )
51
57
}
52
58
@@ -62,6 +68,10 @@ func NewKeyProperty(key string) (Property, error) {
62
68
// Notice: Consider using [NewKeyValuePropertyRaw] instead
63
69
// that does not require percent-encoding of the value.
64
70
func NewKeyValueProperty (key , value string ) (Property , error ) {
71
+ if ! validateKey (key ) {
72
+ return newInvalidProperty (), fmt .Errorf ("%w: %q" , errInvalidKey , key )
73
+ }
74
+
65
75
if ! validateValue (value ) {
66
76
return newInvalidProperty (), fmt .Errorf ("%w: %q" , errInvalidValue , value )
67
77
}
@@ -74,11 +84,20 @@ func NewKeyValueProperty(key, value string) (Property, error) {
74
84
75
85
// NewKeyValuePropertyRaw returns a new Property for key with value.
76
86
//
77
- // The passed key must be compliant with W3C Baggage specification.
87
+ // The passed key must be valid, non-empty UTF-8 string.
88
+ // The passed value must be valid UTF-8 string.
89
+ // However, the specific Propagators that are used to transmit baggage entries across
90
+ // component boundaries may impose their own restrictions on Property key.
91
+ // For example, the W3C Baggage specification restricts the Property keys to strings that
92
+ // satisfy the token definition from RFC7230, Section 3.2.6.
93
+ // For maximum compatibility, alpha-numeric value are strongly recommended to be used as Property key.
78
94
func NewKeyValuePropertyRaw (key , value string ) (Property , error ) {
79
- if ! validateKey (key ) {
95
+ if ! validateBaggageName (key ) {
80
96
return newInvalidProperty (), fmt .Errorf ("%w: %q" , errInvalidKey , key )
81
97
}
98
+ if ! validateBaggageValue (value ) {
99
+ return newInvalidProperty (), fmt .Errorf ("%w: %q" , errInvalidValue , value )
100
+ }
82
101
83
102
p := Property {
84
103
key : key ,
@@ -115,12 +134,15 @@ func (p Property) validate() error {
115
134
return fmt .Errorf ("invalid property: %w" , err )
116
135
}
117
136
118
- if ! validateKey (p .key ) {
137
+ if ! validateBaggageName (p .key ) {
119
138
return errFunc (fmt .Errorf ("%w: %q" , errInvalidKey , p .key ))
120
139
}
121
140
if ! p .hasValue && p .value != "" {
122
141
return errFunc (errors .New ("inconsistent value" ))
123
142
}
143
+ if p .hasValue && ! validateBaggageValue (p .value ) {
144
+ return errFunc (fmt .Errorf ("%w: %q" , errInvalidValue , p .value ))
145
+ }
124
146
return nil
125
147
}
126
148
@@ -138,7 +160,15 @@ func (p Property) Value() (string, bool) {
138
160
139
161
// String encodes Property into a header string compliant with the W3C Baggage
140
162
// specification.
163
+ // It would return empty string if the key is invalid with the W3C Baggage
164
+ // specification. This could happen for a UTF-8 key, as it may contain
165
+ // invalid characters.
141
166
func (p Property ) String () string {
167
+ // W3C Baggage specification does not allow percent-encoded keys.
168
+ if ! validateKey (p .key ) {
169
+ return ""
170
+ }
171
+
142
172
if p .hasValue {
143
173
return fmt .Sprintf ("%s%s%v" , p .key , keyValueDelimiter , valueEscape (p .value ))
144
174
}
@@ -203,9 +233,14 @@ func (p properties) validate() error {
203
233
// String encodes properties into a header string compliant with the W3C Baggage
204
234
// specification.
205
235
func (p properties ) String () string {
206
- props := make ([]string , len (p ))
207
- for i , prop := range p {
208
- props [i ] = prop .String ()
236
+ props := make ([]string , 0 , len (p ))
237
+ for _ , prop := range p {
238
+ s := prop .String ()
239
+
240
+ // Ignored empty properties.
241
+ if s != "" {
242
+ props = append (props , s )
243
+ }
209
244
}
210
245
return strings .Join (props , propertyDelimiter )
211
246
}
@@ -230,6 +265,10 @@ type Member struct {
230
265
// Notice: Consider using [NewMemberRaw] instead
231
266
// that does not require percent-encoding of the value.
232
267
func NewMember (key , value string , props ... Property ) (Member , error ) {
268
+ if ! validateKey (key ) {
269
+ return newInvalidMember (), fmt .Errorf ("%w: %q" , errInvalidKey , key )
270
+ }
271
+
233
272
if ! validateValue (value ) {
234
273
return newInvalidMember (), fmt .Errorf ("%w: %q" , errInvalidValue , value )
235
274
}
@@ -242,7 +281,13 @@ func NewMember(key, value string, props ...Property) (Member, error) {
242
281
243
282
// NewMemberRaw returns a new Member from the passed arguments.
244
283
//
245
- // The passed key must be compliant with W3C Baggage specification.
284
+ // The passed key must be valid, non-empty UTF-8 string.
285
+ // The passed value must be valid UTF-8 string.
286
+ // However, the specific Propagators that are used to transmit baggage entries across
287
+ // component boundaries may impose their own restrictions on baggage key.
288
+ // For example, the W3C Baggage specification restricts the baggage keys to strings that
289
+ // satisfy the token definition from RFC7230, Section 3.2.6.
290
+ // For maximum compatibility, alpha-numeric value are strongly recommended to be used as baggage key.
246
291
func NewMemberRaw (key , value string , props ... Property ) (Member , error ) {
247
292
m := Member {
248
293
key : key ,
@@ -340,9 +385,12 @@ func (m Member) validate() error {
340
385
return fmt .Errorf ("%w: %q" , errInvalidMember , m )
341
386
}
342
387
343
- if ! validateKey (m .key ) {
388
+ if ! validateBaggageName (m .key ) {
344
389
return fmt .Errorf ("%w: %q" , errInvalidKey , m .key )
345
390
}
391
+ if ! validateBaggageValue (m .value ) {
392
+ return fmt .Errorf ("%w: %q" , errInvalidValue , m .value )
393
+ }
346
394
return m .properties .validate ()
347
395
}
348
396
@@ -357,10 +405,15 @@ func (m Member) Properties() []Property { return m.properties.Copy() }
357
405
358
406
// String encodes Member into a header string compliant with the W3C Baggage
359
407
// specification.
408
+ // It would return empty string if the key is invalid with the W3C Baggage
409
+ // specification. This could happen for a UTF-8 key, as it may contain
410
+ // invalid characters.
360
411
func (m Member ) String () string {
361
- // A key is just an ASCII string. A value is restricted to be
362
- // US-ASCII characters excluding CTLs, whitespace,
363
- // DQUOTE, comma, semicolon, and backslash.
412
+ // W3C Baggage specification does not allow percent-encoded keys.
413
+ if ! validateKey (m .key ) {
414
+ return ""
415
+ }
416
+
364
417
s := m .key + keyValueDelimiter + valueEscape (m .value )
365
418
if len (m .properties ) > 0 {
366
419
s += propertyDelimiter + m .properties .String ()
@@ -554,14 +607,22 @@ func (b Baggage) Len() int {
554
607
555
608
// String encodes Baggage into a header string compliant with the W3C Baggage
556
609
// specification.
610
+ // It would ignore members where the member key is invalid with the W3C Baggage
611
+ // specification. This could happen for a UTF-8 key, as it may contain
612
+ // invalid characters.
557
613
func (b Baggage ) String () string {
558
614
members := make ([]string , 0 , len (b .list ))
559
615
for k , v := range b .list {
560
- members = append ( members , Member {
616
+ s := Member {
561
617
key : k ,
562
618
value : v .Value ,
563
619
properties : fromInternalProperties (v .Properties ),
564
- }.String ())
620
+ }.String ()
621
+
622
+ // Ignored empty members.
623
+ if s != "" {
624
+ members = append (members , s )
625
+ }
565
626
}
566
627
return strings .Join (members , listDelimiter )
567
628
}
@@ -748,6 +809,24 @@ var safeKeyCharset = [utf8.RuneSelf]bool{
748
809
'~' : true ,
749
810
}
750
811
812
+ // validateBaggageName checks if the string is a valid OpenTelemetry Baggage name.
813
+ // Baggage name is a valid, non-empty UTF-8 string.
814
+ func validateBaggageName (s string ) bool {
815
+ if len (s ) == 0 {
816
+ return false
817
+ }
818
+
819
+ return utf8 .ValidString (s )
820
+ }
821
+
822
+ // validateBaggageValue checks if the string is a valid OpenTelemetry Baggage value.
823
+ // Baggage value is a valid UTF-8 strings.
824
+ // Empty string is also a valid UTF-8 string.
825
+ func validateBaggageValue (s string ) bool {
826
+ return utf8 .ValidString (s )
827
+ }
828
+
829
+ // validateKey checks if the string is a valid W3C Baggage key.
751
830
func validateKey (s string ) bool {
752
831
if len (s ) == 0 {
753
832
return false
@@ -766,6 +845,7 @@ func validateKeyChar(c int32) bool {
766
845
return c >= 0 && c < int32 (utf8 .RuneSelf ) && safeKeyCharset [c ]
767
846
}
768
847
848
+ // validateValue checks if the string is a valid W3C Baggage value.
769
849
func validateValue (s string ) bool {
770
850
for _ , c := range s {
771
851
if ! validateValueChar (c ) {
0 commit comments