Skip to content

Commit 2f64d67

Browse files
authored
Support W3C Baggage header (dotnet#28328)
1 parent 4853d00 commit 2f64d67

File tree

4 files changed

+75
-6
lines changed

4 files changed

+75
-6
lines changed

src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,11 @@ private Activity StartActivity(HttpContext httpContext, out bool hasDiagnosticLi
266266

267267
// We expect baggage to be empty by default
268268
// Only very advanced users will be using it in near future, we encourage them to keep baggage small (few items)
269-
string[] baggage = headers.GetCommaSeparatedValues(HeaderNames.CorrelationContext);
269+
var baggage = headers.GetCommaSeparatedValues(HeaderNames.Baggage);
270+
if (baggage.Length == 0)
271+
{
272+
baggage = headers.GetCommaSeparatedValues(HeaderNames.CorrelationContext);
273+
}
270274

271275
// AddBaggage adds items at the beginning of the list, so we need to add them in reverse to keep the same order as the client
272276
// An order could be important if baggage has two items with the same key (that is allowed by the contract)

src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public void ActivityIsAvailibleDuringRequest()
271271
}
272272

273273
[Fact]
274-
public void ActivityParentIdAndBaggeReadFromHeaders()
274+
public void ActivityParentIdAndBaggageReadFromHeaders()
275275
{
276276
var diagnosticListener = new DiagnosticListener("DummySource");
277277
var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener);
@@ -291,7 +291,7 @@ public void ActivityParentIdAndBaggeReadFromHeaders()
291291
Headers = new HeaderDictionary()
292292
{
293293
{"Request-Id", "ParentId1"},
294-
{"Correlation-Context", "Key1=value1, Key2=value2"}
294+
{"baggage", "Key1=value1, Key2=value2"}
295295
}
296296
});
297297
hostingApplication.CreateContext(features);
@@ -301,6 +301,67 @@ public void ActivityParentIdAndBaggeReadFromHeaders()
301301
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value2");
302302
}
303303

304+
[Fact]
305+
public void ActivityBaggageReadFromLegacyHeaders()
306+
{
307+
var diagnosticListener = new DiagnosticListener("DummySource");
308+
var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener);
309+
310+
diagnosticListener.Subscribe(new CallbackDiagnosticListener(pair => { }),
311+
s =>
312+
{
313+
if (s.StartsWith("Microsoft.AspNetCore.Hosting.HttpRequestIn", StringComparison.Ordinal))
314+
{
315+
return true;
316+
}
317+
return false;
318+
});
319+
320+
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
321+
{
322+
Headers = new HeaderDictionary()
323+
{
324+
{"Request-Id", "ParentId1"},
325+
{"Correlation-Context", "Key1=value1, Key2=value2"}
326+
}
327+
});
328+
hostingApplication.CreateContext(features);
329+
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
330+
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key1" && pair.Value == "value1");
331+
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value2");
332+
}
333+
334+
[Fact]
335+
public void ActivityBaggagePrefersW3CBaggageHeaderName()
336+
{
337+
var diagnosticListener = new DiagnosticListener("DummySource");
338+
var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener);
339+
340+
diagnosticListener.Subscribe(new CallbackDiagnosticListener(pair => { }),
341+
s =>
342+
{
343+
if (s.StartsWith("Microsoft.AspNetCore.Hosting.HttpRequestIn", StringComparison.Ordinal))
344+
{
345+
return true;
346+
}
347+
return false;
348+
});
349+
350+
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
351+
{
352+
Headers = new HeaderDictionary()
353+
{
354+
{"Request-Id", "ParentId1"},
355+
{"Correlation-Context", "Key1=value1, Key2=value2"},
356+
{"baggage", "Key1=value3, Key2=value4"}
357+
}
358+
});
359+
hostingApplication.CreateContext(features);
360+
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
361+
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key1" && pair.Value == "value3");
362+
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value4");
363+
}
364+
304365
[Fact]
305366
public void ActivityBaggagePreservesItemsOrder()
306367
{
@@ -322,7 +383,7 @@ public void ActivityBaggagePreservesItemsOrder()
322383
Headers = new HeaderDictionary()
323384
{
324385
{"Request-Id", "ParentId1"},
325-
{"Correlation-Context", "Key1=value1, Key2=value2, Key1=value3"} // duplicated keys allowed by the contract
386+
{"baggage", "Key1=value1, Key2=value2, Key1=value3"} // duplicated keys allowed by the contract
326387
}
327388
});
328389
hostingApplication.CreateContext(features);
@@ -359,7 +420,7 @@ public void ActivityBaggageValuesAreUrlDecodedFromHeaders()
359420
Headers = new HeaderDictionary()
360421
{
361422
{"Request-Id", "ParentId1"},
362-
{"Correlation-Context", "Key1=value1%2F1"}
423+
{"baggage", "Key1=value1%2F1"}
363424
}
364425
});
365426
hostingApplication.CreateContext(features);
@@ -389,7 +450,7 @@ public void ActivityTraceParentAndTraceStateFromHeaders()
389450
{
390451
{"traceparent", "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"},
391452
{"tracestate", "TraceState1"},
392-
{"Correlation-Context", "Key1=value1, Key2=value2"}
453+
{"baggage", "Key1=value1, Key2=value2"}
393454
}
394455
});
395456
hostingApplication.CreateContext(features);

src/Http/Headers/src/HeaderNames.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public static class HeaderNames
6464
/// <summary>Gets the <c>Authorization</c> HTTP header name.</summary>
6565
public static readonly string Authorization = "Authorization";
6666

67+
/// <summary>Gets the <c>baggage</c> HTTP header name.</summary>
68+
public static readonly string Baggage = "baggage";
69+
6770
/// <summary>Gets the <c>Cache-Control</c> HTTP header name.</summary>
6871
public static readonly string CacheControl = "Cache-Control";
6972

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#nullable enable
22
Microsoft.Net.Http.Headers.MediaTypeHeaderValue.MatchesMediaType(Microsoft.Extensions.Primitives.StringSegment otherMediaType) -> bool
33
Microsoft.Net.Http.Headers.RangeConditionHeaderValue.RangeConditionHeaderValue(Microsoft.Net.Http.Headers.EntityTagHeaderValue! entityTag) -> void
4+
static readonly Microsoft.Net.Http.Headers.HeaderNames.Baggage -> string!
45
static readonly Microsoft.Net.Http.Headers.HeaderNames.ProxyConnection -> string!

0 commit comments

Comments
 (0)