module Network.Wai.Frontend.MonadCGI ( cgiToApp , cgiToAppGeneric ) where import Network.Wai import Network.Wai.Source import Network.CGI.Monad import Network.CGI.Protocol import qualified Data.Map as Map import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Char8 as S8 import Control.Arrow (first) import Data.Char (toUpper) import Data.String (fromString) 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 input <- toLBS $ requestBody env let vars = map (first fixVarName . go) (requestHeaders env) ++ getCgiVars 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) -> (fromString x, S8.pack y)) headers'' let status' = case lookup (fromString "Status") headers' of Nothing -> 200 Just s -> safeRead 200 $ S8.unpack s return $ Response (Status status' S8.empty) headers' $ ResponseLBS output where go (x, y) = (S8.unpack $ ciOriginal x, S8.unpack y) fixVarName :: String -> String fixVarName = ((++) $ "HTTP_") . map fixVarNameChar fixVarNameChar :: Char -> Char fixVarNameChar '-' = '_' fixVarNameChar c = toUpper c getCgiVars :: Request -> [(String, String)] getCgiVars e = [ ("PATH_INFO", S8.unpack $ pathInfo e) , ("REQUEST_METHOD", show $ requestMethod e) , ("QUERY_STRING", S8.unpack $ queryString e) , ("SERVER_NAME", S8.unpack $ serverName e) , ("SERVER_PORT", show $ serverPort e) ]