module Network.HTTP.Client.Response
( getRedirectedRequest
, getResponse
, lbsResponse
) where
import Control.Monad ((>=>), when)
import Control.Exception (throwIO)
import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy as L
import Data.Default.Class (def)
import Data.Maybe (isJust)
import qualified Network.HTTP.Types as W
import Network.URI (parseURIReference, escapeURIString, isAllowedInURI)
import Network.HTTP.Client.Types
import Network.HTTP.Client.Request
import Network.HTTP.Client.Util
import Network.HTTP.Client.Body
import Network.HTTP.Client.Headers
getRedirectedRequest :: Request -> W.ResponseHeaders -> CookieJar -> Int -> Maybe Request
getRedirectedRequest req hs cookie_jar code
| 300 <= code && code < 400 = do
l' <- lookup "location" hs
let l = escapeURIString isAllowedInURI (S8.unpack l')
req' <- setUriRelative req =<< parseURIReference l
return $
if code == 302 || code == 303
then req'
{ method = "GET"
, requestBody = RequestBodyBS ""
, cookieJar = cookie_jar'
, requestHeaders = filter ((/= W.hContentType) . fst) $ requestHeaders req'
}
else req' {cookieJar = cookie_jar'}
| otherwise = Nothing
where
cookie_jar' = fmap (const cookie_jar) $ cookieJar req
lbsResponse :: Response BodyReader -> IO (Response L.ByteString)
lbsResponse res = do
bss <- brConsume $ responseBody res
return res
{ responseBody = L.fromChunks bss
}
getResponse :: ConnRelease
-> Maybe Int
-> Request
-> Connection
-> IO (Response BodyReader)
getResponse connRelease timeout'' req@(Request {..}) conn = do
let timeout' =
case timeout'' of
Nothing -> id
Just t -> timeout t >=> maybe (throwIO ResponseTimeout) return
StatusHeaders s version hs <- timeout' $ parseStatusHeaders conn
let mcl = lookup "content-length" hs >>= readDec . S8.unpack
isChunked = ("transfer-encoding", "chunked") `elem` hs
toPut = Just "close" /= lookup "connection" hs && version > W.HttpVersion 1 0
cleanup bodyConsumed = connRelease $ if toPut && bodyConsumed then Reuse else DontReuse
when (isJust mcl && isChunked) $ do
cleanup False
throwIO ResponseLengthAndChunkingBothUsed
body <-
if hasNoBody method (W.statusCode s) || mcl == Just 0
then do
cleanup True
return brEmpty
else do
body1 <-
if isChunked
then makeChunkedReader rawBody conn
else
case mcl of
Just len -> makeLengthReader len conn
Nothing -> makeUnlimitedReader conn
body2 <- if needsGunzip req hs
then makeGzipReader body1
else return body1
return $ brAddCleanup (cleanup True) body2
return Response
{ responseStatus = s
, responseVersion = version
, responseHeaders = hs
, responseBody = body
, responseCookieJar = def
, responseClose' = ResponseClose (cleanup False)
}