diff --git a/CHANGELOG.md b/CHANGELOG.md index 33937681837..c26bfe1da1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc` does no longer depend on `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4660) - `go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp` does no longer depend on `go.opentelemetry.io/otel/exporters/otlp/otlpmetric`. (#4660) +### Fixed + +- `baggage.NewMember` and `baggage.parseMember` use `url.PathUnescape` rather than `url.QueryUnescape`, preventing mangling of characters that are valid as baggage values but not query strings. (#3601) + ## [1.19.0/0.42.0/0.0.7] 2023-09-28 This release contains the first stable release of the OpenTelemetry Go [metric SDK]. diff --git a/baggage/baggage.go b/baggage/baggage.go index 9e6b3b7b52a..84532cb1da3 100644 --- a/baggage/baggage.go +++ b/baggage/baggage.go @@ -254,7 +254,7 @@ func NewMember(key, value string, props ...Property) (Member, error) { if err := m.validate(); err != nil { return newInvalidMember(), err } - decodedValue, err := url.QueryUnescape(value) + decodedValue, err := url.PathUnescape(value) if err != nil { return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) } @@ -301,7 +301,7 @@ func parseMember(member string) (Member, error) { // when converting the header into a data structure." key = strings.TrimSpace(k) var err error - value, err = url.QueryUnescape(strings.TrimSpace(v)) + value, err = url.PathUnescape(strings.TrimSpace(v)) if err != nil { return newInvalidMember(), fmt.Errorf("%w: %q", err, value) } diff --git a/baggage/baggage_test.go b/baggage/baggage_test.go index 2b98beace10..4bac6707ea0 100644 --- a/baggage/baggage_test.go +++ b/baggage/baggage_test.go @@ -275,6 +275,48 @@ func TestBaggageParse(t *testing.T) { "foo": {Value: "1"}, }, }, + { + name: "single member no properties plus", + in: "foo=1+1", + want: baggage.List{ + "foo": {Value: "1+1"}, + }, + }, + { + name: "single member no properties plus encoded", + in: "foo=1%2B1", + want: baggage.List{ + "foo": {Value: "1+1"}, + }, + }, + { + name: "single member no properties slash", + in: "foo=1/1", + want: baggage.List{ + "foo": {Value: "1/1"}, + }, + }, + { + name: "single member no properties slash encoded", + in: "foo=1%2F1", + want: baggage.List{ + "foo": {Value: "1/1"}, + }, + }, + { + name: "single member no properties equals", + in: "foo=1=1", + want: baggage.List{ + "foo": {Value: "1=1"}, + }, + }, + { + name: "single member no properties equals encoded", + in: "foo=1%3D1", + want: baggage.List{ + "foo": {Value: "1=1"}, + }, + }, { name: "single member with spaces", in: " foo \t= 1\t\t ", @@ -440,6 +482,13 @@ func TestBaggageString(t *testing.T) { "foo": {Value: "1=1"}, }, }, + { + name: "plus", + out: "foo=1%2B1", + baggage: baggage.List{ + "foo": {Value: "1+1"}, + }, + }, { name: "single member empty value with properties", out: "foo=;red;state=on",