{-# LANGUAGE FlexibleInstances, PatternGuards, ScopedTypeVariables, TypeSynonymInstances #-}
module Happstack.Server.Routing
(
http
, https
, methodM
, methodOnly
, methodSP
, method
, MatchMethod(..)
, dir
, dirs
, nullDir
, trailingSlash
, noTrailingSlash
, anyPath
, path
, uriRest
, host
, withHost
, guardRq
) where
import Control.Monad (MonadPlus(mzero), unless)
import qualified Data.ByteString.Char8 as B
import Happstack.Server.Monads (ServerMonad(..))
import Happstack.Server.Types (Request(..), Method(..), FromReqURI(..), getHeader, rqURL)
import System.FilePath (makeRelative, splitDirectories)
class MatchMethod m where
matchMethod :: m -> Method -> Bool
instance MatchMethod Method where
matchMethod :: Method -> Method -> Bool
matchMethod Method
m = forall m. MatchMethod m => m -> Method -> Bool
matchMethod (forall a. Eq a => a -> a -> Bool
== Method
m)
instance MatchMethod [Method] where
matchMethod :: [Method] -> Method -> Bool
matchMethod [Method]
ms Method
m = forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (forall m. MatchMethod m => m -> Method -> Bool
`matchMethod` Method
m) [Method]
ms
instance MatchMethod (Method -> Bool) where
matchMethod :: (Method -> Bool) -> Method -> Bool
matchMethod Method -> Bool
f Method
HEAD = Method -> Bool
f Method
HEAD Bool -> Bool -> Bool
|| Method -> Bool
f Method
GET
matchMethod Method -> Bool
f Method
m = Method -> Bool
f Method
m
instance MatchMethod () where
matchMethod :: () -> Method -> Bool
matchMethod () Method
_ = Bool
True
guardRq :: (ServerMonad m, MonadPlus m) => (Request -> Bool) -> m ()
guardRq :: forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq Request -> Bool
f = do
Request
rq <- forall (m :: * -> *). ServerMonad m => m Request
askRq
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Request -> Bool
f Request
rq) forall (m :: * -> *) a. MonadPlus m => m a
mzero
http :: (ServerMonad m, MonadPlus m) => m ()
http :: forall (m :: * -> *). (ServerMonad m, MonadPlus m) => m ()
http = forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. Request -> Bool
rqSecure)
https :: (ServerMonad m, MonadPlus m) => m ()
https :: forall (m :: * -> *). (ServerMonad m, MonadPlus m) => m ()
https = forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq Request -> Bool
rqSecure
method :: (ServerMonad m, MonadPlus m, MatchMethod method) => method -> m ()
method :: forall (m :: * -> *) method.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m ()
method method
meth = forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq forall a b. (a -> b) -> a -> b
$ \Request
rq -> forall m. MatchMethod m => m -> Method -> Bool
matchMethod method
meth (Request -> Method
rqMethod Request
rq)
methodM :: (ServerMonad m, MonadPlus m, MatchMethod method) => method -> m ()
methodM :: forall (m :: * -> *) method.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m ()
methodM method
meth = forall (m :: * -> *) method.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m ()
methodOnly method
meth forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *). (ServerMonad m, MonadPlus m) => m ()
nullDir
methodOnly :: (ServerMonad m, MonadPlus m, MatchMethod method) => method -> m ()
methodOnly :: forall (m :: * -> *) method.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m ()
methodOnly = forall (m :: * -> *) method.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m ()
method
{-# DEPRECATED methodOnly "this function is just an alias for method now" #-}
{-# DEPRECATED methodSP "use method instead." #-}
methodSP :: (ServerMonad m, MonadPlus m, MatchMethod method) => method -> m b-> m b
methodSP :: forall (m :: * -> *) method b.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m b -> m b
methodSP method
m m b
handle = forall (m :: * -> *) method.
(ServerMonad m, MonadPlus m, MatchMethod method) =>
method -> m ()
methodM method
m forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> m b
handle
nullDir :: (ServerMonad m, MonadPlus m) => m ()
nullDir :: forall (m :: * -> *). (ServerMonad m, MonadPlus m) => m ()
nullDir = forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq forall a b. (a -> b) -> a -> b
$ \Request
rq -> forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Request -> [String]
rqPaths Request
rq)
dir :: (ServerMonad m, MonadPlus m) => String -> m a -> m a
dir :: forall (m :: * -> *) a.
(ServerMonad m, MonadPlus m) =>
String -> m a -> m a
dir String
staticPath m a
handle =
do
Request
rq <- forall (m :: * -> *). ServerMonad m => m Request
askRq
case Request -> [String]
rqPaths Request
rq of
(String
p:[String]
xs) | String
p forall a. Eq a => a -> a -> Bool
== String
staticPath -> forall (m :: * -> *) a.
ServerMonad m =>
(Request -> Request) -> m a -> m a
localRq (\Request
newRq -> Request
newRq{rqPaths :: [String]
rqPaths = [String]
xs}) m a
handle
[String]
_ -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
dirs :: (ServerMonad m, MonadPlus m) => FilePath -> m a -> m a
dirs :: forall (m :: * -> *) a.
(ServerMonad m, MonadPlus m) =>
String -> m a -> m a
dirs String
fp m a
m =
do let parts :: [String]
parts = String -> [String]
splitDirectories (String -> String -> String
makeRelative String
"/" String
fp)
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall (m :: * -> *) a.
(ServerMonad m, MonadPlus m) =>
String -> m a -> m a
dir m a
m [String]
parts
host :: (ServerMonad m, MonadPlus m) => String -> m a -> m a
host :: forall (m :: * -> *) a.
(ServerMonad m, MonadPlus m) =>
String -> m a -> m a
host String
desiredHost m a
handle =
do Request
rq <- forall (m :: * -> *). ServerMonad m => m Request
askRq
case forall r. HasHeaders r => String -> r -> Maybe ByteString
getHeader String
"host" Request
rq of
(Just ByteString
hostBS) | String
desiredHost forall a. Eq a => a -> a -> Bool
== ByteString -> String
B.unpack ByteString
hostBS -> m a
handle
Maybe ByteString
_ -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
withHost :: (ServerMonad m, MonadPlus m) => (String -> m a) -> m a
withHost :: forall (m :: * -> *) a.
(ServerMonad m, MonadPlus m) =>
(String -> m a) -> m a
withHost String -> m a
handle =
do Request
rq <- forall (m :: * -> *). ServerMonad m => m Request
askRq
case forall r. HasHeaders r => String -> r -> Maybe ByteString
getHeader String
"host" Request
rq of
(Just ByteString
hostBS) -> String -> m a
handle (ByteString -> String
B.unpack ByteString
hostBS)
Maybe ByteString
_ -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
path :: (FromReqURI a, MonadPlus m, ServerMonad m) => (a -> m b) -> m b
path :: forall a (m :: * -> *) b.
(FromReqURI a, MonadPlus m, ServerMonad m) =>
(a -> m b) -> m b
path a -> m b
handle = do
Request
rq <- forall (m :: * -> *). ServerMonad m => m Request
askRq
case Request -> [String]
rqPaths Request
rq of
(String
p:[String]
xs) | Just a
a <- forall a. FromReqURI a => String -> Maybe a
fromReqURI String
p
-> forall (m :: * -> *) a.
ServerMonad m =>
(Request -> Request) -> m a -> m a
localRq (\Request
newRq -> Request
newRq{rqPaths :: [String]
rqPaths = [String]
xs}) (a -> m b
handle a
a)
[String]
_ -> forall (m :: * -> *) a. MonadPlus m => m a
mzero
uriRest :: (ServerMonad m) => (String -> m a) -> m a
uriRest :: forall (m :: * -> *) a. ServerMonad m => (String -> m a) -> m a
uriRest String -> m a
handle = forall (m :: * -> *). ServerMonad m => m Request
askRq forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> m a
handle forall b c a. (b -> c) -> (a -> b) -> a -> c
. Request -> String
rqURL
anyPath :: (ServerMonad m, MonadPlus m) => m r -> m r
anyPath :: forall (m :: * -> *) r. (ServerMonad m, MonadPlus m) => m r -> m r
anyPath m r
x = forall a (m :: * -> *) b.
(FromReqURI a, MonadPlus m, ServerMonad m) =>
(a -> m b) -> m b
path forall a b. (a -> b) -> a -> b
$ (\(String
_::String) -> m r
x)
trailingSlash :: (ServerMonad m, MonadPlus m) => m ()
trailingSlash :: forall (m :: * -> *). (ServerMonad m, MonadPlus m) => m ()
trailingSlash = forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq forall a b. (a -> b) -> a -> b
$ \Request
rq -> (forall a. [a] -> a
last (Request -> String
rqUri Request
rq)) forall a. Eq a => a -> a -> Bool
== Char
'/'
noTrailingSlash :: (ServerMonad m, MonadPlus m) => m ()
noTrailingSlash :: forall (m :: * -> *). (ServerMonad m, MonadPlus m) => m ()
noTrailingSlash = forall (m :: * -> *).
(ServerMonad m, MonadPlus m) =>
(Request -> Bool) -> m ()
guardRq forall a b. (a -> b) -> a -> b
$ \Request
rq -> (forall a. [a] -> a
last (Request -> String
rqUri Request
rq)) forall a. Eq a => a -> a -> Bool
/= Char
'/'