miku-2011.6.11: src/Network/Miku/Middleware/MikuRouter.hs
{-# LANGUAGE OverloadedStrings #-}
module Network.Miku.Middleware.MikuRouter (miku_router) where
import Data.Maybe
import Hack2
import Hack2.Contrib.Utils
import Hack2.Contrib.Utils hiding (get, put)
import Air.Env
import Air.Extra
import Prelude ()
import Data.ByteString.UTF8 (fromString)
import qualified Prelude as P
import qualified Data.ByteString.Lazy.Char8 as B
import Data.ByteString.Lazy.Char8 (ByteString)
type RoutePathT a = (RequestMethod, ByteString, a)
miku_router :: ByteString -> (a -> Application) -> RoutePathT a -> Middleware
miku_router prefix runner route_path app = \env ->
if route_path.match_route env.not
then app env
else do
let (_, template, app_state) = route_path
(_, params) = parse_params template (env.path_info) .fromJust
runner app_state (env .merge_captured params)
where
match_route env' (method, template, _) =
env'.request_method.is method
&& env'.path_info.parse_params template .isJust
merge_captured params env' =
env'.put_namespace prefix params
parse_params :: ByteString -> ByteString -> Maybe (ByteString, [(ByteString, ByteString)])
parse_params "" "" = Just ("", [])
parse_params "" _ = Nothing
parse_params "/" "" = Nothing
parse_params "/" _ = Just ("/", [])
parse_params t s =
let template_tokens = t.B.split '/'
url_tokens = s.B.split '/'
in
if url_tokens.length P.< template_tokens.length
then Nothing
else
let rs = zipWith capture template_tokens url_tokens
in
if rs.all isJust
then
let token_length = template_tokens.length
location = B.pack - "/" / (B.unpack - url_tokens.take token_length .B.intercalate "/")
in
Just - (location, rs.catMaybes.catMaybes)
else Nothing
where
capture x y
| x.B.unpack.starts_with ":" = Just - Just (x.B.tail, y)
| x == y = Just Nothing
| otherwise = Nothing
-- copy from miku utils
put_namespace :: ByteString -> [(ByteString, ByteString)] -> Env -> Env
put_namespace x xs env =
let adds = xs.map_fst (x +)
new_headers = adds.map fst
new_hack_headers =
env.hackHeaders.reject (fst > belongs_to new_headers) ++ adds
in
env {hackHeaders = new_hack_headers}