module Network.HTTP.Lucu.Resource.Tree
( ResourceDef(..)
, ResTree
+ , FallbackHandler
+
, mkResTree -- [ ([String], ResourceDef) ] -> ResTree
, findResource -- ResTree -> URI -> Maybe ([String], ResourceDef)
import Prelude hiding (catch)
+-- |'FallbackHandler' is an extra resource handler for resources which
+-- can't be statically located somewhere in the resource tree. The
+-- Lucu httpd first search for a resource in the tree, and then call
+-- fallback handlers to ask them for a resource. If all of the
+-- handlers returned 'Prelude.Nothing', the httpd responds with 404
+-- Not Found.
+type FallbackHandler = [String] -> IO (Maybe ResourceDef)
+
+
-- "/aaa/bbb/ccc" にアクセスされた時、もし "/aaa/bbb" に貪欲なリソース
-- があれば、假に "/aaa/bbb/ccc" に何らかのリソースがあったとしても必ず
-- "/aaa/bbb" が撰ばれる。"/aaa/bbb" のリソースが貪欲でなければ、それは
-- greedy resource at \/aaa\/bbb, it is always chosen even if
-- there is another resource at \/aaa\/bbb\/ccc. If the resource
-- at \/aaa\/bbb is not greedy, it is just ignored. Greedy
- -- resource is like a CGI script.
+ -- resources are like CGI scripts.
, resIsGreedy :: !Bool
-- | A 'Network.HTTP.Lucu.Resource.Resource' to be run when a GET
-- request comes for the resource path. If 'resGet' is Nothing,
, resDelete :: !(Maybe (Resource ()))
}
--- | 'ResTree' is an opaque structure which is a map from resource
--- path to 'ResourceDef'.
-type ResTree = ResNode -- root だから Map ではない
+-- |'ResTree' is an opaque structure which is a map from resource path
+-- to 'ResourceDef'.
+newtype ResTree = ResTree ResNode -- root だから Map ではない
type ResSubtree = Map String ResNode
data ResNode = ResNode !(Maybe ResourceDef) !ResSubtree
--- | 'mkResTree' converts a list of @(path, def)@ to a 'ResTree' e.g.
+-- |'mkResTree' converts a list of @(path, def)@ to a 'ResTree' e.g.
--
-- @
-- mkResTree [ ([] , 'Network.HTTP.Lucu.StaticFile.staticFile' \"\/usr\/include\/stdio.h\" ) -- \/
in
if null roots then
-- "/" にリソースが定義されない。"/foo" とかにはあるかも。
- ResNode Nothing children
+ ResTree (ResNode Nothing children)
else
-- "/" がある。
let (_, def) = last roots
in
- ResNode (Just def) children
+ ResTree (ResNode (Just def) children)
processNonRoot :: [ ([String], ResourceDef) ] -> ResSubtree
processNonRoot list
subtree
-findResource :: ResTree -> URI -> Maybe ([String], ResourceDef)
-findResource (ResNode rootDefM subtree) uri
- = let pathStr = uriPath uri
- path = [x | x <- splitBy (== '/') pathStr, x /= ""]
- in
- if null path then
- do def <- rootDefM
- return (path, def)
- else
- walkTree subtree path []
+findResource :: ResTree -> [FallbackHandler] -> URI -> IO (Maybe ([String], ResourceDef))
+findResource (ResTree (ResNode rootDefM subtree)) fbs uri
+ = do let pathStr = uriPath uri
+ path = [x | x <- splitBy (== '/') pathStr, x /= ""]
+ foundInTree = if null path then
+ do def <- rootDefM
+ return (path, def)
+ else
+ walkTree subtree path []
+ if isJust foundInTree then
+ return foundInTree
+ else
+ fallback path fbs
where
walkTree :: ResSubtree -> [String] -> [String] -> Maybe ([String], ResourceDef)
return (soFar ++ [x], def)
_ -> walkTree children xs (soFar ++ [x])
+ fallback :: [String] -> [FallbackHandler] -> IO (Maybe ([String], ResourceDef))
+ fallback _ [] = return Nothing
+ fallback path (x:xs) = do m <- x path
+ case m of
+ Just def -> return $! Just ([], def)
+ Nothing -> fallback path xs
+
runResource :: ResourceDef -> Interaction -> IO ThreadId
runResource def itr