webgear-server-1.0.5: src/WebGear/Server/Trait/Header.hs
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Server implementation of the `Header` trait.
module WebGear.Server.Trait.Header () where
import Control.Arrow (arr, returnA, (>>>))
import Data.ByteString.Conversion (ToByteString, toByteString')
import qualified Data.HashMap.Strict as HM
import Data.Proxy (Proxy (Proxy))
import Data.String (fromString)
import Data.Text (Text)
import Data.Void (Void)
import GHC.TypeLits (KnownSymbol, symbolVal)
import Network.HTTP.Types (HeaderName)
import Web.HttpApiData (FromHttpApiData, parseHeader)
import WebGear.Core.Modifiers
import WebGear.Core.Request (Request, requestHeader)
import WebGear.Core.Response (Response (..))
import WebGear.Core.Trait (Get (..), Linked, Set (..), unlink)
import WebGear.Core.Trait.Header (Header (..), HeaderNotFound (..), HeaderParseError (..))
import WebGear.Server.Handler (ServerHandler)
extractRequestHeader ::
(Monad m, KnownSymbol name, FromHttpApiData val) =>
Proxy name ->
ServerHandler m (Linked ts Request) (Maybe (Either Text val))
extractRequestHeader proxy = proc req -> do
let headerName :: HeaderName = fromString $ symbolVal proxy
returnA -< parseHeader <$> requestHeader headerName (unlink req)
instance (Monad m, KnownSymbol name, FromHttpApiData val) => Get (ServerHandler m) (Header Required Strict name val) Request where
{-# INLINE getTrait #-}
getTrait ::
Header Required Strict name val ->
ServerHandler m (Linked ts Request) (Either (Either HeaderNotFound HeaderParseError) val)
getTrait Header = extractRequestHeader (Proxy @name) >>> arr f
where
f = \case
Nothing -> Left $ Left HeaderNotFound
Just (Left e) -> Left $ Right $ HeaderParseError e
Just (Right x) -> Right x
instance (Monad m, KnownSymbol name, FromHttpApiData val) => Get (ServerHandler m) (Header Optional Strict name val) Request where
{-# INLINE getTrait #-}
getTrait ::
Header Optional Strict name val ->
ServerHandler m (Linked ts Request) (Either HeaderParseError (Maybe val))
getTrait Header = extractRequestHeader (Proxy @name) >>> arr f
where
f = \case
Nothing -> Right Nothing
Just (Left e) -> Left $ HeaderParseError e
Just (Right x) -> Right $ Just x
instance (Monad m, KnownSymbol name, FromHttpApiData val) => Get (ServerHandler m) (Header Required Lenient name val) Request where
{-# INLINE getTrait #-}
getTrait ::
Header Required Lenient name val ->
ServerHandler m (Linked ts Request) (Either HeaderNotFound (Either Text val))
getTrait Header = extractRequestHeader (Proxy @name) >>> arr f
where
f = \case
Nothing -> Left HeaderNotFound
Just (Left e) -> Right $ Left e
Just (Right x) -> Right $ Right x
instance (Monad m, KnownSymbol name, FromHttpApiData val) => Get (ServerHandler m) (Header Optional Lenient name val) Request where
{-# INLINE getTrait #-}
getTrait ::
Header Optional Lenient name val ->
ServerHandler m (Linked ts Request) (Either Void (Maybe (Either Text val)))
getTrait Header = extractRequestHeader (Proxy @name) >>> arr f
where
f = \case
Nothing -> Right Nothing
Just (Left e) -> Right $ Just $ Left e
Just (Right x) -> Right $ Just $ Right x
instance (Monad m, KnownSymbol name, ToByteString val) => Set (ServerHandler m) (Header Required Strict name val) Response where
{-# INLINE setTrait #-}
setTrait ::
Header Required Strict name val ->
(Linked ts Response -> Response -> val -> Linked (Header Required Strict name val : ts) Response) ->
ServerHandler m (Linked ts Response, val) (Linked (Header Required Strict name val : ts) Response)
setTrait Header f = proc (l, val) -> do
let headerName :: HeaderName = fromString $ symbolVal $ Proxy @name
response@Response{..} = unlink l
response' = response{responseHeaders = HM.insert headerName (toByteString' val) responseHeaders}
returnA -< f l response' val
instance (Monad m, KnownSymbol name, ToByteString val) => Set (ServerHandler m) (Header Optional Strict name val) Response where
{-# INLINE setTrait #-}
setTrait ::
Header Optional Strict name val ->
(Linked ts Response -> Response -> Maybe val -> Linked (Header Optional Strict name val : ts) Response) ->
ServerHandler m (Linked ts Response, Maybe val) (Linked (Header Optional Strict name val : ts) Response)
setTrait Header f = proc (l, maybeVal) -> do
let headerName :: HeaderName = fromString $ symbolVal $ Proxy @name
response@Response{..} = unlink l
response' = response{responseHeaders = HM.alter (const $ toByteString' <$> maybeVal) headerName responseHeaders}
returnA -< f l response' maybeVal