{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
module Servant.Server.Internal.Router where
import Prelude ()
import Prelude.Compat
import Data.Function
(on)
import Data.List
(nub)
import Data.Map
(Map)
import qualified Data.Map as M
import Data.Text
(Text)
import qualified Data.Text as T
import Data.Typeable
(TypeRep)
import Network.Wai
(Response, pathInfo)
import Servant.Server.Internal.ErrorFormatter
import Servant.Server.Internal.RouteResult
import Servant.Server.Internal.RoutingApplication
import Servant.Server.Internal.ServerError
type Router env = Router' env RoutingApplication
data CaptureHint = CaptureHint
{ CaptureHint -> Text
captureName :: Text
, CaptureHint -> TypeRep
captureType :: TypeRep
}
deriving (Int -> CaptureHint -> ShowS
[CaptureHint] -> ShowS
CaptureHint -> String
(Int -> CaptureHint -> ShowS)
-> (CaptureHint -> String)
-> ([CaptureHint] -> ShowS)
-> Show CaptureHint
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CaptureHint -> ShowS
showsPrec :: Int -> CaptureHint -> ShowS
$cshow :: CaptureHint -> String
show :: CaptureHint -> String
$cshowList :: [CaptureHint] -> ShowS
showList :: [CaptureHint] -> ShowS
Show, CaptureHint -> CaptureHint -> Bool
(CaptureHint -> CaptureHint -> Bool)
-> (CaptureHint -> CaptureHint -> Bool) -> Eq CaptureHint
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CaptureHint -> CaptureHint -> Bool
== :: CaptureHint -> CaptureHint -> Bool
$c/= :: CaptureHint -> CaptureHint -> Bool
/= :: CaptureHint -> CaptureHint -> Bool
Eq)
toCaptureTag :: CaptureHint -> Text
toCaptureTag :: CaptureHint -> Text
toCaptureTag CaptureHint
hint = CaptureHint -> Text
captureName CaptureHint
hint Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"::" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (String -> Text
T.pack (String -> Text) -> (TypeRep -> String) -> TypeRep -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypeRep -> String
forall a. Show a => a -> String
show) (CaptureHint -> TypeRep
captureType CaptureHint
hint)
toCaptureTags :: [CaptureHint] -> Text
toCaptureTags :: [CaptureHint] -> Text
toCaptureTags [CaptureHint]
hints = Text
"<" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate Text
"|" ((CaptureHint -> Text) -> [CaptureHint] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map CaptureHint -> Text
toCaptureTag [CaptureHint]
hints) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
">"
data Router' env a =
StaticRouter (Map Text (Router' env a)) [env -> a]
| CaptureRouter [CaptureHint] (Router' (Text, env) a)
| CaptureAllRouter [CaptureHint] (Router' ([Text], env) a)
| RawRouter (env -> a)
| Choice (Router' env a) (Router' env a)
deriving (forall a b. (a -> b) -> Router' env a -> Router' env b)
-> (forall a b. a -> Router' env b -> Router' env a)
-> Functor (Router' env)
forall a b. a -> Router' env b -> Router' env a
forall a b. (a -> b) -> Router' env a -> Router' env b
forall env a b. a -> Router' env b -> Router' env a
forall env a b. (a -> b) -> Router' env a -> Router' env b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall env a b. (a -> b) -> Router' env a -> Router' env b
fmap :: forall a b. (a -> b) -> Router' env a -> Router' env b
$c<$ :: forall env a b. a -> Router' env b -> Router' env a
<$ :: forall a b. a -> Router' env b -> Router' env a
Functor
pathRouter :: Text -> Router' env a -> Router' env a
pathRouter :: forall env a. Text -> Router' env a -> Router' env a
pathRouter Text
t Router' env a
r = Map Text (Router' env a) -> [env -> a] -> Router' env a
forall env a.
Map Text (Router' env a) -> [env -> a] -> Router' env a
StaticRouter (Text -> Router' env a -> Map Text (Router' env a)
forall k a. k -> a -> Map k a
M.singleton Text
t Router' env a
r) []
leafRouter :: (env -> a) -> Router' env a
leafRouter :: forall env a. (env -> a) -> Router' env a
leafRouter env -> a
l = Map Text (Router' env a) -> [env -> a] -> Router' env a
forall env a.
Map Text (Router' env a) -> [env -> a] -> Router' env a
StaticRouter Map Text (Router' env a)
forall k a. Map k a
M.empty [env -> a
l]
choice :: Router' env a -> Router' env a -> Router' env a
choice :: forall env a. Router' env a -> Router' env a -> Router' env a
choice (StaticRouter Map Text (Router' env a)
table1 [env -> a]
ls1) (StaticRouter Map Text (Router' env a)
table2 [env -> a]
ls2) =
Map Text (Router' env a) -> [env -> a] -> Router' env a
forall env a.
Map Text (Router' env a) -> [env -> a] -> Router' env a
StaticRouter ((Router' env a -> Router' env a -> Router' env a)
-> Map Text (Router' env a)
-> Map Text (Router' env a)
-> Map Text (Router' env a)
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
M.unionWith Router' env a -> Router' env a -> Router' env a
forall env a. Router' env a -> Router' env a -> Router' env a
choice Map Text (Router' env a)
table1 Map Text (Router' env a)
table2) ([env -> a]
ls1 [env -> a] -> [env -> a] -> [env -> a]
forall a. [a] -> [a] -> [a]
++ [env -> a]
ls2)
choice (CaptureRouter [CaptureHint]
hints1 Router' (Text, env) a
router1) (CaptureRouter [CaptureHint]
hints2 Router' (Text, env) a
router2) =
[CaptureHint] -> Router' (Text, env) a -> Router' env a
forall env a.
[CaptureHint] -> Router' (Text, env) a -> Router' env a
CaptureRouter ([CaptureHint] -> [CaptureHint]
forall a. Eq a => [a] -> [a]
nub ([CaptureHint] -> [CaptureHint]) -> [CaptureHint] -> [CaptureHint]
forall a b. (a -> b) -> a -> b
$ [CaptureHint]
hints1 [CaptureHint] -> [CaptureHint] -> [CaptureHint]
forall a. [a] -> [a] -> [a]
++ [CaptureHint]
hints2) (Router' (Text, env) a
-> Router' (Text, env) a -> Router' (Text, env) a
forall env a. Router' env a -> Router' env a -> Router' env a
choice Router' (Text, env) a
router1 Router' (Text, env) a
router2)
choice Router' env a
router1 (Choice Router' env a
router2 Router' env a
router3) = Router' env a -> Router' env a -> Router' env a
forall env a. Router' env a -> Router' env a -> Router' env a
Choice (Router' env a -> Router' env a -> Router' env a
forall env a. Router' env a -> Router' env a -> Router' env a
choice Router' env a
router1 Router' env a
router2) Router' env a
router3
choice Router' env a
router1 Router' env a
router2 = Router' env a -> Router' env a -> Router' env a
forall env a. Router' env a -> Router' env a -> Router' env a
Choice Router' env a
router1 Router' env a
router2
data RouterStructure =
StaticRouterStructure (Map Text RouterStructure) Int
| CaptureRouterStructure [CaptureHint] RouterStructure
| RawRouterStructure
| ChoiceStructure RouterStructure RouterStructure
deriving (RouterStructure -> RouterStructure -> Bool
(RouterStructure -> RouterStructure -> Bool)
-> (RouterStructure -> RouterStructure -> Bool)
-> Eq RouterStructure
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: RouterStructure -> RouterStructure -> Bool
== :: RouterStructure -> RouterStructure -> Bool
$c/= :: RouterStructure -> RouterStructure -> Bool
/= :: RouterStructure -> RouterStructure -> Bool
Eq, Int -> RouterStructure -> ShowS
[RouterStructure] -> ShowS
RouterStructure -> String
(Int -> RouterStructure -> ShowS)
-> (RouterStructure -> String)
-> ([RouterStructure] -> ShowS)
-> Show RouterStructure
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RouterStructure -> ShowS
showsPrec :: Int -> RouterStructure -> ShowS
$cshow :: RouterStructure -> String
show :: RouterStructure -> String
$cshowList :: [RouterStructure] -> ShowS
showList :: [RouterStructure] -> ShowS
Show)
routerStructure :: Router' env a -> RouterStructure
routerStructure :: forall env a. Router' env a -> RouterStructure
routerStructure (StaticRouter Map Text (Router' env a)
m [env -> a]
ls) =
Map Text RouterStructure -> Int -> RouterStructure
StaticRouterStructure ((Router' env a -> RouterStructure)
-> Map Text (Router' env a) -> Map Text RouterStructure
forall a b. (a -> b) -> Map Text a -> Map Text b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Router' env a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Map Text (Router' env a)
m) ([env -> a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [env -> a]
ls)
routerStructure (CaptureRouter [CaptureHint]
hints Router' (Text, env) a
router) =
[CaptureHint] -> RouterStructure -> RouterStructure
CaptureRouterStructure [CaptureHint]
hints (RouterStructure -> RouterStructure)
-> RouterStructure -> RouterStructure
forall a b. (a -> b) -> a -> b
$
Router' (Text, env) a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' (Text, env) a
router
routerStructure (CaptureAllRouter [CaptureHint]
hints Router' ([Text], env) a
router) =
[CaptureHint] -> RouterStructure -> RouterStructure
CaptureRouterStructure [CaptureHint]
hints (RouterStructure -> RouterStructure)
-> RouterStructure -> RouterStructure
forall a b. (a -> b) -> a -> b
$
Router' ([Text], env) a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' ([Text], env) a
router
routerStructure (RawRouter env -> a
_) =
RouterStructure
RawRouterStructure
routerStructure (Choice Router' env a
r1 Router' env a
r2) =
RouterStructure -> RouterStructure -> RouterStructure
ChoiceStructure
(Router' env a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' env a
r1)
(Router' env a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' env a
r2)
sameStructure :: Router' env a -> Router' env b -> Bool
sameStructure :: forall env a b. Router' env a -> Router' env b -> Bool
sameStructure Router' env a
router1 Router' env b
router2 =
Router' env a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' env a
router1 RouterStructure -> RouterStructure -> Bool
forall a. Eq a => a -> a -> Bool
== Router' env b -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' env b
router2
routerLayout :: Router' env a -> Text
routerLayout :: forall env a. Router' env a -> Text
routerLayout Router' env a
router =
[Text] -> Text
T.unlines ([Text
"/"] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
False (Router' env a -> RouterStructure
forall env a. Router' env a -> RouterStructure
routerStructure Router' env a
router))
where
mkRouterLayout :: Bool -> RouterStructure -> [Text]
mkRouterLayout :: Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
c (StaticRouterStructure Map Text RouterStructure
m Int
n) = Bool -> [(Text, RouterStructure)] -> Int -> [Text]
mkSubTrees Bool
c (Map Text RouterStructure -> [(Text, RouterStructure)]
forall k a. Map k a -> [(k, a)]
M.toList Map Text RouterStructure
m) Int
n
mkRouterLayout Bool
c (CaptureRouterStructure [CaptureHint]
hints RouterStructure
r) =
Bool -> Text -> [Text] -> [Text]
mkSubTree Bool
c ([CaptureHint] -> Text
toCaptureTags [CaptureHint]
hints) (Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
False RouterStructure
r)
mkRouterLayout Bool
c RouterStructure
RawRouterStructure =
if Bool
c then [Text
"├─ <raw>"] else [Text
"└─ <raw>"]
mkRouterLayout Bool
c (ChoiceStructure RouterStructure
r1 RouterStructure
r2) =
Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
True RouterStructure
r1 [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [Text
"┆"] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
c RouterStructure
r2
mkSubTrees :: Bool -> [(Text, RouterStructure)] -> Int -> [Text]
mkSubTrees :: Bool -> [(Text, RouterStructure)] -> Int -> [Text]
mkSubTrees Bool
_ [] Int
0 = []
mkSubTrees Bool
c [] Int
n =
[[Text]] -> [Text]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (Int -> [Text] -> [[Text]]
forall a. Int -> a -> [a]
replicate (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Bool -> [Text]
mkLeaf Bool
True) [[Text]] -> [[Text]] -> [[Text]]
forall a. [a] -> [a] -> [a]
++ [Bool -> [Text]
mkLeaf Bool
c])
mkSubTrees Bool
c [(Text
t, RouterStructure
r)] Int
0 =
Bool -> Text -> [Text] -> [Text]
mkSubTree Bool
c Text
t (Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
False RouterStructure
r)
mkSubTrees Bool
c ((Text
t, RouterStructure
r) : [(Text, RouterStructure)]
trs) Int
n =
Bool -> Text -> [Text] -> [Text]
mkSubTree Bool
True Text
t (Bool -> RouterStructure -> [Text]
mkRouterLayout Bool
False RouterStructure
r) [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ Bool -> [(Text, RouterStructure)] -> Int -> [Text]
mkSubTrees Bool
c [(Text, RouterStructure)]
trs Int
n
mkLeaf :: Bool -> [Text]
mkLeaf :: Bool -> [Text]
mkLeaf Bool
True = [Text
"├─•",Text
"┆"]
mkLeaf Bool
False = [Text
"└─•"]
mkSubTree :: Bool -> Text -> [Text] -> [Text]
mkSubTree :: Bool -> Text -> [Text] -> [Text]
mkSubTree Bool
True Text
path [Text]
children = (Text
"├─ " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
path Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/") Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text
"│ " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) [Text]
children
mkSubTree Bool
False Text
path [Text]
children = (Text
"└─ " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
path Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"/") Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>) [Text]
children
tweakResponse :: (RouteResult Response -> RouteResult Response) -> Router env -> Router env
tweakResponse :: forall env.
(RouteResult Response -> RouteResult Response)
-> Router env -> Router env
tweakResponse RouteResult Response -> RouteResult Response
f = (RoutingApplication -> RoutingApplication)
-> Router' env RoutingApplication -> Router' env RoutingApplication
forall a b. (a -> b) -> Router' env a -> Router' env b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\RoutingApplication
a -> \Request
req RouteResult Response -> IO ResponseReceived
cont -> RoutingApplication
a Request
req (RouteResult Response -> IO ResponseReceived
cont (RouteResult Response -> IO ResponseReceived)
-> (RouteResult Response -> RouteResult Response)
-> RouteResult Response
-> IO ResponseReceived
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RouteResult Response -> RouteResult Response
f))
runRouter :: NotFoundErrorFormatter -> Router () -> RoutingApplication
runRouter :: NotFoundErrorFormatter -> Router () -> RoutingApplication
runRouter NotFoundErrorFormatter
fmt Router ()
r = NotFoundErrorFormatter -> Router () -> () -> RoutingApplication
forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router ()
r ()
runRouterEnv :: NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv :: forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router env
router env
env Request
request RouteResult Response -> IO ResponseReceived
respond =
case Router env
router of
StaticRouter Map Text (Router env)
table [env -> RoutingApplication]
ls ->
case Request -> [Text]
pathInfo Request
request of
[] -> NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
runChoice NotFoundErrorFormatter
fmt [env -> RoutingApplication]
ls env
env Request
request RouteResult Response -> IO ResponseReceived
respond
[Text
""] -> NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
runChoice NotFoundErrorFormatter
fmt [env -> RoutingApplication]
ls env
env Request
request RouteResult Response -> IO ResponseReceived
respond
Text
first : [Text]
rest | Just Router env
router' <- Text -> Map Text (Router env) -> Maybe (Router env)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
first Map Text (Router env)
table
-> let request' :: Request
request' = Request
request { pathInfo = rest }
in NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router env
router' env
env Request
request' RouteResult Response -> IO ResponseReceived
respond
[Text]
_ -> RouteResult Response -> IO ResponseReceived
respond (RouteResult Response -> IO ResponseReceived)
-> RouteResult Response -> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ ServerError -> RouteResult Response
forall a. ServerError -> RouteResult a
Fail (ServerError -> RouteResult Response)
-> ServerError -> RouteResult Response
forall a b. (a -> b) -> a -> b
$ NotFoundErrorFormatter
fmt Request
request
CaptureRouter [CaptureHint]
_ Router' (Text, env) RoutingApplication
router' ->
case Request -> [Text]
pathInfo Request
request of
[] -> RouteResult Response -> IO ResponseReceived
respond (RouteResult Response -> IO ResponseReceived)
-> RouteResult Response -> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ ServerError -> RouteResult Response
forall a. ServerError -> RouteResult a
Fail (ServerError -> RouteResult Response)
-> ServerError -> RouteResult Response
forall a b. (a -> b) -> a -> b
$ NotFoundErrorFormatter
fmt Request
request
[Text
""] -> RouteResult Response -> IO ResponseReceived
respond (RouteResult Response -> IO ResponseReceived)
-> RouteResult Response -> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ ServerError -> RouteResult Response
forall a. ServerError -> RouteResult a
Fail (ServerError -> RouteResult Response)
-> ServerError -> RouteResult Response
forall a b. (a -> b) -> a -> b
$ NotFoundErrorFormatter
fmt Request
request
Text
first : [Text]
rest
-> let request' :: Request
request' = Request
request { pathInfo = rest }
in NotFoundErrorFormatter
-> Router' (Text, env) RoutingApplication
-> (Text, env)
-> RoutingApplication
forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router' (Text, env) RoutingApplication
router' (Text
first, env
env) Request
request' RouteResult Response -> IO ResponseReceived
respond
CaptureAllRouter [CaptureHint]
_ Router' ([Text], env) RoutingApplication
router' ->
let segments :: [Text]
segments = Request -> [Text]
pathInfo Request
request
request' :: Request
request' = Request
request { pathInfo = [] }
in NotFoundErrorFormatter
-> Router' ([Text], env) RoutingApplication
-> ([Text], env)
-> RoutingApplication
forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router' ([Text], env) RoutingApplication
router' ([Text]
segments, env
env) Request
request' RouteResult Response -> IO ResponseReceived
respond
RawRouter env -> RoutingApplication
app ->
env -> RoutingApplication
app env
env Request
request RouteResult Response -> IO ResponseReceived
respond
Choice Router env
r1 Router env
r2 ->
NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
runChoice NotFoundErrorFormatter
fmt [NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router env
r1, NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter -> Router env -> env -> RoutingApplication
runRouterEnv NotFoundErrorFormatter
fmt Router env
r2] env
env Request
request RouteResult Response -> IO ResponseReceived
respond
runChoice :: NotFoundErrorFormatter -> [env -> RoutingApplication] -> env -> RoutingApplication
runChoice :: forall env.
NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
runChoice NotFoundErrorFormatter
fmt [env -> RoutingApplication]
ls =
case [env -> RoutingApplication]
ls of
[] -> \ env
_ Request
request RouteResult Response -> IO ResponseReceived
respond -> RouteResult Response -> IO ResponseReceived
respond (ServerError -> RouteResult Response
forall a. ServerError -> RouteResult a
Fail (ServerError -> RouteResult Response)
-> ServerError -> RouteResult Response
forall a b. (a -> b) -> a -> b
$ NotFoundErrorFormatter
fmt Request
request)
[env -> RoutingApplication
r] -> env -> RoutingApplication
r
(env -> RoutingApplication
r : [env -> RoutingApplication]
rs) ->
\ env
env Request
request RouteResult Response -> IO ResponseReceived
respond ->
env -> RoutingApplication
r env
env Request
request ((RouteResult Response -> IO ResponseReceived)
-> IO ResponseReceived)
-> (RouteResult Response -> IO ResponseReceived)
-> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ \ RouteResult Response
response1 ->
case RouteResult Response
response1 of
Fail ServerError
_ -> NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
forall env.
NotFoundErrorFormatter
-> [env -> RoutingApplication] -> env -> RoutingApplication
runChoice NotFoundErrorFormatter
fmt [env -> RoutingApplication]
rs env
env Request
request ((RouteResult Response -> IO ResponseReceived)
-> IO ResponseReceived)
-> (RouteResult Response -> IO ResponseReceived)
-> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ \ RouteResult Response
response2 ->
RouteResult Response -> IO ResponseReceived
respond (RouteResult Response -> IO ResponseReceived)
-> RouteResult Response -> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ RouteResult Response
-> RouteResult Response -> RouteResult Response
forall {a}. RouteResult a -> RouteResult a -> RouteResult a
highestPri RouteResult Response
response1 RouteResult Response
response2
RouteResult Response
_ -> RouteResult Response -> IO ResponseReceived
respond RouteResult Response
response1
where
highestPri :: RouteResult a -> RouteResult a -> RouteResult a
highestPri (Fail ServerError
e1) (Fail ServerError
e2) =
if Int -> Int -> Bool
worseHTTPCode (ServerError -> Int
errHTTPCode ServerError
e1) (ServerError -> Int
errHTTPCode ServerError
e2)
then ServerError -> RouteResult a
forall a. ServerError -> RouteResult a
Fail ServerError
e2
else ServerError -> RouteResult a
forall a. ServerError -> RouteResult a
Fail ServerError
e1
highestPri (Fail ServerError
_) RouteResult a
y = RouteResult a
y
highestPri RouteResult a
x RouteResult a
_ = RouteResult a
x
worseHTTPCode :: Int -> Int -> Bool
worseHTTPCode :: Int -> Int -> Bool
worseHTTPCode = (Int -> Int -> Bool) -> (Int -> Int) -> Int -> Int -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(<) Int -> Int
toPriority
where
toPriority :: Int -> Int
toPriority :: Int -> Int
toPriority Int
404 = Int
0
toPriority Int
405 = Int
1
toPriority Int
401 = Int
2
toPriority Int
415 = Int
3
toPriority Int
406 = Int
4
toPriority Int
400 = Int
6
toPriority Int
_ = Int
5