{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-| The @Clacks@ middleware adds a @X-Clacks-Overhead@ header to every response served by a Wai server. To use this package to keep the legacy of Terry Pratchett alive, simply pass your wai application to @clacks gnuTerryPratchett@ before passing it to the @run@ function: > import Network.Wai.Handler.Warp (run) > import Network.Wai.Middleware.Clacks (clacks, gnuTerryPratchett) > > import MyLib.App (myApp) > > main :: IO () > main = run 8080 $ clacks gnuTerryPratchett myApp You can use the 'Clacks' type to build a custom configuration for the 'clacks' function, allowing you to pass anything into the header: > import Data.List.NonEmpty (NonEmpty(..)) > import Network.Wai (Middleware) > import Network.Wai.Middleware.Clacks (Clacks(..), clacks) > > myClacks :: Middleware > myClacks = clacks $ Clacks $ "GNU Ada Lovelace" :| ["GNU Hoban Washburne", "GNU Shephard Book"] For more information about the Clacks or the @X-Clacks-Overhead@ header, check out the . -} module Network.Wai.Middleware.Clacks ( clacks , Clacks(..) , gnuTerryPratchett , clacksHeaderName ) where import Prelude.Compat import Data.List.NonEmpty.Compat ( NonEmpty(..) , toList ) import Data.Text.Encoding ( encodeUtf8 ) import Network.HTTP.Types.Header ( ResponseHeaders , HeaderName ) import Network.Wai ( Middleware , modifyResponse , mapResponseHeaders ) import qualified Data.ByteString as BS import qualified Data.CaseInsensitive as CI import qualified Data.List as L import qualified Data.Text as T -- | A "Network.Wai" 'Middleware' that adds a @X-Clacks-Overhead@ header -- containing the messages in the 'Clacks' configuration. clacks :: Clacks -> Middleware clacks settings = modifyResponse $ mapResponseHeaders addHeader where headerContents :: BS.ByteString headerContents = encodeUtf8 . T.intercalate "," . toList $ clacksMessages settings addHeader :: ResponseHeaders -> ResponseHeaders addHeader hs = case L.find ((== clacksHeaderName) . fst) hs of Nothing -> (clacksHeaderName, headerContents) : hs Just (_, "") -> (clacksHeaderName, headerContents) : hs Just (name, contents) -> (name, contents <> "," <> headerContents) : filter ((/= clacksHeaderName) . fst) hs -- | Configuration for the Clacks WAI Middleware. newtype Clacks = Clacks { clacksMessages :: NonEmpty T.Text -- ^ The Clacks Messages to Include in the Header. } deriving (Show, Read, Eq) -- | Sends a Clacks message of @GNU Terry Pratchett@. gnuTerryPratchett :: Clacks gnuTerryPratchett = Clacks $ "GNU Terry Pratchett" :| [] -- | The name of the Clacks header. clacksHeaderName :: HeaderName clacksHeaderName = CI.mk "X-Clacks-Overhead"