{-# language OverloadedStrings #-} import Control.Exception (bracket,throwIO) import Http.Exchange.Tls (SocketThrowingNetworkException(..),exchange) import Http.Types (Request(..),RequestLine(..),Bodied(..),Header(Header)) import Text.Show.Pretty (pPrint) import Data.Default (def) import qualified Http.Headers as Headers import qualified Network.Socket as N import qualified Network.TLS.Extra.Cipher as Tls import qualified Network.TLS as Tls main :: IO () main = do let noValidation = Tls.ValidationCache (\_ _ _ -> return Tls.ValidationCachePass) (\_ _ _ -> return ()) let clientParams = (Tls.defaultParamsClient "ifconfig.me" mempty) { Tls.clientSupported = def { Tls.supportedVersions = [Tls.TLS13] , Tls.supportedCiphers = [ Tls.cipher_TLS13_AES128GCM_SHA256 , Tls.cipher_TLS13_AES256GCM_SHA384 , Tls.cipher_TLS13_CHACHA20POLY1305_SHA256 , Tls.cipher_TLS13_AES128CCM_SHA256 , Tls.cipher_TLS13_AES128CCM8_SHA256 ] } , Tls.clientShared = def { Tls.sharedValidationCache = noValidation } } let hints = N.defaultHints { N.addrSocketType = N.Stream } minfo <- N.getAddrInfo (Just hints) (Just "ifconfig.me") (Just "443") info <- case minfo of info : _ -> pure info [] -> fail "Impossible: getAddrInfo cannot return empty list" bracket (N.openSocket info) N.close $ \sock -> do N.connect sock (N.addrAddress info) ctx <- Tls.contextNew (SocketThrowingNetworkException sock) clientParams Tls.handshake ctx result <- exchange ctx Bodied { metadata = Request { requestLine = RequestLine { method = "GET" , path = "/ip" } , headers = Headers.fromList [ Header "Host" "ifconfig.me" , Header "Accept" "text/plain" , Header "User-Agent" "curl/0.0.0" ] } , body = mempty } case result of Left e -> throwIO e Right resp -> pPrint resp