diff --git a/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs b/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs index 57bdb453b8f..0923b1bdfa6 100644 --- a/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs +++ b/src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs @@ -1,8 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -using System.Net; using System.Text; + using OpenTelemetry.Internal; namespace OpenTelemetry.Context.Propagation; @@ -94,7 +94,7 @@ public override void Inject(PropagationContext context, T carrier, Action= '#' && ch <= '+') || // 0x23-0x2B + (ch >= '-' && ch <= ':') || // 0x2D-0x3A + (ch >= '<' && ch <= '[') || // 0x3C-0x5B + (ch >= ']' && ch <= '~'); // 0x5D-0x7E + } + + // originated from https://github.com/dotnet/runtime/blob/9429e432f39786e1bcd1c080833e5d7691946591/src/libraries/System.Private.CoreLib/src/System/Net/WebUtility.cs#L328 + // Modified to percent-encode the space char. + private static void GetEncodedBytes(byte[] originalBytes, int offset, int count, byte[] expandedBytes) + { + int pos = 0; + int end = offset + count; + for (int i = offset; i < end; i++) + { + byte b = originalBytes[i]; + char ch = (char)b; + if (RequiresPercentEncoding(ch)) + { + expandedBytes[pos++] = (byte)'%'; + expandedBytes[pos++] = (byte)ToCharUpper(b >> 4); + expandedBytes[pos++] = (byte)ToCharUpper(b); + } + else + { + expandedBytes[pos++] = b; + } + } + } + + // originated from https://github.com/dotnet/runtime/blob/9429e432f39786e1bcd1c080833e5d7691946591/src/libraries/Common/src/System/HexConverter.cs#L203 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static char ToCharUpper(int value) + { + value &= 0xF; + value += '0'; + + if (value > '9') + { + value += 'A' - ('9' + 1); + } + + return (char)value; + } +} diff --git a/test/OpenTelemetry.Api.Tests/Trace/Propagation/BaggagePropagatorTest.cs b/test/OpenTelemetry.Api.Tests/Trace/Propagation/BaggagePropagatorTest.cs index 097f63e039d..b0575f1850b 100644 --- a/test/OpenTelemetry.Api.Tests/Trace/Propagation/BaggagePropagatorTest.cs +++ b/test/OpenTelemetry.Api.Tests/Trace/Propagation/BaggagePropagatorTest.cs @@ -131,7 +131,8 @@ public void ValidateSpecialCharsBaggageExtraction() Assert.Equal("key%28%293", escapedKey); Assert.Equal("value%28%29%21%26%3B%3A", escapedValue); - var initialBaggage = $"key+1=value+1,{encodedKey}={encodedValue},{escapedKey}={escapedValue}"; + var initialBaggage = + $"key%201=value%201,{encodedKey}={encodedValue},{escapedKey}={escapedValue},key4=%20!%22#$%25&'()*+%2C-./0123456789:%3B<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]^_`abcdefghijklmnopqrstuvwxyz{{|}}~"; var carrier = new List> { new KeyValuePair(BaggagePropagator.BaggageHeaderName, initialBaggage), @@ -142,11 +143,11 @@ public void ValidateSpecialCharsBaggageExtraction() Assert.False(propagationContext == default); Assert.True(propagationContext.ActivityContext == default); - Assert.Equal(3, propagationContext.Baggage.Count); + Assert.Equal(4, propagationContext.Baggage.Count); var actualBaggage = propagationContext.Baggage.GetBaggage(); - Assert.Equal(3, actualBaggage.Count); + Assert.Equal(4, actualBaggage.Count); Assert.True(actualBaggage.ContainsKey("key 1")); Assert.Equal("value 1", actualBaggage["key 1"]); @@ -156,6 +157,9 @@ public void ValidateSpecialCharsBaggageExtraction() Assert.True(actualBaggage.ContainsKey("key()3")); Assert.Equal("value()!&;:", actualBaggage["key()3"]); + + Assert.True(actualBaggage.ContainsKey("key4")); + Assert.Equal(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", actualBaggage["key4"]); } [Fact] @@ -195,11 +199,12 @@ public void ValidateSpecialCharsBaggageInjection() { { "key 1", "value 1" }, { "key2", "!x_x,x-x&x(x\");:" }, + { "key3", " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" }, })); this.baggage.Inject(propagationContext, carrier, Setter); Assert.Single(carrier); - Assert.Equal("key+1=value+1,key2=!x_x%2Cx-x%26x(x%22)%3B%3A", carrier[BaggagePropagator.BaggageHeaderName]); + Assert.Equal("key%201=value%201,key2=!x_x%2Cx-x&x(x%22)%3B:,key3=%20!%22#$%25&'()*+%2C-./0123456789:%3B<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[%5C]^_`abcdefghijklmnopqrstuvwxyz{|}~", carrier[BaggagePropagator.BaggageHeaderName]); } }