-
Notifications
You must be signed in to change notification settings - Fork 192
Description
I ran into an issue with using httpSource to fetch a file from a website requiring basic authentication. What I found was that the website served the file by issuing a redirect to an Amazon service with separate authorization in the form of a X-Amz-Algorithm query parameter. The problem was that when responseOpen encountered the redirect it carried the Authorization header onto the redirect request, and the Amazon service responds with an error if it receives a request with more than one auth mechanism.
In my research I found that which headers are carried over for a redirected request is generally unspecified. It seems however that the behavior of browsers and curl is to strip the Authorization header on a redirect if the host of the Location response header is different than the host of the original request. Though curl has a option (--location-trusted) to disable this behavior if desired.
In general this seems to be done as a security feature (particularly for http basic authentication), but in my case the website depended on it. I'm unsure what, if any, action should be taken for the http-client library, but this seemed worth bringing up.
There's some decent discussion on header behavior with redirects in golang/go#4800 for their net/http library.
I'm including my workaround here in case anyone runs into the same issue. Gist here for syntax highlighting.
-- Need to see how this handles errors and probably fix infinite
-- redirect possibility. Also should probably not strip auth if the
-- host is the same.
redirectHttpBodySource :: Request -> Source LoaderIO ByteString
redirectHttpBodySource req = httpSource req doRedirects
where removeAuthHeader req' =
setRequestHeaders (filter ((/= hAuthorization) . fst) $ requestHeaders req') req'
doRedirects res = do
let code = getResponseStatusCode res
respHeaders = getResponseHeaders res
cookieJar = responseCookieJar res
mRedirect = getRedirectedRequest req respHeaders cookieJar code
case mRedirect of
Nothing -> getResponseBody res
Just req' -> redirectHttpBodySource $ removeAuthHeader req'
-- Make sure to set redirect count to 0
-- redirectHttpBodySource req { redirectCount = 0 }