module Network.HTTP.Lucu.Resource.Tree
( ResourceDef(..)
- , Resource
, ResTree
, mkResTree -- [ ([String], ResourceDef) ] -> ResTree
- , findResource -- ResTree -> URI -> Maybe ResourceDef
+ , findResource -- ResTree -> URI -> Maybe ([String], ResourceDef)
, runResource -- ResourceDef -> Interaction -> IO ThreadId
)
where
import Data.Maybe
import Network.HTTP.Lucu.Abortion
import Network.HTTP.Lucu.Config
+import Network.HTTP.Lucu.MIMEType
import Network.HTTP.Lucu.Request
import Network.HTTP.Lucu.Resource
import Network.HTTP.Lucu.Response
import Prelude hiding (catch)
-{- /aaa/bbb/ccc にアクセスされた時、もし /aaa/bbb に貪欲なリソースがあ
- れば、假に /aaa/bbb/ccc に何らかのリソースがあったとしても必ず
- /aaa/bbb が撰ばれる。/aaa/bbb のリソースが貪欲でなければ、それは無視
- される。 -}
+-- "/aaa/bbb/ccc" にアクセスされた時、もし "/aaa/bbb" に貪欲なリソース
+-- があれば、假に "/aaa/bbb/ccc" に何らかのリソースがあったとしても必ず
+-- "/aaa/bbb" が撰ばれる。"/aaa/bbb" のリソースが貪欲でなければ、それは
+-- 無視される。
data ResourceDef = ResourceDef {
resUsesNativeThread :: Bool
, resIsGreedy :: Bool
children = processNonRoot nonRoots
in
if null roots then
- -- / にリソースが定義されない。/foo とかにはあるかも。
+ -- "/" にリソースが定義されない。"/foo" とかにはあるかも。
ResNode Nothing children
else
- -- / がある。
+ -- "/" がある。
let (_, def) = last roots
in
ResNode (Just def) children
subtree
-findResource :: ResTree -> URI -> Maybe ResourceDef
+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
- rootDefM
+ do def <- rootDefM
+ return (path, def)
else
- walkTree subtree path
+ walkTree subtree path []
where
- walkTree :: ResSubtree -> [String] -> Maybe ResourceDef
+ walkTree :: ResSubtree -> [String] -> [String] -> Maybe ([String], ResourceDef)
- walkTree subtree (name:[])
+ walkTree subtree (name:[]) soFar
= case M.lookup name subtree of
Nothing -> Nothing
- Just (ResNode defM _) -> defM
+ Just (ResNode defM _) -> do def <- defM
+ return (soFar ++ [name], def)
- walkTree subtree (x:xs)
+ walkTree subtree (x:xs) soFar
= case M.lookup x subtree of
Nothing -> Nothing
Just (ResNode defM children) -> case defM of
Just (ResourceDef { resIsGreedy = True })
- -> defM
- _ -> walkTree children xs
+ -> do def <- defM
+ return (soFar ++ [x], def)
+ _ -> walkTree children xs (soFar ++ [x])
runResource :: ResourceDef -> Interaction -> IO ThreadId
driftTo Done
) itr
)
- $ \ exc -> processException (itrConfig itr) exc
+ $ \ exc -> processException exc
where
fork :: IO () -> IO ThreadId
fork = if (resUsesNativeThread def)
Just _ -> xs
Nothing -> []
- processException :: Config -> Exception -> IO ()
- processException conf exc
+ processException :: Exception -> IO ()
+ processException exc
= do let abo = case exc of
- ErrorCall msg -> Abortion InternalServerError [] msg
- IOException ioE -> Abortion InternalServerError [] $ formatIOE ioE
+ ErrorCall msg -> Abortion InternalServerError [] $ Just msg
+ IOException ioE -> Abortion InternalServerError [] $ Just $ formatIOE ioE
DynException dynE -> case fromDynamic dynE of
Just (abo :: Abortion) -> abo
Nothing
-> Abortion InternalServerError []
- $ show exc
- _ -> Abortion InternalServerError [] $ show exc
+ $ Just $ show exc
+ _ -> Abortion InternalServerError [] $ Just $ show exc
+ conf = itrConfig itr
+ reqM = itrRequest itr
-- まだ DecidingHeader 以前の状態だったら、この途中終了
-- を應答に反映させる餘地がある。さうでなければ stderr
-- にでも吐くしか無い。
state <- atomically $ readItr itr itrState id
+ resM <- atomically $ readItr itr itrResponse id
if state <= DecidingHeader then
flip runReaderT itr
$ do setStatus $ aboStatus abo
-- FIXME: 同じ名前で複數の値があった時は、こ
-- れではまずいと思ふ。
mapM_ (\ (name, value) -> setHeader name value) $ aboHeaders abo
- setHeader "Content-Type" "application/xhtml+xml"
- output $ aboPage conf abo
+ setContentType ("application" </> "xhtml+xml")
+ output $ abortPage conf reqM resM abo
else
hPutStrLn stderr $ show abo