packages feed

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 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