X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FResource%2FTree.hs;h=2cd498f7ade7c7f4e5435d2344e161a5717cf65e;hb=50e8fe7af585a8d33d93b3721be8f8f01905b891;hp=bb12dd0ee5c49bb7c3fdce0d58c6e090626eaeb0;hpb=e53a2f3202f763e844de725712f1bf26b82cd41f;p=Lucu.git diff --git a/Network/HTTP/Lucu/Resource/Tree.hs b/Network/HTTP/Lucu/Resource/Tree.hs index bb12dd0..2cd498f 100644 --- a/Network/HTTP/Lucu/Resource/Tree.hs +++ b/Network/HTTP/Lucu/Resource/Tree.hs @@ -4,6 +4,8 @@ module Network.HTTP.Lucu.Resource.Tree ( ResourceDef(..) , ResTree + , FallbackHandler + , mkResTree -- [ ([String], ResourceDef) ] -> ResTree , findResource -- ResTree -> URI -> Maybe ([String], ResourceDef) @@ -35,6 +37,15 @@ import System.IO.Error hiding (catch) 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" のリソースが貪欲でなければ、それは @@ -55,7 +66,7 @@ data ResourceDef = ResourceDef { -- 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, @@ -89,13 +100,13 @@ data ResourceDef = ResourceDef { , 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\" ) -- \/ @@ -112,12 +123,12 @@ mkResTree list = list `seq` processRoot list 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 @@ -139,16 +150,19 @@ mkResTree list = list `seq` processRoot 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) @@ -167,6 +181,13 @@ findResource (ResNode rootDefM subtree) uri 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