Skip to content

Commit 81008e5

Browse files
[release/3.1] Preserve client order of activity baggage items (#26302) (#26398)
* Preserve client order of activity baggage items (#26302) * Add missing using Co-authored-by: Andrey Tretyak <[email protected]>
1 parent e4fdd4a commit 81008e5

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Diagnostics;
66
using System.Runtime.CompilerServices;
7+
using System.Web;
78
using Microsoft.AspNetCore.Http;
89
using Microsoft.Extensions.Logging;
910
using Microsoft.Extensions.Primitives;
@@ -262,14 +263,14 @@ private Activity StartActivity(HttpContext httpContext, out bool hasDiagnosticLi
262263
// We expect baggage to be empty by default
263264
// Only very advanced users will be using it in near future, we encourage them to keep baggage small (few items)
264265
string[] baggage = headers.GetCommaSeparatedValues(HeaderNames.CorrelationContext);
265-
if (baggage.Length > 0)
266+
267+
// 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
268+
// An order could be important if baggage has two items with the same key (that is allowed by the contract)
269+
for (var i = baggage.Length - 1; i >= 0; i--)
266270
{
267-
foreach (var item in baggage)
271+
if (NameValueHeaderValue.TryParse(baggage[i], out var baggageItem))
268272
{
269-
if (NameValueHeaderValue.TryParse(item, out var baggageItem))
270-
{
271-
activity.AddBaggage(baggageItem.Name.ToString(), baggageItem.Value.ToString());
272-
}
273+
activity.AddBaggage(baggageItem.Name.ToString(), HttpUtility.UrlDecode(baggageItem.Value.ToString()));
273274
}
274275
}
275276
}

src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,42 @@ public void ActivityParentIdAndBaggeReadFromHeaders()
345345
Assert.Contains(Activity.Current.Baggage, pair => pair.Key == "Key2" && pair.Value == "value2");
346346
}
347347

348+
[Fact]
349+
public void ActivityBaggagePreservesItemsOrder()
350+
{
351+
var diagnosticListener = new DiagnosticListener("DummySource");
352+
var hostingApplication = CreateApplication(out var features, diagnosticListener: diagnosticListener);
353+
354+
diagnosticListener.Subscribe(new CallbackDiagnosticListener(pair => { }),
355+
s =>
356+
{
357+
if (s.StartsWith("Microsoft.AspNetCore.Hosting.HttpRequestIn"))
358+
{
359+
return true;
360+
}
361+
return false;
362+
});
363+
364+
features.Set<IHttpRequestFeature>(new HttpRequestFeature()
365+
{
366+
Headers = new HeaderDictionary()
367+
{
368+
{"Request-Id", "ParentId1"},
369+
{"Correlation-Context", "Key1=value1, Key2=value2, Key1=value3"} // duplicated keys allowed by the contract
370+
}
371+
});
372+
hostingApplication.CreateContext(features);
373+
Assert.Equal("Microsoft.AspNetCore.Hosting.HttpRequestIn", Activity.Current.OperationName);
374+
375+
var expectedBaggage = new []
376+
{
377+
KeyValuePair.Create("Key1","value1"),
378+
KeyValuePair.Create("Key2","value2"),
379+
KeyValuePair.Create("Key1","value3")
380+
};
381+
382+
Assert.Equal(expectedBaggage, Activity.Current.Baggage);
383+
}
348384

349385
[Fact]
350386
public void ActivityTraceParentAndTraceStateFromHeaders()

0 commit comments

Comments
 (0)