module Utils.Http (send) where
import qualified Control.Exception as E
import Control.Monad.Error
import qualified Data.ByteString.Char8 as BSC
import qualified Data.List as List
import Network (withSocketsDo)
import Network.HTTP.Client
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Network.HTTP.Types
send
:: (MonadIO m, MonadError String m)
=> String
-> (Request -> Manager -> IO a)
-> m a
send url handler =
do result <- liftIO (sendSafe url handler)
either throwError return result
sendSafe :: String -> (Request -> Manager -> IO a) -> IO (Either String a)
sendSafe url handler =
sendUnsafe url handler
`E.catch` handleHttpError url
`E.catch` (handleAnyError url :: E.SomeException -> IO (Either String b))
sendUnsafe :: String -> (Request -> Manager -> IO a) -> IO (Either err a)
sendUnsafe url handler =
do request <- parseUrl url
result <- withSocketsDo $ withManager tlsManagerSettings (handler request)
return (Right result)
handleHttpError :: String -> HttpException -> IO (Either String b)
handleHttpError url exception =
case exception of
StatusCodeException (Status _code err) headers _ ->
let details =
case List.lookup "X-Response-Body-Start" headers of
Just msg | not (BSC.null msg) -> msg
_ -> err
in
return . Left $ BSC.unpack details
_ -> handleAnyError url exception
handleAnyError :: (E.Exception e) => String -> e -> IO (Either String b)
handleAnyError url exception =
return . Left $
"failed with '" ++ show exception ++ "' when sending request to\n" ++
" <" ++ url ++ ">"