@@ -25,10 +25,11 @@ import Control.Applicative ((<$>))
26import Control.Monad.Trans.Either (EitherT)
26import Control.Monad.Trans.Either (EitherT)
27import qualified Data.ByteString as B
27import qualified Data.ByteString as B
28+import qualified Data.ByteString.Lazy as BL
28import qualified Data.Map as M
29import qualified Data.Map as M
29import Data.Maybe (catMaybes, fromMaybe)
30import Data.Maybe (catMaybes, fromMaybe)
30import Data.String (fromString)
31import Data.String (fromString)
31−import Data.String.Conversions (cs, (<>))
32+import Data.String.Conversions (cs, (<>), ConvertibleStrings)
32import Data.Text (Text)
33import Data.Text (Text)
33import qualified Data.Text as T
34import qualified Data.Text as T
34import Data.Text.Encoding (decodeUtf8, encodeUtf8)
35import Data.Text.Encoding (decodeUtf8, encodeUtf8)
@@ -39,7 +40,8 @@ import Network.Socket (SockAddr)
39import Network.Wai (Application, lazyRequestBody,
40import Network.Wai (Application, lazyRequestBody,
40 rawQueryString, requestHeaders,
41 rawQueryString, requestHeaders,
41 requestMethod, responseLBS, remoteHost,
42 requestMethod, responseLBS, remoteHost,
42− isSecure, vault, httpVersion)
43+ isSecure, vault, httpVersion, Response,
43import Servant.API ((:<|>) (..), (:>), Capture,
45import Servant.API ((:<|>) (..), (:>), Capture,
44 Delete, Get, Header,
46 Delete, Get, Header,
45 IsSecure(..), MatrixFlag, MatrixParam,
47 IsSecure(..), MatrixFlag, MatrixParam,
@@ -121,6 +123,24 @@ instance (KnownSymbol capture, FromText a, HasServer sublayout)
121 Just v -> feedTo subserver v)
123 Just v -> feedTo subserver v)
122 where captureProxy = Proxy :: Proxy (Capture capture a)
124 where captureProxy = Proxy :: Proxy (Capture capture a)
126+allowedMethodHead :: Method -> Request -> Bool
127+allowedMethodHead method request = method == methodGet && requestMethod request == methodHead
129+allowedMethod :: Method -> Request -> Bool
130+allowedMethod method request = allowedMethodHead method request || requestMethod request == method
132+processMethodRouter :: forall a. ConvertibleStrings a B.ByteString
133+ => Maybe (a, BL.ByteString) -> Status -> Method
134+ -> Maybe [(HeaderName, B.ByteString)]
135+ -> Request -> RouteResult Response
136+processMethodRouter handleA status method headers request = case handleA of
137+ Nothing -> failWith UnsupportedMediaType
138+ Just (contentT, body) -> succeedWith $ responseLBS status hdrs bdy
140+ bdy = case allowedMethodHead method request of
143+ hdrs = (hContentType, cs contentT) : (fromMaybe [] headers)
125methodRouter :: (AllCTRender ctypes a)
145methodRouter :: (AllCTRender ctypes a)
126 => Method -> Proxy ctypes -> Status
146 => Method -> Proxy ctypes -> Status
@@ -129,13 +149,11 @@ methodRouter :: (AllCTRender ctypes a)
129methodRouter method proxy status action = LeafRouter route'
149methodRouter method proxy status action = LeafRouter route'
131 route' request respond
151 route' request respond
132− | pathIsEmpty request && requestMethod request == method = do
152+ | pathIsEmpty request && allowedMethod method request = do
133 runAction action respond $ \ output -> do
153 runAction action respond $ \ output -> do
134 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
154 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
135− case handleAcceptH proxy (AcceptHeader accH) output of
155+ handleA = handleAcceptH proxy (AcceptHeader accH) output
136− Nothing -> failWith UnsupportedMediaType
156+ processMethodRouter handleA status method Nothing request
137− Just (contentT, body) -> succeedWith $
138− responseLBS status [ ("Content-Type" , cs contentT)] body
139 | pathIsEmpty request && requestMethod request /= method =
157 | pathIsEmpty request && requestMethod request /= method =
140 respond $ failWith WrongMethod
158 respond $ failWith WrongMethod
141 | otherwise = respond $ failWith NotFound
159 | otherwise = respond $ failWith NotFound
@@ -147,14 +165,12 @@ methodRouterHeaders :: (GetHeaders (Headers h v), AllCTRender ctypes v)
147methodRouterHeaders method proxy status action = LeafRouter route'
165methodRouterHeaders method proxy status action = LeafRouter route'
149 route' request respond
167 route' request respond
150− | pathIsEmpty request && requestMethod request == method = do
168+ | pathIsEmpty request && allowedMethod method request = do
151 runAction action respond $ \ output -> do
169 runAction action respond $ \ output -> do
152 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
170 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
153 headers = getHeaders output
171 headers = getHeaders output
154− case handleAcceptH proxy (AcceptHeader accH) (getResponse output) of
172+ handleA = handleAcceptH proxy (AcceptHeader accH) (getResponse output)
155− Nothing -> failWith UnsupportedMediaType
173+ processMethodRouter handleA status method (Just headers) request
156− Just (contentT, body) -> succeedWith $
157− responseLBS status ( ("Content-Type" , cs contentT) : headers) body
158 | pathIsEmpty request && requestMethod request /= method =
174 | pathIsEmpty request && requestMethod request /= method =
159 respond $ failWith WrongMethod
175 respond $ failWith WrongMethod
160 | otherwise = respond $ failWith NotFound
176 | otherwise = respond $ failWith NotFound
@@ -165,7 +181,7 @@ methodRouterEmpty :: Method
165methodRouterEmpty method action = LeafRouter route'
181methodRouterEmpty method action = LeafRouter route'
167 route' request respond
183 route' request respond
168− | pathIsEmpty request && requestMethod request == method = do
184+ | pathIsEmpty request && allowedMethod method request = do
169 runAction action respond $ \ () ->
185 runAction action respond $ \ () ->
170 succeedWith $ responseLBS noContent204 [] ""
186 succeedWith $ responseLBS noContent204 [] ""
171 | pathIsEmpty request && requestMethod request /= method =
187 | pathIsEmpty request && requestMethod request /= method =
@@ -612,7 +628,6 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
612 values = catMaybes $ map (convert . snd) parameters
628 values = catMaybes $ map (convert . snd) parameters
613 route (Proxy :: Proxy sublayout) (feedTo subserver values)
629 route (Proxy :: Proxy sublayout) (feedTo subserver values)
614 _ -> route (Proxy :: Proxy sublayout) (feedTo subserver [])
630 _ -> route (Proxy :: Proxy sublayout) (feedTo subserver [])
616 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
631 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
617 looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
632 looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
618 convert Nothing = Nothing
633 convert Nothing = Nothing
@@ -644,11 +659,8 @@ instance (KnownSymbol sym, HasServer sublayout)
644 Just Nothing -> True -- param is there, with no value
659 Just Nothing -> True -- param is there, with no value
645 Just (Just v) -> examine v -- param with a value
660 Just (Just v) -> examine v -- param with a value
646 Nothing -> False -- param not in the query string
661 Nothing -> False -- param not in the query string
648 route (Proxy :: Proxy sublayout) (feedTo subserver param)
662 route (Proxy :: Proxy sublayout) (feedTo subserver param)
650 _ -> route (Proxy :: Proxy sublayout) (feedTo subserver False)
663 _ -> route (Proxy :: Proxy sublayout) (feedTo subserver False)
652 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
664 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
653 examine v | v == "true" || v == "1" || v == "" = True
665 examine v | v == "true" || v == "1" || v == "" = True
654 | otherwise = False
666 | otherwise = False