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

Make concurrent reads on HttpHeaders thread-safe #68115

Merged
merged 1 commit into from
May 6, 2022

Conversation

MihaZupan
Copy link
Member

@MihaZupan MihaZupan commented Apr 16, 2022

Fixes #61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupan MihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupan MihaZupan self-assigned this Apr 16, 2022
@ghost
Copy link

ghost commented Apr 16, 2022

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author: MihaZupan
Assignees: MihaZupan
Labels:

area-System.Net.Http

Milestone: 7.0.0

@MihaZupan MihaZupan requested a review from a team April 16, 2022 18:47
@MihaZupan
Copy link
Member Author

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if (entries[i].Value is HeaderStoreItemInfo)
{
    // ...
}
else
{
    DoSomething((string)entries[i].Value); // Wrong! The value may now be HeaderStoreItemInfo
}

and it should instead be something like

object value = entries[i].Value;
if (value is HeaderStoreItemInfo)
{
    // ...
}
else
{
    DoSomething((string)value);
}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

Copy link
Member

@CarnaViire CarnaViire left a comment

Choose a reason for hiding this comment

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

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire
Copy link
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan
Copy link
Member Author

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan MihaZupan merged commit b00a64d into dotnet:main May 6, 2022
@juharris
Copy link

juharris commented May 9, 2022

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan
Copy link
Member Author

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghost ghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values
5 participants