Skip to content

Minor race condition in HttpHeaders parsing #103238

@MihaZupan

Description

@MihaZupan

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;
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions