Redirects
editWhy the handler follows redirects
A redirect followed by the inner handler never goes back through HstsClientHandler: a redirect to an HSTS host would be requested over HTTP. So the handler follows the redirects itself, and every hop is checked against the policies:
// http://example.com/go redirects to http://github.com, which is in the preload list.
// The redirect is followed as https://github.com
using var response = await client.GetAsync("http://example.com/go");The Strict-Transport-Security header of every hop is read too.
The redirects are followed with the rules of SocketsHttpHandler:
- A
Locationheader that is relative is resolved against the URI of the request that received it. - A redirect from HTTPS to HTTP is never followed, nor a redirect to a scheme other than
httpandhttps: the redirect response is returned. 300,301and302turn aPOSTinto aGET, and303turns any method other thanGETandHEADinto aGET; the body is dropped with the method.307and308keep the method and the body.- The
Authorizationheader is removed: the credentials were meant for the host that answered, not for the one it points to. - The fragment of the original URL carries over to a
Locationthat has none.
The inner handler is modified
To avoid following the redirects twice, the handler turns AllowAutoRedirect off on the inner handler when it is a SocketsHttpHandler or an HttpClientHandler that follows them, and uses its MaxAutomaticRedirections as its own limit. A DelegatingHandler between them is looked through.
This happens on the first request, not in the constructor. Two consequences:
- An inner handler shared with another
HttpClientstops following redirects for that client too. - An inner handler that has already sent a request cannot be reconfigured: the first request through HstsClientHandler throws an
InvalidOperationException.
Follow redirects without touching the inner handler
Pass maxAutomaticRedirections to the constructor, and configure the inner handler not to follow the redirects. This is how you add HSTS to a shared or an already used handler, and the only way to follow redirects when the inner handler is of another type:
var inner = new SocketsHttpHandler { AllowAutoRedirect = false };
using var client = new HttpClient(new HstsClientHandler(inner, policies, maxAutomaticRedirections: 50), disposeHandler: true);With maxAutomaticRedirections: 0, the handler follows no redirect.
Do not follow redirects
An inner handler already configured not to follow redirects is left untouched, and the handler does not follow them either: the redirect responses are returned to the caller:
// HstsClientHandler does not follow redirects either: the 3xx response is returned as is
var inner = new SocketsHttpHandler { AllowAutoRedirect = false };
using var client = new HttpClient(new HstsClientHandler(inner, policies), disposeHandler: true);An inner handler of a type the handler does not recognize keeps its own behavior, unless you pass maxAutomaticRedirections.
With IHttpClientFactory, the primary handler belongs to the pipeline of the client, so the take-over only affects that client. Configure the primary handler not to follow redirects only if the client must not follow them at all.