    {-# LANGUAGE CPP #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE DeriveDataTypeable #-}
    -- | Support for making connections via the connection package and, in turn,
    -- the tls package suite.
    --
    -- Recommended reading: <https://haskell-lang.org/library/http-client>
    module Network.HTTP.Client.TLS
        ( -- * Settings
          tlsManagerSettings
        , mkManagerSettings
        , mkManagerSettingsContext
        , newTlsManager
        , newTlsManagerWith
          -- * Digest authentication
        , applyDigestAuth
        , DigestAuthException (..)
        , DigestAuthExceptionDetails (..)
        , displayDigestAuthException
          -- * Global manager
        , getGlobalManager
        , setGlobalManager
        ) where

    import Control.Applicative ((<|>))
    import Control.Arrow (first)
    import System.Environment (getEnvironment)
    import Data.Default
    import Network.HTTP.Client hiding (host, port)
    import Network.HTTP.Client.Internal hiding (host, port)
    import Control.Exception
    import qualified Network.Connection as NC
    import Network.Socket (HostAddress)
    import qualified Network.TLS as TLS
    import qualified Data.ByteString as S
    import Data.IORef (IORef, newIORef, readIORef, writeIORef)
    import System.IO.Unsafe (unsafePerformIO)
    import Control.Monad.IO.Class (MonadIO, liftIO)
    import Control.Monad (guard, unless)
    import qualified Data.CaseInsensitive as CI
    import Data.Maybe (fromMaybe, isJust)
    import Network.HTTP.Types (status401)
    import Crypto.Hash (hash, Digest, MD5)
    import Control.Arrow ((***))
    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'
    mkManagerSettings :: NC.TLSSettings
                      -> Maybe NC.SockSettings
                      -> ManagerSettings
    mkManagerSettings :: TLSSettings -> Maybe SockSettings -> ManagerSettings
    mkManagerSettings = Maybe ConnectionContext
    -> TLSSettings -> Maybe SockSettings -> ManagerSettings
    mkManagerSettingsContext Maybe ConnectionContext
    forall a. Maybe a
    Nothing

    -- | Same as 'mkManagerSettings', but also takes an optional
    -- 'NC.ConnectionContext'. Providing this externally can be an
    -- optimization, though that may change in the future. For more
    -- information, see:
    --
    -- <https://github.com/snoyberg/http-client/pull/227>
    --
    -- @since 0.3.2
    mkManagerSettingsContext
        :: Maybe NC.ConnectionContext
        -> NC.TLSSettings
        -> Maybe NC.SockSettings
        -> ManagerSettings
    mkManagerSettingsContext :: Maybe ConnectionContext
    -> TLSSettings -> Maybe SockSettings -> ManagerSettings
    mkManagerSettingsContext Maybe ConnectionContext
    mcontext TLSSettings
    tls Maybe SockSettings
    sock = ManagerSettings
    -> Maybe ConnectionContext
    -> TLSSettings
    -> Maybe SockSettings
    -> Maybe SockSettings
    -> ManagerSettings
    mkManagerSettingsContext' ManagerSettings
    defaultManagerSettings Maybe ConnectionContext
    mcontext TLSSettings
    tls Maybe SockSettings
    sock Maybe SockSettings
    sock

    -- | Internal, allow different SockSettings for HTTP and HTTPS
    mkManagerSettingsContext'
        :: ManagerSettings
        -> Maybe NC.ConnectionContext
        -> NC.TLSSettings
        -> Maybe NC.SockSettings -- ^ insecure
        -> Maybe NC.SockSettings -- ^ secure
        -> ManagerSettings
    mkManagerSettingsContext' :: ManagerSettings
    -> Maybe ConnectionContext
    -> TLSSettings
    -> Maybe SockSettings
    -> Maybe SockSettings
    -> ManagerSettings
    mkManagerSettingsContext' ManagerSettings
    set Maybe ConnectionContext
    mcontext TLSSettings
    tls Maybe SockSettings
    sockHTTP Maybe SockSettings
    sockHTTPS = ManagerSettings
    set
        { managerTlsConnection = getTlsConnection mcontext (Just tls) sockHTTPS
        , managerTlsProxyConnection = getTlsProxyConnection mcontext tls sockHTTPS
        , managerRawConnection =
            case sockHTTP of
                Maybe SockSettings
    Nothing -> ManagerSettings
    -> IO (Maybe HostAddress -> [Char] -> Int -> IO Connection)
    managerRawConnection ManagerSettings
    defaultManagerSettings
                Just SockSettings
    _ -> Maybe ConnectionContext
    -> Maybe TLSSettings
    -> Maybe SockSettings
    -> IO (Maybe HostAddress -> [Char] -> Int -> IO Connection)
    getTlsConnection Maybe ConnectionContext
    mcontext Maybe TLSSettings
    forall a. Maybe a
    Nothing Maybe SockSettings
    sockHTTP
        , managerRetryableException = \SomeException
    e ->
            case () of
                ()
    #if MIN_VERSION_tls(1,8,0)
                    | ((SomeException -> Maybe TLSException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e)::(Maybe TLS.TLSException))Maybe TLSException -> Maybe TLSException -> Bool
    forall a. Eq a => a -> a -> Bool
    ==TLSException -> Maybe TLSException
    forall a. a -> Maybe a
    Just (TLSError -> TLSException
    TLS.PostHandshake TLSError
    TLS.Error_EOF) -> Bool
    True
    #else
                    | ((fromException e)::(Maybe TLS.TLSError))==Just TLS.Error_EOF -> True
    #endif
                    | Bool
    otherwise -> ManagerSettings -> SomeException -> Bool
    managerRetryableException ManagerSettings
    defaultManagerSettings SomeException
    e
        , managerWrapException = \Request
    req ->
            let wrapper :: SomeException -> SomeException
    wrapper SomeException
    se
                  | Just (IOException
    _ :: IOException)          <- SomeException -> Maybe IOException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    se = SomeException
    se'
                  | Just (TLSException
    _ :: TLS.TLSException)     <- SomeException -> Maybe TLSException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    se = SomeException
    se'
    #if !MIN_VERSION_tls(1,8,0)
                  | Just (_ :: TLS.TLSError)         <- fromException se = se'
    #endif
                  | Just (LineTooLong
    _ :: NC.LineTooLong)       <- SomeException -> Maybe LineTooLong
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    se = SomeException
    se'
                  | Just (HostNotResolved
    _ :: NC.HostNotResolved)   <- SomeException -> Maybe HostNotResolved
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    se = SomeException
    se'
                  | Just (HostCannotConnect
    _ :: NC.HostCannotConnect) <- SomeException -> Maybe HostCannotConnect
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    se = SomeException
    se'
                  | Bool
    otherwise = SomeException
    se
                  where
                    se' :: SomeException
    se' = HttpException -> SomeException
    forall e. Exception e => e -> SomeException
    toException (HttpException -> SomeException) -> HttpException -> SomeException
    forall a b. (a -> b) -> a -> b
    $ Request -> HttpExceptionContent -> HttpException
    HttpExceptionRequest Request
    req (HttpExceptionContent -> HttpException)
    -> HttpExceptionContent -> HttpException
    forall a b. (a -> b) -> a -> b
    $ SomeException -> HttpExceptionContent
    InternalException SomeException
    se
             in (SomeException -> IO a) -> IO a -> IO a
    forall e a. Exception e => (e -> IO a) -> IO a -> IO a
    handle ((SomeException -> IO a) -> IO a -> IO a)
    -> (SomeException -> IO a) -> IO a -> IO a
    forall a b. (a -> b) -> a -> b
    $ SomeException -> IO a
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO (SomeException -> IO a)
    -> (SomeException -> SomeException) -> SomeException -> IO a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . SomeException -> SomeException
    wrapper
        }

    -- | Default TLS-enabled manager settings
    tlsManagerSettings :: ManagerSettings
    tlsManagerSettings :: ManagerSettings
    tlsManagerSettings = TLSSettings -> Maybe SockSettings -> ManagerSettings
    mkManagerSettings TLSSettings
    forall a. Default a => a
    def Maybe SockSettings
    forall a. Maybe a
    Nothing

    getTlsConnection :: Maybe NC.ConnectionContext
                     -> Maybe NC.TLSSettings
                     -> Maybe NC.SockSettings
                     -> IO (Maybe HostAddress -> String -> Int -> IO Connection)
    getTlsConnection :: Maybe ConnectionContext
    -> Maybe TLSSettings
    -> Maybe SockSettings
    -> IO (Maybe HostAddress -> [Char] -> Int -> IO Connection)
    getTlsConnection Maybe ConnectionContext
    mcontext Maybe TLSSettings
    tls Maybe SockSettings
    sock = do
        context <- IO ConnectionContext
    -> (ConnectionContext -> IO ConnectionContext)
    -> Maybe ConnectionContext
    -> IO ConnectionContext
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe IO ConnectionContext
    NC.initConnectionContext ConnectionContext -> IO ConnectionContext
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ConnectionContext
    mcontext
        return $ \Maybe HostAddress
    _ha [Char]
    host Int
    port -> IO Connection
    -> (Connection -> IO ())
    -> (Connection -> IO Connection)
    -> IO Connection
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracketOnError
            (ConnectionContext -> ConnectionParams -> IO Connection
    NC.connectTo ConnectionContext
    context NC.ConnectionParams
                { connectionHostname :: [Char]
    NC.connectionHostname = [Char] -> [Char]
    strippedHostName [Char]
    host
                , connectionPort :: PortNumber
    NC.connectionPort = Int -> PortNumber
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    port
                , connectionUseSecure :: Maybe TLSSettings
    NC.connectionUseSecure = Maybe TLSSettings
    tls
                , connectionUseSocks :: Maybe SockSettings
    NC.connectionUseSocks = Maybe SockSettings
    sock
                })
            Connection -> IO ()
    NC.connectionClose
            Connection -> IO Connection
    convertConnection

    getTlsProxyConnection
        :: Maybe NC.ConnectionContext
        -> NC.TLSSettings
        -> Maybe NC.SockSettings
        -> IO (S.ByteString -> (Connection -> IO ()) -> String -> Maybe HostAddress -> String -> Int -> IO Connection)
    getTlsProxyConnection :: Maybe ConnectionContext
    -> TLSSettings
    -> Maybe SockSettings
    -> IO
         (ByteString
          -> (Connection -> IO ())
          -> [Char]
          -> Maybe HostAddress
          -> [Char]
          -> Int
          -> IO Connection)
    getTlsProxyConnection Maybe ConnectionContext
    mcontext TLSSettings
    tls Maybe SockSettings
    sock = do
        context <- IO ConnectionContext
    -> (ConnectionContext -> IO ConnectionContext)
    -> Maybe ConnectionContext
    -> IO ConnectionContext
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe IO ConnectionContext
    NC.initConnectionContext ConnectionContext -> IO ConnectionContext
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe ConnectionContext
    mcontext
        return $ \ByteString
    connstr Connection -> IO ()
    checkConn [Char]
    serverName Maybe HostAddress
    _ha [Char]
    host Int
    port -> IO Connection
    -> (Connection -> IO ())
    -> (Connection -> IO Connection)
    -> IO Connection
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracketOnError
            (ConnectionContext -> ConnectionParams -> IO Connection
    NC.connectTo ConnectionContext
    context NC.ConnectionParams
                { connectionHostname :: [Char]
    NC.connectionHostname = [Char] -> [Char]
    strippedHostName [Char]
    serverName
                , connectionPort :: PortNumber
    NC.connectionPort = Int -> PortNumber
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    port
                , connectionUseSecure :: Maybe TLSSettings
    NC.connectionUseSecure = Maybe TLSSettings
    forall a. Maybe a
    Nothing
                , connectionUseSocks :: Maybe SockSettings
    NC.connectionUseSocks =
                    case Maybe SockSettings
    sock of
                        Just SockSettings
    _ -> [Char] -> Maybe SockSettings
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "Cannot use SOCKS and TLS proxying together"
                        Maybe SockSettings
    Nothing -> SockSettings -> Maybe SockSettings
    forall a. a -> Maybe a
    Just (SockSettings -> Maybe SockSettings)
    -> SockSettings -> Maybe SockSettings
    forall a b. (a -> b) -> a -> b
    $ [Char] -> PortNumber -> SockSettings
    NC.OtherProxy ([Char] -> [Char]
    strippedHostName [Char]
    host) (PortNumber -> SockSettings) -> PortNumber -> SockSettings
    forall a b. (a -> b) -> a -> b
    $ Int -> PortNumber
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    port
                })
            Connection -> IO ()
    NC.connectionClose
            ((Connection -> IO Connection) -> IO Connection)
    -> (Connection -> IO Connection) -> IO Connection
    forall a b. (a -> b) -> a -> b
    $ \Connection
    conn -> do
                Connection -> ByteString -> IO ()
    NC.connectionPut Connection
    conn ByteString
    connstr
                conn' <- Connection -> IO Connection
    convertConnection Connection
    conn

                checkConn conn'

                NC.connectionSetSecure context conn tls

                return conn'

    convertConnection :: NC.Connection -> IO Connection
    convertConnection :: Connection -> IO Connection
    convertConnection Connection
    conn = IO ByteString -> (ByteString -> IO ()) -> IO () -> IO Connection
    makeConnection
        (Connection -> IO ByteString
    NC.connectionGetChunk Connection
    conn)
        (Connection -> ByteString -> IO ()
    NC.connectionPut Connection
    conn)
        -- Closing an SSL connection gracefully involves writing/reading
        -- on the socket.  But when this is called the socket might be
        -- already closed, and we get a @ResourceVanished@.
        (Connection -> IO ()
    NC.connectionClose Connection
    conn IO () -> (IOException -> IO ()) -> IO ()
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `Control.Exception.catch` \(IOException
    _ :: IOException) -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    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 :: ConnectionContext
    globalConnectionContext = IO ConnectionContext -> ConnectionContext
    forall a. IO a -> a
    unsafePerformIO IO ConnectionContext
    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 :: forall (m :: * -> *). MonadIO m => m Manager
    newTlsManager = IO Manager -> m Manager
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Manager -> m Manager) -> IO Manager -> m Manager
    forall a b. (a -> b) -> a -> b
    $ do
        env <- IO [([Char], [Char])]
    getEnvironment
        let lenv = [(Text, [Char])] -> Map Text [Char]
    forall k a. Ord k => [(k, a)] -> Map k a
    Map.fromList ([(Text, [Char])] -> Map Text [Char])
    -> [(Text, [Char])] -> Map Text [Char]
    forall a b. (a -> b) -> a -> b
    $ (([Char], [Char]) -> (Text, [Char]))
    -> [([Char], [Char])] -> [(Text, [Char])]
    forall a b. (a -> b) -> [a] -> [b]
    map (([Char] -> Text) -> ([Char], [Char]) -> (Text, [Char])
    forall b c d. (b -> c) -> (b, d) -> (c, d)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (b, d) (c, d)
    first (([Char] -> Text) -> ([Char], [Char]) -> (Text, [Char]))
    -> ([Char] -> Text) -> ([Char], [Char]) -> (Text, [Char])
    forall a b. (a -> b) -> a -> b
    $ Text -> Text
    T.toLower (Text -> Text) -> ([Char] -> Text) -> [Char] -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> Text
    T.pack) [([Char], [Char])]
    env
            msocksHTTP = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
    parseSocksSettings [([Char], [Char])]
    env Map Text [Char]
    lenv Text
    "http_proxy"
            msocksHTTPS = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
    parseSocksSettings [([Char], [Char])]
    env Map Text [Char]
    lenv Text
    "https_proxy"
            settings = ManagerSettings
    -> Maybe ConnectionContext
    -> TLSSettings
    -> Maybe SockSettings
    -> Maybe SockSettings
    -> ManagerSettings
    mkManagerSettingsContext' ManagerSettings
    defaultManagerSettings (ConnectionContext -> Maybe ConnectionContext
    forall a. a -> Maybe a
    Just ConnectionContext
    globalConnectionContext) TLSSettings
    forall a. Default a => a
    def Maybe SockSettings
    msocksHTTP Maybe SockSettings
    msocksHTTPS
            settings' = (ManagerSettings -> ManagerSettings)
    -> (SockSettings -> ManagerSettings -> ManagerSettings)
    -> Maybe SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ManagerSettings -> ManagerSettings
    forall a. a -> a
    id ((ManagerSettings -> ManagerSettings)
    -> SockSettings -> ManagerSettings -> ManagerSettings
    forall a b. a -> b -> a
    const ((ManagerSettings -> ManagerSettings)
     -> SockSettings -> ManagerSettings -> ManagerSettings)
    -> (ManagerSettings -> ManagerSettings)
    -> SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall a b. (a -> b) -> a -> b
    $ ProxyOverride -> ManagerSettings -> ManagerSettings
    managerSetInsecureProxy ProxyOverride
    proxyFromRequest) Maybe SockSettings
    msocksHTTP
                      (ManagerSettings -> ManagerSettings)
    -> ManagerSettings -> ManagerSettings
    forall a b. (a -> b) -> a -> b
    $ (ManagerSettings -> ManagerSettings)
    -> (SockSettings -> ManagerSettings -> ManagerSettings)
    -> Maybe SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ManagerSettings -> ManagerSettings
    forall a. a -> a
    id ((ManagerSettings -> ManagerSettings)
    -> SockSettings -> ManagerSettings -> ManagerSettings
    forall a b. a -> b -> a
    const ((ManagerSettings -> ManagerSettings)
     -> SockSettings -> ManagerSettings -> ManagerSettings)
    -> (ManagerSettings -> ManagerSettings)
    -> SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall a b. (a -> b) -> a -> b
    $ ProxyOverride -> ManagerSettings -> ManagerSettings
    managerSetSecureProxy ProxyOverride
    proxyFromRequest) Maybe SockSettings
    msocksHTTPS
                        ManagerSettings
    settings
        newManager settings'

    -- | Load up a new TLS manager based upon specified settings,
    -- respecting proxy environment variables.
    --
    -- @since 0.3.5
    newTlsManagerWith :: MonadIO m => ManagerSettings -> m Manager
    newTlsManagerWith :: forall (m :: * -> *). MonadIO m => ManagerSettings -> m Manager
    newTlsManagerWith ManagerSettings
    set = IO Manager -> m Manager
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Manager -> m Manager) -> IO Manager -> m Manager
    forall a b. (a -> b) -> a -> b
    $ do
        env <- IO [([Char], [Char])]
    getEnvironment
        let lenv = [(Text, [Char])] -> Map Text [Char]
    forall k a. Ord k => [(k, a)] -> Map k a
    Map.fromList ([(Text, [Char])] -> Map Text [Char])
    -> [(Text, [Char])] -> Map Text [Char]
    forall a b. (a -> b) -> a -> b
    $ (([Char], [Char]) -> (Text, [Char]))
    -> [([Char], [Char])] -> [(Text, [Char])]
    forall a b. (a -> b) -> [a] -> [b]
    map (([Char] -> Text) -> ([Char], [Char]) -> (Text, [Char])
    forall b c d. (b -> c) -> (b, d) -> (c, d)
    forall (a :: * -> * -> *) b c d.
    Arrow a =>
    a b c -> a (b, d) (c, d)
    first (([Char] -> Text) -> ([Char], [Char]) -> (Text, [Char]))
    -> ([Char] -> Text) -> ([Char], [Char]) -> (Text, [Char])
    forall a b. (a -> b) -> a -> b
    $ Text -> Text
    T.toLower (Text -> Text) -> ([Char] -> Text) -> [Char] -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> Text
    T.pack) [([Char], [Char])]
    env
            msocksHTTP = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
    parseSocksSettings [([Char], [Char])]
    env Map Text [Char]
    lenv Text
    "http_proxy"
            msocksHTTPS = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
    parseSocksSettings [([Char], [Char])]
    env Map Text [Char]
    lenv Text
    "https_proxy"
            settings = ManagerSettings
    -> Maybe ConnectionContext
    -> TLSSettings
    -> Maybe SockSettings
    -> Maybe SockSettings
    -> ManagerSettings
    mkManagerSettingsContext' ManagerSettings
    set (ConnectionContext -> Maybe ConnectionContext
    forall a. a -> Maybe a
    Just ConnectionContext
    globalConnectionContext) TLSSettings
    forall a. Default a => a
    def Maybe SockSettings
    msocksHTTP Maybe SockSettings
    msocksHTTPS
            settings' = (ManagerSettings -> ManagerSettings)
    -> (SockSettings -> ManagerSettings -> ManagerSettings)
    -> Maybe SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ManagerSettings -> ManagerSettings
    forall a. a -> a
    id ((ManagerSettings -> ManagerSettings)
    -> SockSettings -> ManagerSettings -> ManagerSettings
    forall a b. a -> b -> a
    const ((ManagerSettings -> ManagerSettings)
     -> SockSettings -> ManagerSettings -> ManagerSettings)
    -> (ManagerSettings -> ManagerSettings)
    -> SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall a b. (a -> b) -> a -> b
    $ ProxyOverride -> ManagerSettings -> ManagerSettings
    managerSetInsecureProxy ProxyOverride
    proxyFromRequest) Maybe SockSettings
    msocksHTTP
                      (ManagerSettings -> ManagerSettings)
    -> ManagerSettings -> ManagerSettings
    forall a b. (a -> b) -> a -> b
    $ (ManagerSettings -> ManagerSettings)
    -> (SockSettings -> ManagerSettings -> ManagerSettings)
    -> Maybe SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ManagerSettings -> ManagerSettings
    forall a. a -> a
    id ((ManagerSettings -> ManagerSettings)
    -> SockSettings -> ManagerSettings -> ManagerSettings
    forall a b. a -> b -> a
    const ((ManagerSettings -> ManagerSettings)
     -> SockSettings -> ManagerSettings -> ManagerSettings)
    -> (ManagerSettings -> ManagerSettings)
    -> SockSettings
    -> ManagerSettings
    -> ManagerSettings
    forall a b. (a -> b) -> a -> b
    $ ProxyOverride -> ManagerSettings -> ManagerSettings
    managerSetSecureProxy ProxyOverride
    proxyFromRequest) Maybe SockSettings
    msocksHTTPS
                        ManagerSettings
    settings
                            -- We want to keep the original TLS settings that were
                            -- passed in. Sadly they aren't available as a record
                            -- field on `ManagerSettings`. So instead we grab the
                            -- fields that depend on the TLS settings.
                            -- https://github.com/snoyberg/http-client/issues/289
                            { managerTlsConnection = managerTlsConnection set
                            , managerTlsProxyConnection = managerTlsProxyConnection set
                            }
        newManager settings'

    parseSocksSettings :: [(String, String)] -- ^ original environment
                       -> Map.Map T.Text String -- ^ lower-cased keys
                       -> T.Text -- ^ env name
                       -> Maybe NC.SockSettings
    parseSocksSettings :: [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
    parseSocksSettings [([Char], [Char])]
    env Map Text [Char]
    lenv Text
    n = do
      str <- [Char] -> [([Char], [Char])] -> Maybe [Char]
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup (Text -> [Char]
    T.unpack Text
    n) [([Char], [Char])]
    env Maybe [Char] -> Maybe [Char] -> Maybe [Char]
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Text -> Map Text [Char] -> Maybe [Char]
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup Text
    n Map Text [Char]
    lenv
      let allowedScheme a
    x = a
    x a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    "socks5:" Bool -> Bool -> Bool
    || a
    x a -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    == a
    "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
              [Char]
    "" -> Maybe PortNumber
    forall a. Maybe a
    Nothing -- should we use some default?
              Char
    ':':[Char]
    rest ->
                  case Reader PortNumber
    forall a. Integral a => Reader a
    decimal Reader PortNumber -> Reader PortNumber
    forall a b. (a -> b) -> a -> b
    $ [Char] -> Text
    T.pack [Char]
    rest of
                      Right (PortNumber
    p, Text
    "") -> PortNumber -> Maybe PortNumber
    forall a. a -> Maybe a
    Just PortNumber
    p
                      Either [Char] (PortNumber, Text)
    _ -> Maybe PortNumber
    forall a. Maybe a
    Nothing
              [Char]
    _ -> Maybe PortNumber
    forall a. Maybe a
    Nothing

      Just $ NC.SockSettingsSimple (U.uriRegName auth) port'

    -- | Evil global manager, to make life easier for the common use case
    globalManager :: IORef Manager
    globalManager :: IORef Manager
    globalManager = IO (IORef Manager) -> IORef Manager
    forall a. IO a -> a
    unsafePerformIO (IO (IORef Manager) -> IORef Manager)
    -> IO (IORef Manager) -> IORef Manager
    forall a b. (a -> b) -> a -> b
    $ IO Manager
    forall (m :: * -> *). MonadIO m => m Manager
    newTlsManager IO Manager -> (Manager -> IO (IORef Manager)) -> IO (IORef Manager)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Manager -> IO (IORef Manager)
    forall a. a -> IO (IORef a)
    newIORef
    {-# NOINLINE globalManager #-}

    -- | Get the current global 'Manager'
    --
    -- @since 0.2.4
    getGlobalManager :: IO Manager
    getGlobalManager :: IO Manager
    getGlobalManager = IORef Manager -> IO Manager
    forall a. IORef a -> IO a
    readIORef IORef Manager
    globalManager
    {-# INLINE getGlobalManager #-}

    -- | Set the current global 'Manager'
    --
    -- @since 0.2.4
    setGlobalManager :: Manager -> IO ()
    setGlobalManager :: Manager -> IO ()
    setGlobalManager = IORef Manager -> Manager -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef Manager
    globalManager

    -- | Generated by 'applyDigestAuth' when it is unable to apply the
    -- digest credentials to the request.
    --
    -- @since 0.3.3
    data DigestAuthException
        = DigestAuthException Request (Response ()) DigestAuthExceptionDetails
        deriving (Int -> DigestAuthException -> [Char] -> [Char]
    [DigestAuthException] -> [Char] -> [Char]
    DigestAuthException -> [Char]
    (Int -> DigestAuthException -> [Char] -> [Char])
    -> (DigestAuthException -> [Char])
    -> ([DigestAuthException] -> [Char] -> [Char])
    -> Show DigestAuthException
    forall a.
    (Int -> a -> [Char] -> [Char])
    -> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
    $cshowsPrec :: Int -> DigestAuthException -> [Char] -> [Char]
    showsPrec :: Int -> DigestAuthException -> [Char] -> [Char]
    $cshow :: DigestAuthException -> [Char]
    show :: DigestAuthException -> [Char]
    $cshowList :: [DigestAuthException] -> [Char] -> [Char]
    showList :: [DigestAuthException] -> [Char] -> [Char]
    Show, Typeable)
    instance Exception DigestAuthException where
    #if MIN_VERSION_base(4, 8, 0)
        displayException :: DigestAuthException -> [Char]
    displayException = DigestAuthException -> [Char]
    displayDigestAuthException
    #endif

    -- | User friendly display of a 'DigestAuthException'
    --
    -- @since 0.3.3
    displayDigestAuthException :: DigestAuthException -> String
    displayDigestAuthException :: DigestAuthException -> [Char]
    displayDigestAuthException (DigestAuthException Request
    req Response ()
    res DigestAuthExceptionDetails
    det) = [[Char]] -> [Char]
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat
        [ [Char]
    "Unable to submit digest credentials due to: "
        , [Char]
    details
        , [Char]
    ".\n\nRequest: "
        , Request -> [Char]
    forall a. Show a => a -> [Char]
    show Request
    req
        , [Char]
    ".\n\nResponse: "
        , Response () -> [Char]
    forall a. Show a => a -> [Char]
    show Response ()
    res
        ]
      where
        details :: [Char]
    details =
            case DigestAuthExceptionDetails
    det of
                DigestAuthExceptionDetails
    UnexpectedStatusCode -> [Char]
    "received unexpected status code"
                DigestAuthExceptionDetails
    MissingWWWAuthenticateHeader ->
                    [Char]
    "missing WWW-Authenticate response header"
                DigestAuthExceptionDetails
    WWWAuthenticateIsNotDigest ->
                    [Char]
    "WWW-Authenticate response header does not indicate Digest"
                DigestAuthExceptionDetails
    MissingRealm ->
                    [Char]
    "WWW-Authenticate response header does include realm"
                DigestAuthExceptionDetails
    MissingNonce ->
                    [Char]
    "WWW-Authenticate response header does include nonce"

    -- | Detailed explanation for failure for 'DigestAuthException'
    --
    -- @since 0.3.3
    data DigestAuthExceptionDetails
        = UnexpectedStatusCode
        | MissingWWWAuthenticateHeader
        | WWWAuthenticateIsNotDigest
        | MissingRealm
        | MissingNonce
        deriving (Int -> DigestAuthExceptionDetails -> [Char] -> [Char]
    [DigestAuthExceptionDetails] -> [Char] -> [Char]
    DigestAuthExceptionDetails -> [Char]
    (Int -> DigestAuthExceptionDetails -> [Char] -> [Char])
    -> (DigestAuthExceptionDetails -> [Char])
    -> ([DigestAuthExceptionDetails] -> [Char] -> [Char])
    -> Show DigestAuthExceptionDetails
    forall a.
    (Int -> a -> [Char] -> [Char])
    -> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
    $cshowsPrec :: Int -> DigestAuthExceptionDetails -> [Char] -> [Char]
    showsPrec :: Int -> DigestAuthExceptionDetails -> [Char] -> [Char]
    $cshow :: DigestAuthExceptionDetails -> [Char]
    show :: DigestAuthExceptionDetails -> [Char]
    $cshowList :: [DigestAuthExceptionDetails] -> [Char] -> [Char]
    showList :: [DigestAuthExceptionDetails] -> [Char] -> [Char]
    Show, ReadPrec [DigestAuthExceptionDetails]
    ReadPrec DigestAuthExceptionDetails
    Int -> ReadS DigestAuthExceptionDetails
    ReadS [DigestAuthExceptionDetails]
    (Int -> ReadS DigestAuthExceptionDetails)
    -> ReadS [DigestAuthExceptionDetails]
    -> ReadPrec DigestAuthExceptionDetails
    -> ReadPrec [DigestAuthExceptionDetails]
    -> Read DigestAuthExceptionDetails
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS DigestAuthExceptionDetails
    readsPrec :: Int -> ReadS DigestAuthExceptionDetails
    $creadList :: ReadS [DigestAuthExceptionDetails]
    readList :: ReadS [DigestAuthExceptionDetails]
    $creadPrec :: ReadPrec DigestAuthExceptionDetails
    readPrec :: ReadPrec DigestAuthExceptionDetails
    $creadListPrec :: ReadPrec [DigestAuthExceptionDetails]
    readListPrec :: ReadPrec [DigestAuthExceptionDetails]
    Read, Typeable, DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    (DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> Bool)
    -> Eq DigestAuthExceptionDetails
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    == :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    $c/= :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    /= :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    Eq, Eq DigestAuthExceptionDetails
    Eq DigestAuthExceptionDetails =>
    (DigestAuthExceptionDetails
     -> DigestAuthExceptionDetails -> Ordering)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> Bool)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> Bool)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> Bool)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> Bool)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails)
    -> (DigestAuthExceptionDetails
        -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails)
    -> Ord DigestAuthExceptionDetails
    DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> Ordering
    DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> Ordering
    compare :: DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> Ordering
    $c< :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    < :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    $c<= :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    <= :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    $c> :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    > :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    $c>= :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    >= :: DigestAuthExceptionDetails -> DigestAuthExceptionDetails -> Bool
    $cmax :: DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails
    max :: DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails
    $cmin :: DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails
    min :: DigestAuthExceptionDetails
    -> DigestAuthExceptionDetails -> DigestAuthExceptionDetails
    Ord)

    -- | Apply digest authentication to this request.
    --
    -- Note that this function will need to make an HTTP request to the
    -- server in order to get the nonce, thus the need for a @Manager@ and
    -- to live in @IO@. This also means that the request body will be sent
    -- to the server. If the request body in the supplied @Request@ can
    -- only be read once, you should replace it with a dummy value.
    --
    -- In the event of successfully generating a digest, this will return
    -- a @Just@ value. If there is any problem with generating the digest,
    -- it will return @Nothing@.
    --
    -- @since 0.3.1
    applyDigestAuth :: (MonadIO m, MonadThrow n)
                    => S.ByteString -- ^ username
                    -> S.ByteString -- ^ password
                    -> Request
                    -> Manager
                    -> m (n Request)
    applyDigestAuth :: forall (m :: * -> *) (n :: * -> *).
    (MonadIO m, MonadThrow n) =>
    ByteString -> ByteString -> Request -> Manager -> m (n Request)
    applyDigestAuth ByteString
    user ByteString
    pass Request
    req0 Manager
    man = IO (n Request) -> m (n Request)
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO (n Request) -> m (n Request))
    -> IO (n Request) -> m (n Request)
    forall a b. (a -> b) -> a -> b
    $ do
        res <- Request -> Manager -> IO (Response ())
    httpNoBody Request
    req Manager
    man
        let throw' = DigestAuthException -> n a
    forall e a. (HasCallStack, Exception e) => e -> n a
    forall (m :: * -> *) e a.
    (MonadThrow m, HasCallStack, Exception e) =>
    e -> m a
    throwM (DigestAuthException -> n a)
    -> (DigestAuthExceptionDetails -> DigestAuthException)
    -> DigestAuthExceptionDetails
    -> n a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Request
    -> Response () -> DigestAuthExceptionDetails -> DigestAuthException
    DigestAuthException Request
    req Response ()
    res
        return $ do
            unless (responseStatus res == status401)
                $ throw' UnexpectedStatusCode
            h1 <- maybe (throw' MissingWWWAuthenticateHeader) return
                $ lookup "WWW-Authenticate" $ responseHeaders res
            h2 <- maybe (throw' WWWAuthenticateIsNotDigest) return
                $ stripCI "Digest " h1
            let pieces = ((ByteString, ByteString) -> (ByteString, ByteString))
    -> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
    forall a b. (a -> b) -> [a] -> [b]
    map (ByteString -> ByteString
    strip (ByteString -> ByteString)
    -> (ByteString -> ByteString)
    -> (ByteString, ByteString)
    -> (ByteString, ByteString)
    forall b c b' c'. (b -> c) -> (b' -> c') -> (b, b') -> (c, c')
    forall (a :: * -> * -> *) b c b' c'.
    Arrow a =>
    a b c -> a b' c' -> a (b, b') (c, c')
    *** ByteString -> ByteString
    strip) (ByteString -> [(ByteString, ByteString)]
    toPairs ByteString
    h2)
            realm <- maybe (throw' MissingRealm) return
                   $ lookup "realm" pieces
            nonce <- maybe (throw' MissingNonce) return
                   $ lookup "nonce" pieces
            let qop = Maybe ByteString -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe ByteString -> Bool) -> Maybe ByteString -> Bool
    forall a b. (a -> b) -> a -> b
    $ ByteString -> [(ByteString, ByteString)] -> Maybe ByteString
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup ByteString
    "qop" [(ByteString, ByteString)]
    pieces
                digest
                    | Bool
    qop = ByteString -> ByteString
    forall {bout} {ba}.
    (ByteArray bout, ByteArrayAccess ba) =>
    ba -> bout
    md5 (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ [ByteString] -> ByteString
    S.concat
                        [ ByteString
    ha1
                        , ByteString
    ":"
                        , ByteString
    nonce
                        , ByteString
    ":00000001:deadbeef:auth:"
                        , ByteString
    ha2
                        ]
                    | Bool
    otherwise = ByteString -> ByteString
    forall {bout} {ba}.
    (ByteArray bout, ByteArrayAccess ba) =>
    ba -> bout
    md5 (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ [ByteString] -> ByteString
    S.concat [ByteString
    ha1, ByteString
    ":", ByteString
    nonce, ByteString
    ":", ByteString
    ha2]
                  where
                    ha1 :: ByteString
    ha1 = ByteString -> ByteString
    forall {bout} {ba}.
    (ByteArray bout, ByteArrayAccess ba) =>
    ba -> bout
    md5 (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ [ByteString] -> ByteString
    S.concat [ByteString
    user, ByteString
    ":", ByteString
    realm, ByteString
    ":", ByteString
    pass]

                    -- we always use no qop or qop=auth
                    ha2 :: ByteString
    ha2 = ByteString -> ByteString
    forall {bout} {ba}.
    (ByteArray bout, ByteArrayAccess ba) =>
    ba -> bout
    md5 (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ [ByteString] -> ByteString
    S.concat [Request -> ByteString
    method Request
    req, ByteString
    ":", Request -> ByteString
    path Request
    req]

                    md5 :: ba -> bout
    md5 ba
    bs = Base -> Digest MD5 -> bout
    forall bin bout.
    (ByteArrayAccess bin, ByteArray bout) =>
    Base -> bin -> bout
    convertToBase Base
    Base16 (ba -> Digest MD5
    forall ba a.
    (ByteArrayAccess ba, HashAlgorithm a) =>
    ba -> Digest a
    hash ba
    bs :: Digest MD5)
                key = HeaderName
    "Authorization"
                val = [ByteString] -> ByteString
    S.concat
                    [ ByteString
    "Digest username=\""
                    , ByteString
    user
                    , ByteString
    "\", realm=\""
                    , ByteString
    realm
                    , ByteString
    "\", nonce=\""
                    , ByteString
    nonce
                    , ByteString
    "\", uri=\""
                    , Request -> ByteString
    path Request
    req
                    , ByteString
    "\", response=\""
                    , ByteString
    digest
                    , ByteString
    "\""
                    -- FIXME algorithm?
                    , case ByteString -> [(ByteString, ByteString)] -> Maybe ByteString
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup ByteString
    "opaque" [(ByteString, ByteString)]
    pieces of
                        Maybe ByteString
    Nothing -> ByteString
    ""
                        Just ByteString
    o -> [ByteString] -> ByteString
    S.concat [ByteString
    ", opaque=\"", ByteString
    o, ByteString
    "\""]
                    , if Bool
    qop
                        then ByteString
    ", qop=auth, nc=00000001, cnonce=\"deadbeef\""
                        else ByteString
    ""
                    ]
            return req
                { requestHeaders = (key, val)
                                 : filter
                                        (\(HeaderName
    x, ByteString
    _) -> HeaderName
    x HeaderName -> HeaderName -> Bool
    forall a. Eq a => a -> a -> Bool
    /= HeaderName
    key)
                                        (requestHeaders req)
                , cookieJar = Just $ responseCookieJar res
                }
      where
        -- Since we're expecting a non-200 response, ensure we do not
        -- throw exceptions for such responses.
        req :: Request
    req = Request
    req0 { checkResponse = \Request
    _ Response (IO ByteString)
    _ -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return () }

        stripCI :: ByteString -> ByteString -> Maybe ByteString
    stripCI ByteString
    x ByteString
    y
            | ByteString -> HeaderName
    forall s. FoldCase s => s -> CI s
    CI.mk ByteString
    x HeaderName -> HeaderName -> Bool
    forall a. Eq a => a -> a -> Bool
    == ByteString -> HeaderName
    forall s. FoldCase s => s -> CI s
    CI.mk (Int -> ByteString -> ByteString
    S.take Int
    len ByteString
    y) = ByteString -> Maybe ByteString
    forall a. a -> Maybe a
    Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
    forall a b. (a -> b) -> a -> b
    $ Int -> ByteString -> ByteString
    S.drop Int
    len ByteString
    y
            | Bool
    otherwise = Maybe ByteString
    forall a. Maybe a
    Nothing
          where
            len :: Int
    len = ByteString -> Int
    S.length ByteString
    x

        _comma :: Word8
    _comma = Word8
    44
        _equal :: Word8
    _equal = Word8
    61
        _dquot :: Word8
    _dquot = Word8
    34
        _space :: Word8
    _space = Word8
    32

        strip :: ByteString -> ByteString
    strip = (ByteString, ByteString) -> ByteString
    forall a b. (a, b) -> a
    fst ((ByteString, ByteString) -> ByteString)
    -> (ByteString -> (ByteString, ByteString))
    -> ByteString
    -> ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    S.spanEnd (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _space) (ByteString -> (ByteString, ByteString))
    -> (ByteString -> ByteString)
    -> ByteString
    -> (ByteString, ByteString)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Word8 -> Bool) -> ByteString -> ByteString
    S.dropWhile (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _space)

        toPairs :: ByteString -> [(ByteString, ByteString)]
    toPairs ByteString
    bs0
            | ByteString -> Bool
    S.null ByteString
    bs0 = []
            | Bool
    otherwise =
                let bs1 :: ByteString
    bs1 = (Word8 -> Bool) -> ByteString -> ByteString
    S.dropWhile (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _space) ByteString
    bs0
                    (ByteString
    key, ByteString
    bs2) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    S.break (\Word8
    w -> Word8
    w Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _equal Bool -> Bool -> Bool
    || Word8
    w Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _comma) ByteString
    bs1
                 in case () of
                      ()
                        | ByteString -> Bool
    S.null ByteString
    bs2 -> [(ByteString
    key, ByteString
    "")]
                        | HasCallStack => ByteString -> Word8
    ByteString -> Word8
    S.head ByteString
    bs2 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _equal ->
                            let (ByteString
    val, ByteString
    rest) = ByteString -> (ByteString, ByteString)
    parseVal (ByteString -> (ByteString, ByteString))
    -> ByteString -> (ByteString, ByteString)
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => ByteString -> ByteString
    ByteString -> ByteString
    S.tail ByteString
    bs2
                             in (ByteString
    key, ByteString
    val) (ByteString, ByteString)
    -> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
    forall a. a -> [a] -> [a]
    : ByteString -> [(ByteString, ByteString)]
    toPairs ByteString
    rest
                        | Bool
    otherwise ->
                            Bool -> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
    forall a. HasCallStack => Bool -> a -> a
    assert (HasCallStack => ByteString -> Word8
    ByteString -> Word8
    S.head ByteString
    bs2 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _comma) ([(ByteString, ByteString)] -> [(ByteString, ByteString)])
    -> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
    forall a b. (a -> b) -> a -> b
    $
                            (ByteString
    key, ByteString
    "") (ByteString, ByteString)
    -> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
    forall a. a -> [a] -> [a]
    : ByteString -> [(ByteString, ByteString)]
    toPairs (HasCallStack => ByteString -> ByteString
    ByteString -> ByteString
    S.tail ByteString
    bs2)

        parseVal :: ByteString -> (ByteString, ByteString)
    parseVal ByteString
    bs0 = (ByteString, ByteString)
    -> Maybe (ByteString, ByteString) -> (ByteString, ByteString)
    forall a. a -> Maybe a -> a
    fromMaybe (ByteString -> (ByteString, ByteString)
    parseUnquoted ByteString
    bs0) (Maybe (ByteString, ByteString) -> (ByteString, ByteString))
    -> Maybe (ByteString, ByteString) -> (ByteString, ByteString)
    forall a b. (a -> b) -> a -> b
    $ do
            Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Bool -> Maybe ()) -> Bool -> Maybe ()
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ ByteString -> Bool
    S.null ByteString
    bs0
            Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Bool -> Maybe ()) -> Bool -> Maybe ()
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => ByteString -> Word8
    ByteString -> Word8
    S.head ByteString
    bs0 Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _dquot
            let (ByteString
    x, ByteString
    y) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    S.break (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _dquot) (ByteString -> (ByteString, ByteString))
    -> ByteString -> (ByteString, ByteString)
    forall a b. (a -> b) -> a -> b
    $ HasCallStack => ByteString -> ByteString
    ByteString -> ByteString
    S.tail ByteString
    bs0
            Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Bool -> Maybe ()) -> Bool -> Maybe ()
    forall a b. (a -> b) -> a -> b
    $ Bool -> Bool
    not (Bool -> Bool) -> Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ ByteString -> Bool
    S.null ByteString
    y
            (ByteString, ByteString) -> Maybe (ByteString, ByteString)
    forall a. a -> Maybe a
    Just (ByteString
    x, Int -> ByteString -> ByteString
    S.drop Int
    1 (ByteString -> ByteString) -> ByteString -> ByteString
    forall a b. (a -> b) -> a -> b
    $ (Word8 -> Bool) -> ByteString -> ByteString
    S.dropWhile (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Word8
    _comma) ByteString
    y)

        parseUnquoted :: ByteString -> (ByteString, ByteString)
    parseUnquoted ByteString
    bs =
            let (ByteString
    x, ByteString
    y) = (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
    S.break (Word8 -> Word8 -> Bool
    forall a. Eq a => a -> a -> Bool
    == Word8
    _comma) ByteString
    bs
             in (ByteString
    x, Int -> ByteString -> ByteString
    S.drop Int
    1 ByteString
    y)