@@ -22,6 +22,7 @@ module Servant.Server.Internal
22 , module Servant.Server.Internal.ServantErr
22 , module Servant.Server.Internal.ServantErr
25+import Control.Monad.Trans (liftIO)
25import qualified Data.ByteString as B
26import qualified Data.ByteString as B
26import qualified Data.ByteString.Char8 as BC8
27import qualified Data.ByteString.Char8 as BC8
27import qualified Data.ByteString.Lazy as BL
28import qualified Data.ByteString.Lazy as BL
@@ -70,7 +71,11 @@ import Servant.Server.Internal.ServantErr
70class HasServer layout context where
71class HasServer layout context where
71 type ServerT layout (m :: * -> *) :: *
72 type ServerT layout (m :: * -> *) :: *
73− route :: Proxy layout -> Context context -> Delayed (Server layout) -> Router
77+ -> Delayed env (Server layout)
75type Server layout = ServerT layout Handler
80type Server layout = ServerT layout Handler
@@ -92,7 +97,7 @@ instance (HasServer a context, HasServer b context) => HasServer (a :<|> b) cont
92 type ServerT (a :<|> b) m = ServerT a m :<|> ServerT b m
97 type ServerT (a :<|> b) m = ServerT a m :<|> ServerT b m
94 route Proxy context server = choice (route pa context ((\ (a :<|> _) -> a) <$> server))
99 route Proxy context server = choice (route pa context ((\ (a :<|> _) -> a) <$> server))
95− (route pb context ((\ (_ :<|> b) -> b) <$> server))
100+ (route pb context ((\ (_ :<|> b) -> b) <$> server))
96 where pa = Proxy :: Proxy a
101 where pa = Proxy :: Proxy a
97 pb = Proxy :: Proxy b
102 pb = Proxy :: Proxy b
@@ -120,12 +125,12 @@ instance (KnownSymbol capture, FromHttpApiData a, HasServer sublayout context)
120 a -> ServerT sublayout m
125 a -> ServerT sublayout m
122 route Proxy context d =
127 route Proxy context d =
123− DynamicRouter $ \ first ->
128+ CaptureRouter $
124 route (Proxy :: Proxy sublayout)
129 route (Proxy :: Proxy sublayout)
126− (addCapture d $ case parseUrlPieceMaybe first :: Maybe a of
131+ (addCapture d $ \ txt -> case parseUrlPieceMaybe txt :: Maybe a of
127− Nothing -> return $ Fail err400
132+ Nothing -> delayedFail err400
128− Just v -> return $ Route v
133+ Just v -> return v
131allowedMethodHead :: Method -> Request -> Bool
136allowedMethodHead :: Method -> Request -> Bool
@@ -144,41 +149,41 @@ processMethodRouter handleA status method headers request = case handleA of
144 bdy = if allowedMethodHead method request then "" else body
149 bdy = if allowedMethodHead method request then "" else body
145 hdrs = (hContentType, cs contentT) : (fromMaybe [] headers)
150 hdrs = (hContentType, cs contentT) : (fromMaybe [] headers)
147−methodCheck :: Method -> Request -> IO (RouteResult ())
152+methodCheck :: Method -> Request -> DelayedIO ()
148methodCheck method request
153methodCheck method request
149− | allowedMethod method request = return $ Route ()
154+ | allowedMethod method request = return ()
150− | otherwise = return $ Fail err405
155+ | otherwise = delayedFail err405
152−acceptCheck :: (AllMime list) => Proxy list -> B.ByteString -> IO (RouteResult ())
157+acceptCheck :: (AllMime list) => Proxy list -> B.ByteString -> DelayedIO ()
153acceptCheck proxy accH
158acceptCheck proxy accH
154− | canHandleAcceptH proxy (AcceptHeader accH) = return $ Route ()
159+ | canHandleAcceptH proxy (AcceptHeader accH) = return ()
155− | otherwise = return $ FailFatal err406
160+ | otherwise = delayedFailFatal err406
157methodRouter :: (AllCTRender ctypes a)
162methodRouter :: (AllCTRender ctypes a)
158 => Method -> Proxy ctypes -> Status
163 => Method -> Proxy ctypes -> Status
159− -> Delayed (Handler a)
164+ -> Delayed env (Handler a)
160− -> Router
165+ -> Router env
161methodRouter method proxy status action = leafRouter route'
166methodRouter method proxy status action = leafRouter route'
163− route' request respond =
168+ route' env request respond =
164 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
169 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
165 in runAction (action `addMethodCheck` methodCheck method request
170 in runAction (action `addMethodCheck` methodCheck method request
166 `addAcceptCheck` acceptCheck proxy accH
171 `addAcceptCheck` acceptCheck proxy accH
167− ) respond $ \ output -> do
172+ ) env request respond $ \ output -> do
168 let handleA = handleAcceptH proxy (AcceptHeader accH) output
173 let handleA = handleAcceptH proxy (AcceptHeader accH) output
169 processMethodRouter handleA status method Nothing request
174 processMethodRouter handleA status method Nothing request
171methodRouterHeaders :: (GetHeaders (Headers h v), AllCTRender ctypes v)
176methodRouterHeaders :: (GetHeaders (Headers h v), AllCTRender ctypes v)
172 => Method -> Proxy ctypes -> Status
177 => Method -> Proxy ctypes -> Status
173− -> Delayed (Handler (Headers h v))
178+ -> Delayed env (Handler (Headers h v))
174− -> Router
179+ -> Router env
175methodRouterHeaders method proxy status action = leafRouter route'
180methodRouterHeaders method proxy status action = leafRouter route'
177− route' request respond =
182+ route' env request respond =
178 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
183 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
179 in runAction (action `addMethodCheck` methodCheck method request
184 in runAction (action `addMethodCheck` methodCheck method request
180 `addAcceptCheck` acceptCheck proxy accH
185 `addAcceptCheck` acceptCheck proxy accH
181− ) respond $ \ output -> do
186+ ) env request respond $ \ output -> do
182 let headers = getHeaders output
187 let headers = getHeaders output
183 handleA = handleAcceptH proxy (AcceptHeader accH) (getResponse output)
188 handleA = handleAcceptH proxy (AcceptHeader accH) (getResponse output)
184 processMethodRouter handleA status method (Just headers) request
189 processMethodRouter handleA status method (Just headers) request
@@ -230,8 +235,8 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
230 type ServerT (Header sym a :> sublayout) m =
235 type ServerT (Header sym a :> sublayout) m =
231 Maybe a -> ServerT sublayout m
236 Maybe a -> ServerT sublayout m
233− route Proxy context subserver = WithRequest $ \ request ->
238+ route Proxy context subserver =
234− let mheader = parseHeaderMaybe =<< lookup str (requestHeaders request)
239+ let mheader req = parseHeaderMaybe =<< lookup str (requestHeaders req)
235 in route (Proxy :: Proxy sublayout) context (passToServer subserver mheader)
240 in route (Proxy :: Proxy sublayout) context (passToServer subserver mheader)
236 where str = fromString $ symbolVal (Proxy :: Proxy sym)
241 where str = fromString $ symbolVal (Proxy :: Proxy sym)
@@ -262,10 +267,10 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
262 type ServerT (QueryParam sym a :> sublayout) m =
267 type ServerT (QueryParam sym a :> sublayout) m =
263 Maybe a -> ServerT sublayout m
268 Maybe a -> ServerT sublayout m
265− route Proxy context subserver = WithRequest $ \ request ->
270+ route Proxy context subserver =
266− let querytext = parseQueryText $ rawQueryString request
271+ let querytext r = parseQueryText $ rawQueryString r
267− param =
272+ param r =
268− case lookup paramname querytext of
273+ case lookup paramname (querytext r) of
269 Nothing -> Nothing -- param absent from the query string
274 Nothing -> Nothing -- param absent from the query string
270 Just Nothing -> Nothing -- param present with no value -> Nothing
275 Just Nothing -> Nothing -- param present with no value -> Nothing
271 Just (Just v) -> parseQueryParamMaybe v -- if present, we try to convert to
276 Just (Just v) -> parseQueryParamMaybe v -- if present, we try to convert to
@@ -298,13 +303,13 @@ instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout context)
298 type ServerT (QueryParams sym a :> sublayout) m =
303 type ServerT (QueryParams sym a :> sublayout) m =
299 [a] -> ServerT sublayout m
304 [a] -> ServerT sublayout m
301− route Proxy context subserver = WithRequest $ \ request ->
306+ route Proxy context subserver =
302− let querytext = parseQueryText $ rawQueryString request
307+ let querytext r = parseQueryText $ rawQueryString r
303 -- if sym is "foo", we look for query string parameters
308 -- if sym is "foo", we look for query string parameters
304 -- named "foo" or "foo[]" and call parseQueryParam on the
309 -- named "foo" or "foo[]" and call parseQueryParam on the
305 -- corresponding values
310 -- corresponding values
306− parameters = filter looksLikeParam querytext
311+ parameters r = filter looksLikeParam (querytext r)
307− values = mapMaybe (convert . snd) parameters
312+ values r = mapMaybe (convert . snd) (parameters r)
308 in route (Proxy :: Proxy sublayout) context (passToServer subserver values)
313 in route (Proxy :: Proxy sublayout) context (passToServer subserver values)
309 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
314 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
310 looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
315 looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
@@ -329,9 +334,9 @@ instance (KnownSymbol sym, HasServer sublayout context)
329 type ServerT (QueryFlag sym :> sublayout) m =
334 type ServerT (QueryFlag sym :> sublayout) m =
330 Bool -> ServerT sublayout m
335 Bool -> ServerT sublayout m
332− route Proxy context subserver = WithRequest $ \ request ->
337+ route Proxy context subserver =
333− let querytext = parseQueryText $ rawQueryString request
338+ let querytext r = parseQueryText $ rawQueryString r
334− param = case lookup paramname querytext of
339+ param r = case lookup paramname (querytext r) of
335 Just Nothing -> True -- param is there, with no value
340 Just Nothing -> True -- param is there, with no value
336 Just (Just v) -> examine v -- param with a value
341 Just (Just v) -> examine v -- param with a value
337 Nothing -> False -- param not in the query string
342 Nothing -> False -- param not in the query string
@@ -352,8 +357,8 @@ instance HasServer Raw context where
353 type ServerT Raw m = Application
358 type ServerT Raw m = Application
355− route Proxy _ rawApplication = RawRouter $ \ request respond -> do
360+ route Proxy _ rawApplication = RawRouter $ \ env request respond -> do
356− r <- runDelayed rawApplication
361+ r <- runDelayed rawApplication env request
357 case r of
362 case r of
358 Route app -> app request (respond . Route)
363 Route app -> app request (respond . Route)
359 Fail a -> respond $ Fail a
364 Fail a -> respond $ Fail a
@@ -386,10 +391,10 @@ instance ( AllCTUnrender list a, HasServer sublayout context
386 type ServerT (ReqBody list a :> sublayout) m =
391 type ServerT (ReqBody list a :> sublayout) m =
387 a -> ServerT sublayout m
392 a -> ServerT sublayout m
389− route Proxy context subserver = WithRequest $ \ request ->
394+ route Proxy context subserver =
390− route (Proxy :: Proxy sublayout) context (addBodyCheck subserver (bodyCheck request))
395+ route (Proxy :: Proxy sublayout) context (addBodyCheck subserver bodyCheck)
392− bodyCheck request = do
397+ bodyCheck = withRequest $ \ request -> do
393 -- See HTTP RFC 2616, section 7.2.1
398 -- See HTTP RFC 2616, section 7.2.1
394 -- http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
399 -- http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
395 -- See also "W3C Internet Media Type registration, consistency of use"
400 -- See also "W3C Internet Media Type registration, consistency of use"
@@ -397,11 +402,11 @@ instance ( AllCTUnrender list a, HasServer sublayout context
397 let contentTypeH = fromMaybe "application/octet-stream"
402 let contentTypeH = fromMaybe "application/octet-stream"
398 $ lookup hContentType $ requestHeaders request
403 $ lookup hContentType $ requestHeaders request
399 mrqbody <- handleCTypeH (Proxy :: Proxy list) (cs contentTypeH)
404 mrqbody <- handleCTypeH (Proxy :: Proxy list) (cs contentTypeH)
400− <$> lazyRequestBody request
405+ <$> liftIO (lazyRequestBody request)
401 case mrqbody of
406 case mrqbody of
402− Nothing -> return $ FailFatal err415
407+ Nothing -> delayedFailFatal err415
403− Just (Left e) -> return $ FailFatal err400 { errBody = cs e }
408+ Just (Left e) -> delayedFailFatal err400 { errBody = cs e }
404− Just (Right v) -> return $ Route v
409+ Just (Right v) -> return v
406-- | Make sure the incoming request starts with @"/path"@, strip it and
411-- | Make sure the incoming request starts with @"/path"@, strip it and
407-- pass the rest of the request path to @sublayout@.
412-- pass the rest of the request path to @sublayout@.
@@ -418,28 +423,28 @@ instance (KnownSymbol path, HasServer sublayout context) => HasServer (path :> s
418instance HasServer api context => HasServer (RemoteHost :> api) context where
423instance HasServer api context => HasServer (RemoteHost :> api) context where
419 type ServerT (RemoteHost :> api) m = SockAddr -> ServerT api m
424 type ServerT (RemoteHost :> api) m = SockAddr -> ServerT api m
421− route Proxy context subserver = WithRequest $ \req ->
426+ route Proxy context subserver =
422− route (Proxy :: Proxy api) context (passToServer subserver $ remoteHost req)
427+ route (Proxy :: Proxy api) context (passToServer subserver remoteHost)
424instance HasServer api context => HasServer (IsSecure :> api) context where
429instance HasServer api context => HasServer (IsSecure :> api) context where
425 type ServerT (IsSecure :> api) m = IsSecure -> ServerT api m
430 type ServerT (IsSecure :> api) m = IsSecure -> ServerT api m
427− route Proxy context subserver = WithRequest $ \req ->
432+ route Proxy context subserver =
428− route (Proxy :: Proxy api) context (passToServer subserver $ secure req)
433+ route (Proxy :: Proxy api) context (passToServer subserver secure)
430 where secure req = if isSecure req then Secure else NotSecure
435 where secure req = if isSecure req then Secure else NotSecure
432instance HasServer api context => HasServer (Vault :> api) context where
437instance HasServer api context => HasServer (Vault :> api) context where
433 type ServerT (Vault :> api) m = Vault -> ServerT api m
438 type ServerT (Vault :> api) m = Vault -> ServerT api m
435− route Proxy context subserver = WithRequest $ \req ->
440+ route Proxy context subserver =
436− route (Proxy :: Proxy api) context (passToServer subserver $ vault req)
441+ route (Proxy :: Proxy api) context (passToServer subserver vault)
438instance HasServer api context => HasServer (HttpVersion :> api) context where
443instance HasServer api context => HasServer (HttpVersion :> api) context where
439 type ServerT (HttpVersion :> api) m = HttpVersion -> ServerT api m
444 type ServerT (HttpVersion :> api) m = HttpVersion -> ServerT api m
441− route Proxy context subserver = WithRequest $ \req ->
446+ route Proxy context subserver =
442− route (Proxy :: Proxy api) context (passToServer subserver $ httpVersion req)
447+ route (Proxy :: Proxy api) context (passToServer subserver httpVersion)
444-- | Basic Authentication
449-- | Basic Authentication
445instance ( KnownSymbol realm
450instance ( KnownSymbol realm
@@ -450,12 +455,12 @@ instance ( KnownSymbol realm
451 type ServerT (BasicAuth realm usr :> api) m = usr -> ServerT api m
456 type ServerT (BasicAuth realm usr :> api) m = usr -> ServerT api m
453− route Proxy context subserver = WithRequest $ \ request ->
458+ route Proxy context subserver =
454− route (Proxy :: Proxy api) context (subserver `addAuthCheck` authCheck request)
459+ route (Proxy :: Proxy api) context (subserver `addAuthCheck` authCheck)
456 realm = BC8.pack $ symbolVal (Proxy :: Proxy realm)
461 realm = BC8.pack $ symbolVal (Proxy :: Proxy realm)
457 basicAuthContext = getContextEntry context
462 basicAuthContext = getContextEntry context
458− authCheck req = runBasicAuth req realm basicAuthContext
463+ authCheck = withRequest $ \ req -> runBasicAuth req realm basicAuthContext
460-- * helpers
465-- * helpers