{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.HTTP.Conduit
(
simpleHttp
, httpLbs
, http
, Proxy (..)
, RequestBody (..)
, Request
, method
, secure
, host
, port
, path
, queryString
, requestHeaders
, requestBody
, proxy
, hostAddress
, rawBody
, decompress
, redirectCount
, checkStatus
, responseTimeout
, cookieJar
, getConnectionWrapper
, requestBodySource
, requestBodySourceChunked
, requestBodySourceIO
, requestBodySourceChunkedIO
, Response
, responseStatus
, responseVersion
, responseHeaders
, responseBody
, responseCookieJar
, Manager
, newManager
, closeManager
, withManager
, withManagerSettings
, ManagerSettings
, conduitManagerSettings
, mkManagerSettings
, managerConnCount
, managerResponseTimeout
, managerTlsConnection
, Cookie(..)
, CookieJar
, createCookieJar
, destroyCookieJar
, parseUrl
, applyBasicAuth
, addProxy
, lbsResponse
, getRedirectedRequest
, alwaysDecompress
, browserDecompress
, urlEncodedBody
, HttpException (..)
) where
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import Data.Conduit (ResumableSource, ($$+-), await, ($$++), ($$+), Source)
import qualified Data.Conduit.Internal as CI
import qualified Data.Conduit.List as CL
import Data.IORef (readIORef, writeIORef, newIORef)
import Data.Int (Int64)
import Control.Applicative ((<$>))
import Control.Exception.Lifted (bracket)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Trans.Resource
import qualified Network.HTTP.Client as Client (httpLbs, responseOpen, responseClose)
import qualified Network.HTTP.Client.Conduit as HCC
import Network.HTTP.Client.Internal (createCookieJar,
destroyCookieJar)
import Network.HTTP.Client.Internal (Manager, ManagerSettings,
closeManager, managerConnCount,
managerResponseTimeout,
managerTlsConnection, newManager)
import Network.HTTP.Client (parseUrl, urlEncodedBody, applyBasicAuth)
import Network.HTTP.Client.Internal (addProxy, alwaysDecompress,
browserDecompress)
import Network.HTTP.Client.Internal (getRedirectedRequest)
import Network.HTTP.Client.TLS (mkManagerSettings,
tlsManagerSettings)
import Network.HTTP.Client.Internal (Cookie (..), CookieJar (..),
HttpException (..), Proxy (..),
Request (..), RequestBody (..),
Response (..))
httpLbs :: MonadIO m => Request -> Manager -> m (Response L.ByteString)
httpLbs r m = liftIO $ Client.httpLbs r m
simpleHttp :: MonadIO m => String -> m L.ByteString
simpleHttp url = liftIO $ withManager $ \man -> do
req <- liftIO $ parseUrl url
responseBody <$> httpLbs (setConnectionClose req) man
conduitManagerSettings :: ManagerSettings
conduitManagerSettings = tlsManagerSettings
withManager :: (MonadIO m, MonadBaseControl IO m)
=> (Manager -> ResourceT m a)
-> m a
withManager = withManagerSettings conduitManagerSettings
withManagerSettings :: (MonadIO m, MonadBaseControl IO m)
=> ManagerSettings
-> (Manager -> ResourceT m a)
-> m a
withManagerSettings set f = bracket
(liftIO $ newManager set)
(liftIO . closeManager)
(runResourceT . f)
setConnectionClose :: Request -> Request
setConnectionClose req = req{requestHeaders = ("Connection", "close") : requestHeaders req}
lbsResponse :: Monad m
=> Response (ResumableSource m S.ByteString)
-> m (Response L.ByteString)
lbsResponse res = do
bss <- responseBody res $$+- CL.consume
return res
{ responseBody = L.fromChunks bss
}
http :: MonadResource m
=> Request
-> Manager
-> m (Response (ResumableSource m S.ByteString))
http req man = do
(key, res) <- allocate (Client.responseOpen req man) Client.responseClose
let rsrc = CI.ResumableSource
(HCC.bodyReaderSource $ responseBody res)
(release key)
return res { responseBody = rsrc }
requestBodySource :: Int64 -> Source (ResourceT IO) S.ByteString -> RequestBody
requestBodySource size = RequestBodyStream size . srcToPopper
requestBodySourceChunked :: Source (ResourceT IO) S.ByteString -> RequestBody
requestBodySourceChunked = RequestBodyStreamChunked . srcToPopper
srcToPopper :: Source (ResourceT IO) S.ByteString -> HCC.GivesPopper ()
srcToPopper src f = runResourceT $ do
(rsrc0, ()) <- src $$+ return ()
irsrc <- liftIO $ newIORef rsrc0
is <- getInternalState
let popper :: IO S.ByteString
popper = do
rsrc <- readIORef irsrc
(rsrc', mres) <- runInternalState (rsrc $$++ await) is
writeIORef irsrc rsrc'
case mres of
Nothing -> return S.empty
Just bs
| S.null bs -> popper
| otherwise -> return bs
liftIO $ f popper
requestBodySourceIO :: Int64 -> Source IO S.ByteString -> RequestBody
requestBodySourceIO = HCC.requestBodySource
requestBodySourceChunkedIO :: Source IO S.ByteString -> RequestBody
requestBodySourceChunkedIO = HCC.requestBodySourceChunked