{-# LANGUAGE OverloadedStrings #-} module Network.Wai.Middleware.Debug ( debug , debugHandle ) where import Network.Wai (Request(..), Middleware) import Network.Wai.Parse (parseRequestBody, lbsSink, fileName, Param, File) import Data.ByteString.Char8 (unpack) import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import System.IO (hPutStrLn, stderr) import Control.Monad.IO.Class (liftIO) import qualified Data.Text.Lazy as T import Data.Enumerator (run_, ($$), enumList) import Data.Enumerator.List (consume) -- | Prints a message to 'stderr' for each request. debug :: Middleware debug = debugHandle $ hPutStrLn stderr . T.unpack -- | Prints a message using the given callback function for each request. -- This is not for serious production use- it is inefficient. -- It immediately consumes a POST body and fills it back in and is otherwise inefficient debugHandle :: (T.Text -> IO ()) -> Middleware debugHandle cb app req = do body <- consume postParams <- if any (requestMethod req ==) ["GET", "HEAD"] then return [] else do postParams <- liftIO $ allPostParams req body return $ collectPostParams postParams let getParams = map emptyGetParam $ queryString req liftIO $ cb $ T.pack $ concat [ unpack $ requestMethod req , " " , unpack $ rawPathInfo req , "\n" , (++) "Accept: " $ maybe "" unpack $ lookup "Accept" $ requestHeaders req , paramsToStr "GET " getParams , paramsToStr "POST " postParams ] -- we just consumed the body- fill the enumerator back up so it is available again liftIO $ run_ $ enumList 1 body $$ app req where paramsToStr prefix params = if null params then "" else "\n" ++ prefix ++ (show params) allPostParams req' body = run_ $ enumList 1 body $$ parseRequestBody lbsSink req' emptyGetParam :: (S.ByteString, Maybe S.ByteString) -> (S.ByteString, S.ByteString) emptyGetParam (k, Just v) = (k,v) emptyGetParam (k, Nothing) = (k,"") collectPostParams :: ([Param], [File L.ByteString]) -> [Param] collectPostParams (postParams, files) = postParams ++ (map (\(k,v) -> (k, S.append "FILE: " (fileName v))) files)