Skip to content

Commit

Permalink
Fix baggage.NewMember to decode the accepted value (#3226)
Browse files Browse the repository at this point in the history
* Fix baggage.NewMember to decode the accepted value

`value` is decoded and stored after validating the input parameters.

Corresponding test cases are modified so that we can make sure `value` is properly encoded before creating Member.

* fix md lint

* add function document to NewMember for value encoding and decoding

* remove redundant comments and fix CHANGELOG.md

* fix wrong PR number in the changelog

* fix wrong PR number

* fix md-lint

Co-authored-by: Chester Cheung <cheung.zhy.csu@gmail.com>
  • Loading branch information
NewReStarter and hanyuancheung committed Oct 18, 2022
1 parent 1cbd4c2 commit 0963f59
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Fixed

- Fix function `baggage.NewMember` to decode the `value` parameter instead of directly use it according to the W3C specification. (#3226)
- Slice attributes of `attribute` package are now comparable based on their value, not instance. (#3108 #3252)
- Prometheus exporter will now cumulatively sum histogram buckets. (#3281)
- Export the sum of each histogram datapoint uniquely with the `go.opentelemetry.io/otel/exporters/otlpmetric` exporters. (#3284, #3293)
Expand Down
16 changes: 11 additions & 5 deletions baggage/baggage.go
Expand Up @@ -250,8 +250,9 @@ type Member struct {
hasData bool
}

// NewMember returns a new Member from the passed arguments. An error is
// returned if the created Member would be invalid according to the W3C
// NewMember returns a new Member from the passed arguments. The key will be
// used directly while the value will be url decoded after validation. An error
// is returned if the created Member would be invalid according to the W3C
// Baggage specification.
func NewMember(key, value string, props ...Property) (Member, error) {
m := Member{
Expand All @@ -263,7 +264,11 @@ func NewMember(key, value string, props ...Property) (Member, error) {
if err := m.validate(); err != nil {
return newInvalidMember(), err
}

decodedValue, err := url.QueryUnescape(value)
if err != nil {
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
}
m.value = decodedValue
return m, nil
}

Expand Down Expand Up @@ -328,8 +333,9 @@ func parseMember(member string) (Member, error) {
return Member{key: key, value: value, properties: props, hasData: true}, nil
}

// validate ensures m conforms to the W3C Baggage specification, returning an
// error otherwise.
// validate ensures m conforms to the W3C Baggage specification.
// A key is just an ASCII string, but a value must be URL encoded UTF-8,
// returning an error otherwise.
func (m Member) validate() error {
if !m.hasData {
return fmt.Errorf("%w: %q", errInvalidMember, m)
Expand Down
28 changes: 28 additions & 0 deletions baggage/baggage_test.go
Expand Up @@ -768,6 +768,23 @@ func TestNewMember(t *testing.T) {
}
assert.Equal(t, expected, m)

// wrong value with wrong decoding
val = "%zzzzz"
_, err = NewMember(key, val, p)
assert.ErrorIs(t, err, errInvalidValue)

// value should be decoded
val = "%3B"
m, err = NewMember(key, val, p)
expected = Member{
key: key,
value: ";",
properties: properties{{key: "foo", hasData: true}},
hasData: true,
}
assert.NoError(t, err)
assert.Equal(t, expected, m)

// Ensure new member is immutable.
p.key = "bar"
assert.Equal(t, expected, m)
Expand All @@ -784,6 +801,17 @@ func TestPropertiesValidate(t *testing.T) {
assert.NoError(t, p.validate())
}

func TestMemberString(t *testing.T) {
// normal key value pair
member, _ := NewMember("key", "value")
memberStr := member.String()
assert.Equal(t, memberStr, "key=value")
// encoded key
member, _ = NewMember("key", "%3B")
memberStr = member.String()
assert.Equal(t, memberStr, "key=%3B")
}

var benchBaggage Baggage

func BenchmarkNew(b *testing.B) {
Expand Down
4 changes: 2 additions & 2 deletions propagation/baggage_test.go
Expand Up @@ -17,6 +17,7 @@ package propagation_test
import (
"context"
"net/http"
"net/url"
"strings"
"testing"

Expand Down Expand Up @@ -46,8 +47,7 @@ func (m member) Member(t *testing.T) baggage.Member {
}
props = append(props, p)
}

bMember, err := baggage.NewMember(m.Key, m.Value, props...)
bMember, err := baggage.NewMember(m.Key, url.QueryEscape(m.Value), props...)
if err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit 0963f59

Please sign in to comment.