http-client-tls 0.3.3.1 → 0.3.4
raw patch · 3 files changed
+99/−25 lines, 3 filesdep +containersdep +network-uridep +textdep ~connectiondep ~networkPVP ok
version bump matches the API change (PVP)
Dependencies added: containers, network-uri, text
Dependency ranges changed: connection, network
API changes (from Hackage documentation)
+ Network.HTTP.Client.TLS: newTlsManager :: MonadIO m => m Manager
Files
- ChangeLog.md +11/−0
- Network/HTTP/Client/TLS.hs +83/−23
- http-client-tls.cabal +5/−2
ChangeLog.md view
@@ -1,3 +1,14 @@+## 0.3.4++* Add 'newTlsManager'+ [#263](https://github.com/snoyberg/http-client/issues/263), which adds+ support for respecting `socks5://` and `socks5h://` `http_proxy` and+ `https_proxy` environment variables.++## 0.3.3.2++* Better handling of internal exceptions+ ## 0.3.3.1 * Better exception safety via `bracketOnError`
Network/HTTP/Client/TLS.hs view
@@ -11,6 +11,7 @@ tlsManagerSettings , mkManagerSettings , mkManagerSettingsContext+ , newTlsManager -- * Digest authentication , applyDigestAuth , DigestAuthException (..)@@ -21,6 +22,9 @@ , setGlobalManager ) where +import Control.Applicative ((<|>))+import Control.Arrow (first)+import System.Environment (getEnvironment) import Data.Default.Class import Network.HTTP.Client hiding (host, port) import Network.HTTP.Client.Internal hiding (host, port)@@ -41,6 +45,10 @@ import Data.ByteArray.Encoding (convertToBase, Base (Base16)) import Data.Typeable (Typeable) import Control.Monad.Catch (MonadThrow, throwM)+import qualified Data.Map as Map+import qualified Data.Text as T+import Data.Text.Read (decimal)+import qualified Network.URI as U -- | Create a TLS-enabled 'ManagerSettings' with the given 'NC.TLSSettings' and -- 'NC.SockSettings'@@ -62,27 +70,37 @@ -> NC.TLSSettings -> Maybe NC.SockSettings -> ManagerSettings-mkManagerSettingsContext mcontext tls sock = defaultManagerSettings- { managerTlsConnection = getTlsConnection mcontext (Just tls) sock- , managerTlsProxyConnection = getTlsProxyConnection mcontext tls sock+mkManagerSettingsContext mcontext tls sock = mkManagerSettingsContext' mcontext tls sock sock++-- | Internal, allow different SockSettings for HTTP and HTTPS+mkManagerSettingsContext'+ :: Maybe NC.ConnectionContext+ -> NC.TLSSettings+ -> Maybe NC.SockSettings -- ^ insecure+ -> Maybe NC.SockSettings -- ^ secure+ -> ManagerSettings+mkManagerSettingsContext' mcontext tls sockHTTP sockHTTPS = defaultManagerSettings+ { managerTlsConnection = getTlsConnection mcontext (Just tls) sockHTTPS+ , managerTlsProxyConnection = getTlsProxyConnection mcontext tls sockHTTPS , managerRawConnection =- case sock of+ case sockHTTP of Nothing -> managerRawConnection defaultManagerSettings- Just _ -> getTlsConnection mcontext Nothing sock+ Just _ -> getTlsConnection mcontext Nothing sockHTTP , managerRetryableException = \e -> case () of () | ((fromException e)::(Maybe TLS.TLSError))==Just TLS.Error_EOF -> True | otherwise -> managerRetryableException defaultManagerSettings e , managerWrapException = \req ->- let wrapper se =- case fromException se of- Just (_ :: IOException) -> se'- Nothing -> case fromException se of- Just TLS.Terminated{} -> se'- Just TLS.HandshakeFailed{} -> se'- Just TLS.ConnectionNotEstablished -> se'- _ -> se+ let wrapper se+ | Just (_ :: IOException) <- fromException se = se'+ | Just (_ :: TLS.TLSException) <- fromException se = se'+ | Just (_ :: NC.LineTooLong) <- fromException se = se'+#if MIN_VERSION_connection(0,2,7)+ | Just (_ :: NC.HostNotResolved) <- fromException se = se'+ | Just (_ :: NC.HostCannotConnect) <- fromException se = se'+#endif+ | otherwise = se where se' = toException $ HttpExceptionRequest req $ InternalException se in handle $ throwIO . wrapper@@ -144,18 +162,60 @@ -- already closed, and we get a @ResourceVanished@. (NC.connectionClose conn `Control.Exception.catch` \(_ :: IOException) -> return ()) +-- We may decide in the future to just have a global+-- ConnectionContext and use it directly in tlsManagerSettings, at+-- which point this can again be a simple (newManager+-- tlsManagerSettings >>= newIORef). See:+-- https://github.com/snoyberg/http-client/pull/227.+globalConnectionContext :: NC.ConnectionContext+globalConnectionContext = unsafePerformIO NC.initConnectionContext+{-# NOINLINE globalConnectionContext #-}++-- | Load up a new TLS manager with default settings, respecting proxy+-- environment variables.+--+-- @since 0.3.4+newTlsManager :: MonadIO m => m Manager+newTlsManager = liftIO $ do+ env <- getEnvironment+ let lenv = Map.fromList $ map (first $ T.toLower . T.pack) env+ msocksHTTP = parseSocksSettings env lenv "http_proxy"+ msocksHTTPS = parseSocksSettings env lenv "https_proxy"+ settings = mkManagerSettingsContext' (Just globalConnectionContext) def msocksHTTP msocksHTTPS+ settings' = maybe id (const $ managerSetInsecureProxy proxyFromRequest) msocksHTTP+ $ maybe id (const $ managerSetSecureProxy proxyFromRequest) msocksHTTPS+ settings+ newManager settings'++parseSocksSettings :: [(String, String)] -- ^ original environment+ -> Map.Map T.Text String -- ^ lower-cased keys+ -> T.Text -- ^ env name+ -> Maybe NC.SockSettings+parseSocksSettings env lenv n = do+ str <- lookup (T.unpack n) env <|> Map.lookup n lenv+ let allowedScheme x = x == "socks5:" || x == "socks5h:"+ uri <- U.parseURI str++ guard $ allowedScheme $ U.uriScheme uri+ guard $ null (U.uriPath uri) || U.uriPath uri == "/"+ guard $ null $ U.uriQuery uri+ guard $ null $ U.uriFragment uri++ auth <- U.uriAuthority uri+ port' <-+ case U.uriPort auth of+ "" -> Nothing -- should we use some default?+ ':':rest ->+ case decimal $ T.pack rest of+ Right (p, "") -> Just p+ _ -> Nothing+ _ -> Nothing++ Just $ NC.SockSettingsSimple (U.uriRegName auth) port'+ -- | Evil global manager, to make life easier for the common use case globalManager :: IORef Manager-globalManager = unsafePerformIO $ do- -- We may decide in the future to just have a global- -- ConnectionContext and use it directly in tlsManagerSettings, at- -- which point this can again be a simple (newManager- -- tlsManagerSettings >>= newIORef). See:- -- https://github.com/snoyberg/http-client/pull/227.- context <- NC.initConnectionContext- let settings = mkManagerSettingsContext (Just context) def Nothing- manager <- newManager settings- newIORef manager+globalManager = unsafePerformIO $ newTlsManager >>= newIORef {-# NOINLINE globalManager #-} -- | Get the current global 'Manager'
http-client-tls.cabal view
@@ -1,5 +1,5 @@ name: http-client-tls-version: 0.3.3.1+version: 0.3.4 synopsis: http-client backend using the connection package and tls library description: Hackage documentation generation is not reliable. For up to date documentation, please see: <https://www.stackage.org/package/http-client-tls>. homepage: https://github.com/snoyberg/http-client@@ -19,7 +19,7 @@ build-depends: base >= 4 && < 5 , data-default-class , http-client >= 0.5.0- , connection >= 0.2.2+ , connection >= 0.2.5 , network , tls >= 1.2 , bytestring@@ -29,6 +29,9 @@ , cryptonite , memory , exceptions+ , containers+ , text+ , network-uri default-language: Haskell2010 ghc-options: -Wall