module Hack.Frontend.MonadCGI
( cgiToApp
, cgiToAppGeneric
) where
import Hack
import Network.CGI.Monad
import Network.CGI.Protocol
import qualified Data.Map as Map
import qualified Data.ByteString.Lazy as BS
import Control.Arrow (first)
import Data.Char (toUpper)
safeRead :: Read a => a -> String -> a
safeRead d s = case reads s of
((x, _):_) -> x
_ -> d
cgiToApp :: CGI CGIResult -> Application
cgiToApp = cgiToAppGeneric id
cgiToAppGeneric :: Monad m
=> (m (Headers, CGIResult) -> IO (Headers, CGIResult))
-> CGIT m CGIResult
-> Application
cgiToAppGeneric toIO cgi env = do
let vars = map (first fixVarName) (http env)++ getCgiVars env
input = hackInput env
(inputs, body') = decodeInput vars input
req = CGIRequest
{ cgiVars = Map.fromList $ vars
, cgiInputs = inputs
, cgiRequestBody = body'
}
(headers'', output') <- toIO $ runCGIT cgi req
let output = case output' of
CGIOutput bs -> bs
CGINothing -> BS.empty
let headers' = map (\(HeaderName x, y) -> (x, y)) headers''
let status' = case lookup "Status" headers' of
Nothing -> 200
Just s -> safeRead 200 s
return $ Response status' headers' output
fixVarName :: String -> String
fixVarName = ((++) $ "HTTP_") . map fixVarNameChar
fixVarNameChar :: Char -> Char
fixVarNameChar '-' = '_'
fixVarNameChar c = toUpper c
getCgiVars :: Env -> [(String, String)]
getCgiVars e =
[ ("PATH_INFO", pathInfo e)
, ("REQUEST_METHOD", show $ requestMethod e)
, ("SCRIPT_NAME", scriptName e)
, ("QUERY_STRING", queryString e)
, ("SERVER_NAME", serverName e)
, ("SERVER_PORT", show $ serverPort e)
]