module Development.Bake.Web(
Input(..), Output(..), send, server
) where
import Development.Bake.Type hiding (run)
import Network.Wai.Handler.Warp hiding (Port)
import Network.Wai
import Control.DeepSeq
import Control.Exception
import Network.HTTP.Types.Status
import Network.HTTP hiding (Request)
import qualified Data.Text as Text
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as LBS
import System.Console.CmdArgs.Verbosity
data Input = Input
{inputURL :: [String]
,inputArgs :: [(String, String)]
,inputBody :: String
} deriving Show
data Output
= OutputString String
| OutputHTML String
| OutputFile FilePath
| OutputError String
| OutputMissing
deriving Show
instance NFData Output where
rnf (OutputString x) = rnf x
rnf (OutputHTML x) = rnf x
rnf (OutputFile x) = rnf x
rnf (OutputError x) = rnf x
rnf OutputMissing = ()
send :: (Host,Port) -> Input -> IO String
send (host,port) Input{..} = do
let url = "http://" ++ host ++ ":" ++ show port ++ concatMap ('/':) inputURL ++
concat (zipWith (++) ("?":repeat "&") [a ++ "=" ++ b | (a,b) <- inputArgs])
whenLoud $ print ("sending",inputBody,host,port)
res <- simpleHTTP (getRequest url)
{rqBody=inputBody
,rqHeaders=[Header HdrContentType "application/x-www-form-urlencoded", Header HdrContentLength $ show $ length inputBody]}
case res of
Left err -> error $ show err
Right r | rspCode r /= (2,0,0) -> error $
"Incorrect code: " ++ show (rspCode r,rspReason r,url) ++ "\n" ++ rspBody r
| otherwise -> return $ rspBody r
server :: Port -> (Input -> IO Output) -> IO ()
server port act = runSettings (setOnException exception $ setPort port defaultSettings) $ \req reply -> do
bod <- strictRequestBody req
whenLoud $ print ("receiving",bod,requestHeaders req,port)
let pay = Input
(map Text.unpack $ pathInfo req)
[(BS.unpack a, maybe "" BS.unpack b) | (a,b) <- queryString req]
(LBS.unpack bod)
res <- act pay
reply $ case res of
OutputFile file -> responseFile status200 [] file Nothing
OutputString msg -> responseLBS status200 [] $ LBS.pack msg
OutputHTML msg -> responseLBS status200 [("content-type","text/html")] $ LBS.pack msg
OutputError msg -> responseLBS status500 [] $ LBS.pack msg
OutputMissing -> responseLBS status404 [] $ LBS.pack "Resource not found"
exception :: Maybe Request -> SomeException -> IO ()
exception r e
| Just (_ :: InvalidRequest) <- fromException e = return ()
| otherwise = putStrLn $ "Error when processing " ++ maybe "Nothing" (show . rawPathInfo) r ++
"\n " ++ show e