hackage-server-0.5.0: Distribution/Server/Framework/HappstackUtils.hs
{-|
Functions and combinators to expose functioanlity buiding
on happstack bit is not really specific to any one area
of Hackage.
-}
module Distribution.Server.Framework.HappstackUtils (
remainingPath,
remainingPathString,
mime,
consumeRequestBody,
uriEscape,
showContentType
) where
import Happstack.Server.Types
import Happstack.Server.Monads
import Happstack.Server.Response
import Happstack.Server.FileServe
import qualified Data.Map as Map
import System.FilePath.Posix (takeExtension, (</>))
import Control.Monad
import qualified Data.ByteString.Lazy as BS
import qualified Network.URI as URI
-- |Passes a list of remaining path segments in the URL. Does not
-- include the query string. This call only fails if the passed in
-- handler fails.
remainingPath :: Monad m => ([String] -> ServerPartT m a) -> ServerPartT m a
remainingPath handle = do
rq <- askRq
localRq (\newRq -> newRq{rqPaths=[]}) $ handle (rqPaths rq)
-- | Gets the string without altering the request.
remainingPathString :: Monad m => ServerPartT m String
remainingPathString = do
strs <- liftM rqPaths askRq
return $ if null strs then "" else foldr1 (</>) . map uriEscape $ strs
-- This disappeared from happstack in 7.1.7
uriEscape :: String -> String
uriEscape = URI.escapeURIString URI.isAllowedInURI
-- |Returns a mime-type string based on the extension of the passed in
-- file.
mime :: FilePath -> String
mime x = Map.findWithDefault "text/plain" (drop 1 (takeExtension x)) mimeTypes
-- | Get the raw body of a PUT or POST request.
--
-- Note that for performance reasons, this consumes the data and it cannot be
-- called twice.
--
consumeRequestBody :: Happstack m => m BS.ByteString
consumeRequestBody = do
mRq <- takeRequestBody =<< askRq
case mRq of
Nothing -> escape $ internalServerError $ toResponse
"consumeRequestBody cannot be called more than once."
Just (Body b) -> return b
-- The following functions are in happstack-server, but not exported. So we
-- copy them here.
-- | Produce the standard string representation of a content-type,
-- e.g. \"text\/html; charset=ISO-8859-1\".
showContentType :: ContentType -> String
showContentType (ContentType x y ps) = x ++ "/" ++ y ++ showParameters ps
-- | Helper for 'showContentType'.
showParameters :: [(String,String)] -> String
showParameters = concatMap f
where f (n,v) = "; " ++ n ++ "=\"" ++ concatMap esc v ++ "\""
esc '\\' = "\\\\"
esc '"' = "\\\""
esc c | c `elem` ['\\','"'] = '\\':[c]
| otherwise = [c]