http-enumerator-0.5.0: Network/TLS/Client/Enumerator.hs
module Network.TLS.Client.Enumerator
( ConnInfo
, connClose
, connIter
, connEnum
, sslClientConn
, socketConn
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import System.IO (Handle, hClose)
import Network.Socket (Socket, sClose)
import Network.Socket.ByteString (recv, sendAll)
import Network.TLS
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.Class (lift)
import Data.Enumerator
( Iteratee (..), Enumerator, Step (..), Stream (..), continue, returnI
)
import Data.Certificate.X509 (X509)
data ConnInfo = ConnInfo
{ connRead :: IO [ByteString]
, connWrite :: [ByteString] -> IO ()
, connClose :: IO ()
}
connIter :: MonadIO m => ConnInfo -> Iteratee ByteString m ()
connIter ConnInfo { connWrite = write } =
continue go
where
go EOF = return ()
go (Chunks bss) = do
liftIO $ write bss
continue go
connEnum :: MonadIO m => ConnInfo -> Enumerator ByteString m b
connEnum ConnInfo { connRead = read' } =
go
where
go (Continue k) = do
bs <- liftIO read'
if all S.null bs
then continue k
else do
step <- lift $ runIteratee $ k $ Chunks bs
go step
go step = returnI step
socketConn :: Socket -> ConnInfo
socketConn sock = ConnInfo
{ connRead = fmap return $ recv sock 4096
, connWrite = mapM_ (sendAll sock)
, connClose = sClose sock
}
sslClientConn :: ([X509] -> IO Bool) -> Handle -> IO ConnInfo
sslClientConn onCerts h = do
let tcp = defaultParams
{ pConnectVersion = TLS10
, pAllowedVersions = [ TLS10, TLS11 ]
, pCiphers = ciphers
, onCertificatesRecv = onCerts
}
esrand <- liftIO makeSRandomGen
let srg = either (error . show) id esrand
istate <- liftIO $ client tcp srg h
liftIO $ handshake istate
return ConnInfo
{ connRead = liftIO $ fmap L.toChunks $ recvData istate
, connWrite = liftIO . sendData istate . L.fromChunks
, connClose = liftIO $ bye istate >> hClose h
}
where
ciphers =
[ cipher_AES128_SHA1
, cipher_AES256_SHA1
, cipher_RC4_128_MD5
, cipher_RC4_128_SHA1
]