Skip to content

Conversation

@stephentoub
Copy link
Member

This lock existed to protect HttpClient.DefaultRequestHeaders. While headers collections aren't meant to be thread-safe, out of necessity the design of DefaultRequestHeaders required this lock be in place, with multiple concurrent requests all potentially enumerating DefaultRequestHeaders in order to copy its contents into the outgoing request. Such enumeration could trigger parsing, which could trigger the same object to be mutated from multiple threads to store the parsed result, hence the lock. But as of #49673, we no longer force parsing of the DefaultRequestHeaders, instead preferring to just transfer everything over as-is. With that, there shouldn't be any concurrent mutation of these objects (and if there is, it's user error doing their own concurrent enumeration of a header collection).

Please quadruple check me on this 😄
cc: @geoffkizer, @scalablecory

This lock existed to protect HttpClient.DefaultRequestHeaders.  While headers collections aren't meant to be thread-safe, out of necessity the design of DefaultRequestHeaders required this lock be in place, with multiple concurrent requests all potentially enumerating DefaultRequestHeaders in order to copy its contents into the outgoing request.  Such enumeration could trigger parsing, which could trigger the same object to be mutated from multiple threads to store the parsed result.  But as of dotnet#49673, we no longer force parsing of the DefaultRequestHeaders, instead preferring to just transfer everything over as-is.  With that, there shouldn't be any concurrent mutation of these objects (and if there is, it's user error doing their own concurrent enumeration of a header collection).
@ghost ghost added the area-System.Net.Http label Jun 14, 2021
@ghost
Copy link

ghost commented Jun 14, 2021

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

Issue Details

This lock existed to protect HttpClient.DefaultRequestHeaders. While headers collections aren't meant to be thread-safe, out of necessity the design of DefaultRequestHeaders required this lock be in place, with multiple concurrent requests all potentially enumerating DefaultRequestHeaders in order to copy its contents into the outgoing request. Such enumeration could trigger parsing, which could trigger the same object to be mutated from multiple threads to store the parsed result, hence the lock. But as of #49673, we no longer force parsing of the DefaultRequestHeaders, instead preferring to just transfer everything over as-is. With that, there shouldn't be any concurrent mutation of these objects (and if there is, it's user error doing their own concurrent enumeration of a header collection).

Please quadruple check me on this 😄
cc: @geoffkizer, @scalablecory

Author: stephentoub
Assignees: -
Labels:

area-System.Net.Http

Milestone: -

@stephentoub stephentoub merged commit bfb8d6b into dotnet:main Jun 15, 2021
@stephentoub stephentoub deleted the removestalelock branch June 15, 2021 00:15
@ghost ghost locked as resolved and limited conversation to collaborators Jul 15, 2021
@karelz karelz added this to the 6.0.0 milestone Jul 15, 2021
@MihaZupan
Copy link
Member

Note from #55898 (comment):

This lock was preventing side-effects of reading the collection from multiple threads.
While not documented as thread-safe, the implementation details in 5.0 allowed it to be used as such "safely".

For example, we may have allocated HeaderStoreItemInfo multiple times for the same header and tried to parse it multiple times, but since parsing is idempotent that remained hidden to the user.

We may have modified the internal dictionary, but dict.Remove(key) and dict[key] = value will for the most part work fine from multiple threads if we're not doing any inserts.

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.

4 participants