-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Consider updating HttpClientFactory defaults to leverage SocketsHttpHandler #35987
Comments
Tagging subscribers to this area: @dotnet/ncl |
Triage:
We may still use Moving to future. |
We really should do this. Someone should be able to create and hold on to an HttpClient and have things "just work". The fact that it doesn't today is arguably a bug. With this, at least the important case will "just work".
We can when the default handler is used on core, which is the most important case. |
We should also consider pushing the rotation down into a delegating handler. When the primary handler isn't SHH, we can wrap the primary in a handler that will do the rotation, rather than doing it as part of the factory. That way, someone holding on to an HttpClient will still get the rotation under the covers. |
@stephentoub I agree. Both this issue and #47091 are crucial to overcome the most common fallouts. The good thing is that the API prerequisites that they both required are already done within #87914. We've discussed some (potentially ugly 😅) ways to remove rotation from .NET Framework/mobile/browser as well. So it might boil down to just custom primary handlers. re: we cannot remove the rotation entirely -- what I meant in the original comment was that we won't be able to simplify the codebase because we have to leave the code there for certain cases. It will most possibly just make it even more complicated. But I really like the idea of a rotating handler, I will play with this approach to see whether it will work out. We will also have to agree on how much of a breaking change we (and users) could accept. Because technically both changing the default primary handler from |
Triage: Not urgent, moving to Future. The two main parts of the issue are
-- brings the biggest value, and is already addressed by #101808
-- nice to have, not urgent plus there are existing concerns listed above (blocked by #47091) |
#101808 was locked so I can't share my feedback there.
FWIW, this change breaks OpenIddict - according to NuGet.org, the largest project using options.HttpMessageHandlerBuilderActions.Add(builder =>
{
if (builder.PrimaryHandler is not HttpClientHandler handler)
{
throw new InvalidOperationException(SR.FormatID0373(typeof(HttpClientHandler).FullName));
}
// Note: automatic content decompression can be enabled by constructing an HttpClient wrapping
// a generic HttpClientHandler, a SocketsHttpHandler or a WinHttpHandler instance with the
// AutomaticDecompression property set to the desired algorithms (e.g GZip, Deflate or Brotli).
//
// Unfortunately, while convenient and efficient, relying on this property has a downside:
// setting AutomaticDecompression always overrides the Accept-Encoding header of all requests
// to include the selected algorithms without offering a way to make this behavior opt-in.
// Sadly, using HTTP content compression with transport security enabled has security implications
// that could potentially lead to compression side-channel attacks if the client is used with
// remote endpoints that reflect user-defined data and contain secret values (e.g BREACH attacks).
//
// Since OpenIddict itself cannot safely assume such scenarios will never happen (e.g a token request
// will typically be sent with an authorization code that can be defined by a malicious user and can
// potentially be reflected in the token response depending on the configuration of the remote server),
// it is safer to disable compression by default by not sending an Accept-Encoding header while
// still allowing encoded responses to be processed (e.g StackExchange forces content compression
// for all the supported HTTP APIs even if no Accept-Encoding header is explicitly sent by the client).
//
// For these reasons, OpenIddict doesn't rely on the automatic decompression feature and uses
// a custom event handler to deal with GZip/Deflate/Brotli-encoded responses, so that servers
// that require using HTTP compression can be supported without having to use it for all servers.
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.None;
}
// OpenIddict uses IHttpClientFactory to manage the creation of the HTTP clients and
// their underlying HTTP message handlers, that are cached for the specified duration
// and re-used to process multiple requests during that period. While remote APIs are
// typically not expected to return cookies, it is in practice a very frequent case,
// which poses a serious security issue when the cookies are shared across multiple
// requests (which is the case when the same message handler is cached and re-used).
//
// To avoid that, cookies support is explicitly disabled here, for security reasons.
handler.UseCookies = false;
// ...
}); While designing that a while ago, I considered downcasting to other well-known handler types, but:
I'll probably add a |
I can personally think of 3 options to make
|
BTW, a quick GitHub Code search reveals that other projects will be broken too for the same reasons. |
@CarnaViire, what would you like to do here? |
TL;DR: I still need some time to reach a decision. Thanks for bringing this up @kevinchalet. I still think that HttpClientFactory using HttpClientHandler by default is an implementation detail that shouldn't be depended on, but I do see your point -- e.g. we had to do some rather ugly casts ourselves 😞 (it doesn't break, yeah, it works as expected in all cases, but it is ugly) runtime/src/libraries/Microsoft.Extensions.Http/src/MetricsFactoryHttpMessageHandlerFilter.cs Lines 31 to 40 in 29fe6a8
Unfortunately I guess there's no good solution in the 9.0 timeframe. I'm inclined to keep the change, but I need some time to think and consider pros and cons. Reverting the change is fast and easy 😅 but it was introduced for a reason, as well. I see that you have already implemented a workaround @kevinchalet. I wonder if // all clients will have HttpClientHandler by default
services.ConfigureHttpClientDefaults(b =>
b.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler())); or even services.ConfigureHttpClientDefaults(b =>
b.ConfigurePrimaryHttpMessageHandler(() =>
{
var handler = new HttpClientHandler() { UseCookies = false };
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.None;
}
return handler;
})); |
My pleasure! Thanks for taking the time to reply.
I agree. Unfortunately, downcasting is pretty much required as soon as you want to tweak the properties of the handler (
"works as expected in all cases" seems a bit optimistic to me: it only works if the user doesn't replace the default primary handler (that can now be a
It's certainly a positive change, but we really need a better way to amend the handler properties without having to manually downcast to every possible type 😅
No doubt it would work, but it would affect every HTTP client and not just the clients needed by the OpenIddict libraries, including user-defined clients, which is a bit meh (I don't want to force users to use Thanks! |
For .NET 5 we should switch the defaults of the factory:
The problem that's solved by the current behavior (handler rotation) is solved more elegantly by just using the feature for it.
The text was updated successfully, but these errors were encountered: