{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Network.HTTP.Client.TLS
(
tlsManagerSettings
, mkManagerSettings
, mkManagerSettingsContext
, newTlsManager
, newTlsManagerWith
, applyDigestAuth
, DigestAuthException (..)
, DigestAuthExceptionDetails (..)
, displayDigestAuthException
, getGlobalManager
, 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)
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
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
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
mkManagerSettingsContext'
:: ManagerSettings
-> Maybe NC.ConnectionContext
-> NC.TLSSettings
-> Maybe NC.SockSettings
-> Maybe NC.SockSettings
-> 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. 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
}
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
ConnectionContext
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
(Maybe HostAddress -> [Char] -> Int -> IO Connection)
-> IO (Maybe HostAddress -> [Char] -> Int -> IO Connection)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Maybe HostAddress -> [Char] -> Int -> IO Connection)
-> IO (Maybe HostAddress -> [Char] -> Int -> IO Connection))
-> (Maybe HostAddress -> [Char] -> Int -> IO Connection)
-> IO (Maybe HostAddress -> [Char] -> Int -> IO Connection)
forall a b. (a -> b) -> a -> b
$ \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
ConnectionContext
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
(ByteString
-> (Connection -> IO ())
-> [Char]
-> Maybe HostAddress
-> [Char]
-> Int
-> IO Connection)
-> IO
(ByteString
-> (Connection -> IO ())
-> [Char]
-> Maybe HostAddress
-> [Char]
-> Int
-> IO Connection)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((ByteString
-> (Connection -> IO ())
-> [Char]
-> Maybe HostAddress
-> [Char]
-> Int
-> IO Connection)
-> IO
(ByteString
-> (Connection -> IO ())
-> [Char]
-> Maybe HostAddress
-> [Char]
-> Int
-> IO Connection))
-> (ByteString
-> (Connection -> IO ())
-> [Char]
-> Maybe HostAddress
-> [Char]
-> Int
-> IO Connection)
-> IO
(ByteString
-> (Connection -> IO ())
-> [Char]
-> Maybe HostAddress
-> [Char]
-> Int
-> IO Connection)
forall a b. (a -> b) -> a -> b
$ \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
Connection
conn' <- Connection -> IO Connection
convertConnection Connection
conn
Connection -> IO ()
checkConn Connection
conn'
ConnectionContext -> Connection -> TLSSettings -> IO ()
NC.connectionSetSecure ConnectionContext
context Connection
conn TLSSettings
tls
Connection -> IO Connection
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Connection
conn'
convertConnection :: NC.Connection -> IO Connection
convertConnection :: Connection -> IO Connection
convertConnection Connection
conn = IO ByteString
-> (ByteString -> IO ()) -> IO () -> Connection -> IO Connection
forall a.
Typeable a =>
IO ByteString
-> (ByteString -> IO ()) -> IO () -> a -> IO Connection
makeConnection
(Connection -> IO ByteString
NC.connectionGetChunk Connection
conn)
(Connection -> ByteString -> IO ()
NC.connectionPut Connection
conn)
(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 ())
Connection
conn
globalConnectionContext :: NC.ConnectionContext
globalConnectionContext :: ConnectionContext
globalConnectionContext = IO ConnectionContext -> ConnectionContext
forall a. IO a -> a
unsafePerformIO IO ConnectionContext
NC.initConnectionContext
{-# NOINLINE globalConnectionContext #-}
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
[([Char], [Char])]
env <- IO [([Char], [Char])]
getEnvironment
let lenv :: Map Text [Char]
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 :: Maybe SockSettings
msocksHTTP = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
parseSocksSettings [([Char], [Char])]
env Map Text [Char]
lenv Text
"http_proxy"
msocksHTTPS :: Maybe SockSettings
msocksHTTPS = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
parseSocksSettings [([Char], [Char])]
env Map Text [Char]
lenv Text
"https_proxy"
settings :: ManagerSettings
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
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
ManagerSettings -> IO Manager
newManager ManagerSettings
settings'
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
[([Char], [Char])]
env <- IO [([Char], [Char])]
getEnvironment
let lenv :: Map Text [Char]
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 :: Maybe SockSettings
msocksHTTP = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
parseSocksSettings [([Char], [Char])]
env Map Text [Char]
lenv Text
"http_proxy"
msocksHTTPS :: Maybe SockSettings
msocksHTTPS = [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
parseSocksSettings [([Char], [Char])]
env Map Text [Char]
lenv Text
"https_proxy"
settings :: ManagerSettings
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
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
{ managerTlsConnection = managerTlsConnection set
, managerTlsProxyConnection = managerTlsProxyConnection set
}
ManagerSettings -> IO Manager
newManager ManagerSettings
settings'
parseSocksSettings :: [(String, String)]
-> Map.Map T.Text String
-> T.Text
-> Maybe NC.SockSettings
parseSocksSettings :: [([Char], [Char])] -> Map Text [Char] -> Text -> Maybe SockSettings
parseSocksSettings [([Char], [Char])]
env Map Text [Char]
lenv Text
n = do
[Char]
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 -> Bool
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
uri <- [Char] -> Maybe URI
U.parseURI [Char]
str
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ [Char] -> Bool
forall {a}. (Eq a, IsString a) => a -> Bool
allowedScheme ([Char] -> Bool) -> [Char] -> Bool
forall a b. (a -> b) -> a -> b
$ URI -> [Char]
U.uriScheme URI
uri
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ [Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (URI -> [Char]
U.uriPath URI
uri) Bool -> Bool -> Bool
|| URI -> [Char]
U.uriPath URI
uri [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
"/"
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ [Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Char] -> Bool) -> [Char] -> Bool
forall a b. (a -> b) -> a -> b
$ URI -> [Char]
U.uriQuery URI
uri
Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Maybe ()) -> Bool -> Maybe ()
forall a b. (a -> b) -> a -> b
$ [Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Char] -> Bool) -> [Char] -> Bool
forall a b. (a -> b) -> a -> b
$ URI -> [Char]
U.uriFragment URI
uri
URIAuth
auth <- URI -> Maybe URIAuth
U.uriAuthority URI
uri
PortNumber
port' <-
case URIAuth -> [Char]
U.uriPort URIAuth
auth of
[Char]
"" -> Maybe PortNumber
forall a. Maybe a
Nothing
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
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.SockSettingsSimple (URIAuth -> [Char]
U.uriRegName URIAuth
auth) PortNumber
port'
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 #-}
getGlobalManager :: IO Manager
getGlobalManager :: IO Manager
getGlobalManager = IORef Manager -> IO Manager
forall a. IORef a -> IO a
readIORef IORef Manager
globalManager
{-# INLINE getGlobalManager #-}
setGlobalManager :: Manager -> IO ()
setGlobalManager :: Manager -> IO ()
setGlobalManager = IORef Manager -> Manager -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef Manager
globalManager
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
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"
data DigestAuthExceptionDetails
= UnexpectedStatusCode
|
| 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)
applyDigestAuth :: (MonadIO m, MonadThrow n)
=> S.ByteString
-> S.ByteString
-> 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
Response ()
res <- Request -> Manager -> IO (Response ())
httpNoBody Request
req Manager
man
let throw' :: DigestAuthExceptionDetails -> n a
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
n Request -> IO (n Request)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (n Request -> IO (n Request)) -> n Request -> IO (n Request)
forall a b. (a -> b) -> a -> b
$ do
Bool -> n () -> n ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Response () -> Status
forall body. Response body -> Status
responseStatus Response ()
res Status -> Status -> Bool
forall a. Eq a => a -> a -> Bool
== Status
status401)
(n () -> n ()) -> n () -> n ()
forall a b. (a -> b) -> a -> b
$ DigestAuthExceptionDetails -> n ()
forall {a}. DigestAuthExceptionDetails -> n a
throw' DigestAuthExceptionDetails
UnexpectedStatusCode
ByteString
h1 <- n ByteString
-> (ByteString -> n ByteString) -> Maybe ByteString -> n ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (DigestAuthExceptionDetails -> n ByteString
forall {a}. DigestAuthExceptionDetails -> n a
throw' DigestAuthExceptionDetails
MissingWWWAuthenticateHeader) ByteString -> n ByteString
forall a. a -> n a
forall (m :: * -> *) a. Monad m => a -> m a
return
(Maybe ByteString -> n ByteString)
-> Maybe ByteString -> n ByteString
forall a b. (a -> b) -> a -> b
$ HeaderName -> [(HeaderName, ByteString)] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup HeaderName
"WWW-Authenticate" ([(HeaderName, ByteString)] -> Maybe ByteString)
-> [(HeaderName, ByteString)] -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Response () -> [(HeaderName, ByteString)]
forall body. Response body -> [(HeaderName, ByteString)]
responseHeaders Response ()
res
ByteString
h2 <- n ByteString
-> (ByteString -> n ByteString) -> Maybe ByteString -> n ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (DigestAuthExceptionDetails -> n ByteString
forall {a}. DigestAuthExceptionDetails -> n a
throw' DigestAuthExceptionDetails
WWWAuthenticateIsNotDigest) ByteString -> n ByteString
forall a. a -> n a
forall (m :: * -> *) a. Monad m => a -> m a
return
(Maybe ByteString -> n ByteString)
-> Maybe ByteString -> n ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> Maybe ByteString
stripCI ByteString
"Digest " ByteString
h1
let pieces :: [(ByteString, ByteString)]
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)
ByteString
realm <- n ByteString
-> (ByteString -> n ByteString) -> Maybe ByteString -> n ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (DigestAuthExceptionDetails -> n ByteString
forall {a}. DigestAuthExceptionDetails -> n a
throw' DigestAuthExceptionDetails
MissingRealm) ByteString -> n ByteString
forall a. a -> n a
forall (m :: * -> *) a. Monad m => a -> m a
return
(Maybe ByteString -> n ByteString)
-> Maybe ByteString -> n ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> [(ByteString, ByteString)] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup ByteString
"realm" [(ByteString, ByteString)]
pieces
ByteString
nonce <- n ByteString
-> (ByteString -> n ByteString) -> Maybe ByteString -> n ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (DigestAuthExceptionDetails -> n ByteString
forall {a}. DigestAuthExceptionDetails -> n a
throw' DigestAuthExceptionDetails
MissingNonce) ByteString -> n ByteString
forall a. a -> n a
forall (m :: * -> *) a. Monad m => a -> m a
return
(Maybe ByteString -> n ByteString)
-> Maybe ByteString -> n ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> [(ByteString, ByteString)] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup ByteString
"nonce" [(ByteString, ByteString)]
pieces
let qop :: Bool
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 :: ByteString
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]
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
key = HeaderName
"Authorization"
val :: ByteString
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
"\""
, 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
""
]
Request -> n Request
forall a. a -> n a
forall (m :: * -> *) a. Monad m => a -> m a
return Request
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
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)