This #103008 (comment) from @ManickaP made me double-check the thread-safety of our reading/parsing logic on HttpHeaders.
After #68115, concurrent reads on the header collection are thread-safe. All read operations will see the same values, and won't corrupt the underlying storage.
A minor exception to that is that while they will all see equivalent values, they may not be exactly the same objects. Since some header values are mutable, this could lead to observable differences later.
Simple repro:
while (true)
{
var headers = new ByteArrayContent([]).Headers;
headers.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
var task = Task.Run(() => headers.ContentType);
MediaTypeHeaderValue contentType = headers.ContentType;
await task;
contentType.MediaType = "foo/bar";
if (headers.ContentType.MediaType != "foo/bar")
{
Console.WriteLine("Race condition");
break;
}
}
The fix would be to avoid overwriting the underlying storage with different HeaderStoreItemInfo instances. The simplest way would be via an Interlocked.CompareExchange here:
|
storeValueRef = info = new HeaderStoreItemInfo() { RawValue = value }; |
and here
|
if (EntriesAreLiveView) |
|
{ |
|
entries[i].Value = info; |
|
} |
|
else |
|
{ |
|
Debug.Assert(Contains(entry.Key)); |
|
((Dictionary<HeaderDescriptor, object>)_headerStore!)[entry.Key] = info; |
|
} |
This #103008 (comment) from @ManickaP made me double-check the thread-safety of our reading/parsing logic on
HttpHeaders.After #68115, concurrent reads on the header collection are thread-safe. All read operations will see the same values, and won't corrupt the underlying storage.
A minor exception to that is that while they will all see equivalent values, they may not be exactly the same objects. Since some header values are mutable, this could lead to observable differences later.
Simple repro:
The fix would be to avoid overwriting the underlying storage with different
HeaderStoreItemInfoinstances. The simplest way would be via anInterlocked.CompareExchangehere:runtime/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Line 739 in 7ffb9a4
and here
runtime/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
Lines 352 to 360 in 7ffb9a4