prodapi-proxy-0.1.0.0: src/Prod/Proxy/MultiApp.hs
{-# LANGUAGE TupleSections #-}
-- | Set of helpers to configure WarpTLS settings.
module Prod.Proxy.MultiApp where
import Control.Applicative ((<|>))
import qualified Data.ByteString.Char8 as ByteString
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe (fromMaybe)
import Network.TLS as TLS
import Network.Wai as WAI
import Network.Wai.Handler.WarpTLS as WarpTLS
import Network.Wai.Internal as WAI
-- TLS
type CredentialMap = Map TLS.HostName TLS.Credentials
type DefaultCredentials = TLS.Credentials
type X509Path = FilePath
type PrivateKeyPath = FilePath
loadCredentialMap :: [(HostName, X509Path, PrivateKeyPath)] -> IO (Either String CredentialMap)
loadCredentialMap configs = do
loads <- traverse loadHostConfig configs
pure $ fmap bundleMap (sequence loads)
where
loadHostConfig :: (HostName, X509Path, PrivateKeyPath) -> IO (Either String (HostName, Credential))
loadHostConfig (h, x, k) = do
c <- TLS.credentialLoadX509 x k
pure $ fmap (h,) c
bundleMap :: [(HostName, Credential)] -> CredentialMap
bundleMap pairs = Map.fromListWith (<>) [(h, Credentials [c]) | (h, c) <- pairs]
type SNIHandler = Maybe HostName -> IO (Credentials)
toSNIHandler ::
CredentialMap ->
DefaultCredentials ->
SNIHandler
toSNIHandler m def = \h -> case h of
Nothing -> pure def
Just x -> pure $ fromMaybe def $ Map.lookup x m
withTLSCredentialMap ::
CredentialMap ->
DefaultCredentials ->
TLSSettings ->
TLSSettings
withTLSCredentialMap m c tlsSetts =
let
hooks = (tlsServerHooks tlsSetts){onServerNameIndication = toSNIHandler m c}
in
tlsSetts{tlsServerHooks = hooks}
-- WEB
type ApplicationMap = Map TLS.HostName WAI.Application
routeApplication :: ApplicationMap -> WAI.Application -> WAI.Application
routeApplication apps defaultApp = \req reply -> do
let host = ByteString.unpack <$> WAI.requestHeaderHost req
let routedApp = host >>= flip Map.lookup apps
let app = fromMaybe defaultApp routedApp
app req reply