Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix TraceContextPropagator behavior when trace parent flags contain… #4893

4 changes: 4 additions & 0 deletions src/OpenTelemetry.Api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
`GetTracer` from leaking memory.
([#4906](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4906))

* Fix `TraceContextPropagator` by validating the first digit of the hex-encoded
`trace-flags` field of the `traceparent` header.
([#4893](https://github.com/open-telemetry/opentelemetry-dotnet/pull/4893))

## 1.6.0

Released 2023-Sep-05
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,19 +195,20 @@ internal static bool TryExtractTraceparent(string traceparent, out ActivityTrace
return false;
}

byte options1;
byte optionsLowByte;
try
{
spanId = ActivitySpanId.CreateFromString(traceparent.AsSpan().Slice(VersionAndTraceIdLength, SpanIdLength));
options1 = HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength + 1]);
_ = HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength]); // to verify if there is no bad chars on options position
optionsLowByte = HexCharToByte(traceparent[VersionAndTraceIdAndSpanIdLength + 1]);
}
catch (ArgumentOutOfRangeException)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is outside the scope of this PR but we don't use the exception in any way. We could simply update HexCharToByte method to return false instead of throwing an unused exception.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kielek Would you mind updating this follow-up PRs?

{
// it's ok to still parse tracestate
return false;
}

if ((options1 & 1) == 1)
if ((optionsLowByte & 1) == 1)
{
traceOptions |= ActivityTraceFlags.Recorded;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class W3CTraceContextTests : IDisposable
*/
private const string W3cTraceContextEnvVarName = "OTEL_W3CTRACECONTEXT";
private static readonly Version AspNetCoreHostingVersion = typeof(Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory).Assembly.GetName().Version;
private readonly HttpClient httpClient = new HttpClient();
private readonly HttpClient httpClient = new();
private readonly ITestOutputHelper output;

public W3CTraceContextTests(ITestOutputHelper output)
Expand Down Expand Up @@ -107,7 +107,7 @@ public void W3CTraceContextTestSuiteAsync(string value)
}
else
{
Assert.StartsWith("FAILED (failures=3)", lastLine);
Assert.StartsWith("FAILED (failures=2)", lastLine);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,16 @@ public void IsBlankIfNoHeader()
Assert.False(ctx.ActivityContext.IsValid());
}

[Fact]
public void IsBlankIfInvalid()
[Theory]
[InlineData($"00-xyz7651916cd43dd8448eb211c80319c-{SpanId}-01")]
[InlineData($"00-{TraceId}-xyz7c989f97918e1-01")]
[InlineData($"00-{TraceId}-{SpanId}-x1")]
[InlineData($"00-{TraceId}-{SpanId}-1x")]
public void IsBlankIfInvalid(string invalidTraceParent)
{
var headers = new Dictionary<string, string>
{
{ TraceParent, $"00-xyz7651916cd43dd8448eb211c80319c-{SpanId}-01" },
{ TraceParent, invalidTraceParent },
};

var f = new TraceContextPropagator();
Expand Down Expand Up @@ -191,8 +195,8 @@ public void DuplicateKeys()
// test_tracestate_duplicated_keys
Assert.Empty(CallTraceContextPropagator("foo=1,foo=1"));
Assert.Empty(CallTraceContextPropagator("foo=1,foo=2"));
Assert.Empty(CallTraceContextPropagator(new string[] { "foo=1", "foo=1" }));
Assert.Empty(CallTraceContextPropagator(new string[] { "foo=1", "foo=2" }));
Assert.Empty(CallTraceContextPropagator(new[] { "foo=1", "foo=1" }));
Assert.Empty(CallTraceContextPropagator(new[] { "foo=1", "foo=2" }));
}

[Fact]
Expand Down Expand Up @@ -318,7 +322,7 @@ private static string CallTraceContextPropagator(string[] tracestate)
{
var headers = new Dictionary<string, string[]>
{
{ TraceParent, new string[] { $"00-{TraceId}-{SpanId}-01" } },
{ TraceParent, new[] { $"00-{TraceId}-{SpanId}-01" } },
{ TraceState, tracestate },
};
var f = new TraceContextPropagator();
Expand Down