]> gitweb @ CieloNegro.org - Lucu.git/blobdiff - Network/HTTP/Lucu/Resource/Tree.hs
Network.HTTP.Lucu
[Lucu.git] / Network / HTTP / Lucu / Resource / Tree.hs
index 062ffdca9217b5dd5462cf238fdb97e033b01ca7..e4fa662688ad24ccdf642283f0790350779ad659 100644 (file)
@@ -1,10 +1,9 @@
 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
@@ -20,6 +19,7 @@ import           Data.Map (Map)
 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
@@ -31,10 +31,10 @@ import           System.IO.Error hiding (catch)
 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
@@ -58,10 +58,10 @@ mkResTree list = processRoot list
                 children = processNonRoot nonRoots
             in
               if null roots then
-                  -- / にリソースが定義されない。/foo とかにはあるかも。
+                  -- "/" にリソースが定義されない。"/foo" とかにはあるかも。
                   ResNode Nothing children
               else
-                  -- / がある。
+                  -- "/" がある。
                   let (_, def) = last roots
                   in 
                     ResNode (Just def) children
@@ -86,30 +86,33 @@ mkResTree list = processRoot list
               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
@@ -119,7 +122,7 @@ runResource def itr
                                 driftTo Done
                            ) itr
               )
-      $ \ exc -> processException (itrConfig itr) exc
+      $ \ exc -> processException exc
     where
       fork :: IO () -> IO ThreadId
       fork = if (resUsesNativeThread def)
@@ -153,29 +156,32 @@ runResource def itr
                        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