- walkTree :: ResSubtree -> [String] -> Maybe ResourceDef
-
- walkTree subtree (name:[])
- = case M.lookup name subtree of
- Nothing -> Nothing
- Just (ResNode defM _) -> defM
-
- walkTree subtree (x:xs)
- = case M.lookup x subtree of
- Nothing -> Nothing
- Just (ResNode defM children) -> case defM of
- Just (ResourceDef { resIsGreedy = True })
- -> defM
- _ -> walkTree children xs
-
-
-runResource :: ResourceDef -> Interaction -> IO ThreadId
-runResource def itr
- = fork
- $ catch ( runReaderT ( do fromMaybe notAllowed rsrc
- driftTo Done
- ) itr
- )
- $ \ exc -> processException exc
- where
- fork :: IO () -> IO ThreadId
- fork = if (resUsesNativeThread def)
- then forkOS
- else forkIO
-
- rsrc :: Maybe (Resource ())
- rsrc = case reqMethod $ fromJust $ itrRequest itr of
- GET -> resGet def
- HEAD -> case resHead def of
- Just r -> Just r
- Nothing -> resGet def
- POST -> resPost def
- PUT -> resPut def
- DELETE -> resDelete def
-
- notAllowed :: Resource ()
- notAllowed = do setStatus MethodNotAllowed
- setHeader "Allow" $ joinWith ", " allowedMethods
-
- allowedMethods :: [String]
- allowedMethods = nub $ foldr (++) [] [ methods resGet ["GET"]
- , methods resHead ["GET", "HEAD"]
- , methods resPost ["POST"]
- , methods resPut ["PUT"]
- , methods resDelete ["DELETE"]
- ]
-
- methods :: (ResourceDef -> Maybe a) -> [String] -> [String]
- methods f xs = case f def of
- Just _ -> xs
- Nothing -> []
-
- processException :: Exception -> IO ()
- processException exc
- = do let abo = case exc of
- 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 []
- $ 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 $ abortPage conf reqM resM abo
- else
- hPutStrLn stderr $ show abo
-
- flip runReaderT itr $ driftTo Done
-
- formatIOE :: IOError -> String
- formatIOE ioE = if isUserError ioE then
- ioeGetErrorString ioE
- else
- show ioE
+ walkTree ∷ ResSubtree
+ → [ByteString]
+ → Seq ByteString
+ → Maybe ([ByteString], ResourceDef)
+
+ walkTree _ [] _
+ = error "Internal error: should not reach here."
+
+ walkTree tree (name:[]) soFar
+ = do ResNode defM _ ← M.lookup name tree
+ def ← defM
+ return (toList $ soFar ⊳ name, def)
+
+ walkTree tree (x:xs) soFar
+ = do ResNode defM sub ← M.lookup x tree
+ case defM of
+ Just (ResourceDef { resIsGreedy = True })
+ → do def ← defM
+ return (toList $ soFar ⊳ x, def)
+ _ → walkTree sub xs (soFar ⊳ x)
+
+ fallback ∷ [ByteString]
+ → [FallbackHandler]
+ → IO (Maybe ([ByteString], ResourceDef))
+ fallback _ [] = return Nothing
+ fallback path (x:xs) = do m ← x path
+ case m of
+ Just def → return $ Just ([], def)
+ Nothing → fallback path xs