@@ -10,6 +10,7 @@
10{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE PolyKinds #-}
11{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE RankNTypes #-}
12{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE ScopedTypeVariables #-}
13+{-# LANGUAGE TupleSections #-}
13{-# LANGUAGE TypeFamilies #-}
14{-# LANGUAGE TypeFamilies #-}
14{-# LANGUAGE TypeOperators #-}
15{-# LANGUAGE TypeOperators #-}
@@ -67,8 +68,8 @@ import Servant.API ((:<|>) (..), (:>), BasicAuth, Capt
67 WithNamedContext,
68 WithNamedContext,
68 Description, Summary,
69 Description, Summary,
69 Accept(..),
70 Accept(..),
70− Framing(..), Stream,
71+ FramingRender(..), Stream,
71− StreamGenerator(..),
72+ StreamGenerator(..), ToStreamGenerator(..),
72 BoundaryStrategy(..))
73 BoundaryStrategy(..))
73import Servant.API.ContentTypes (AcceptHeader (..),
74import Servant.API.ContentTypes (AcceptHeader (..),
74 AllCTRender (..),
75 AllCTRender (..),
@@ -287,40 +288,68 @@ instance OVERLAPPING_
287 status = toEnum . fromInteger $ natVal (Proxy :: Proxy status)
288 status = toEnum . fromInteger $ natVal (Proxy :: Proxy status)
291+instance OVERLAPPABLE_
290−instance ( MimeRender ctype a, ReflectMethod method, Framing framing ctype
292+ ( MimeRender ctype a, ReflectMethod method,
293+ FramingRender framing ctype, ToStreamGenerator f a
294+ ) => HasServer (Stream method framing ctype (f a)) context where
296+ type ServerT (Stream method framing ctype (f a)) m = m (f a)
297+ hoistServerWithContext _ _ nt s = nt s
299+ route Proxy _ = streamRouter ([],) method (Proxy :: Proxy framing) (Proxy :: Proxy ctype)
300+ where method = reflectMethod (Proxy :: Proxy method)
302+instance OVERLAPPING_
303+ ( MimeRender ctype a, ReflectMethod method,
304+ FramingRender framing ctype, ToStreamGenerator f a,
305+ GetHeaders (Headers h (f a))
291− ) => HasServer (Stream method framing ctype a) context where
306+ ) => HasServer (Stream method framing ctype (Headers h (f a))) context where
293− type ServerT (Stream method framing ctype a) m = m (StreamGenerator a)
308+ type ServerT (Stream method framing ctype (Headers h (f a))) m = m (Headers h (f a))
294 hoistServerWithContext _ _ nt s = nt s
309 hoistServerWithContext _ _ nt s = nt s
311+ route Proxy _ = streamRouter (\x -> (getHeaders x, getResponse x)) method (Proxy :: Proxy framing) (Proxy :: Proxy ctype)
312+ where method = reflectMethod (Proxy :: Proxy method)
315+streamRouter :: (MimeRender ctype a, FramingRender framing ctype, ToStreamGenerator f a) =>
316+ (b -> ([(HeaderName, B.ByteString)], f a))
320+ -> Delayed env (Handler b)
296− route Proxy _ action = leafRouter $ \env request respond ->
322+streamRouter splitHeaders method framingproxy ctypeproxy action = leafRouter $ \env request respond ->
297 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
323 let accH = fromMaybe ct_wildcard $ lookup hAccept $ requestHeaders request
298− cmediatype = NHM.matchAccept [contentType (Proxy :: Proxy ctype)] accH
324+ cmediatype = NHM.matchAccept [contentType ctypeproxy] accH
299 accCheck = when (isNothing cmediatype) $ delayedFail err406
325 accCheck = when (isNothing cmediatype) $ delayedFail err406
300 contentHeader = (hContentType, NHM.renderHeader . maybeToList $ cmediatype)
326 contentHeader = (hContentType, NHM.renderHeader . maybeToList $ cmediatype)
301 in runAction (action `addMethodCheck` methodCheck method request
327 in runAction (action `addMethodCheck` methodCheck method request
302 `addAcceptCheck` accCheck
328 `addAcceptCheck` accCheck
303− ) env request respond $ \ (StreamGenerator k) ->
329+ ) env request respond $ \ output ->
330+ let (headers, fa) = splitHeaders output
331+ k = getStreamGenerator . toStreamGenerator $ fa in
304− Route $ responseStream status200 [contentHeader] $ \write flush -> do
332+ Route $ responseStream status200 (contentHeader : headers) $ \write flush -> do
305− write . BB.lazyByteString . header (Proxy :: Proxy framing) $ (Proxy :: Proxy ctype)
333+ write . BB.lazyByteString $ header framingproxy ctypeproxy
306− case boundary (Proxy :: Proxy framing) (Proxy :: Proxy ctype) of
334+ case boundary framingproxy ctypeproxy of
307 BoundaryStrategyBracket f ->
335 BoundaryStrategyBracket f ->
308− let go x = let bs = mimeRender (Proxy :: Proxy ctype) $ x
336+ let go x = let bs = mimeRender ctypeproxy $ x
309 (before, after) = f bs
337 (before, after) = f bs
310 in write ( BB.lazyByteString before
338 in write ( BB.lazyByteString before
311 <> BB.lazyByteString bs
339 <> BB.lazyByteString bs
312− <> BB.lazyByteString after)
340+ <> BB.lazyByteString after) >> flush
313 in k go go
341 in k go go
314 BoundaryStrategyIntersperse sep -> k
342 BoundaryStrategyIntersperse sep -> k
315 (\x -> do
343 (\x -> do
316− write . BB.lazyByteString . mimeRender (Proxy :: Proxy ctype) $ x
344+ write . BB.lazyByteString . mimeRender ctypeproxy $ x
318 (\x -> do
346 (\x -> do
319− write . (BB.lazyByteString sep <>) . BB.lazyByteString . mimeRender (Proxy :: Proxy ctype) $ x
347+ write . (BB.lazyByteString sep <>) . BB.lazyByteString . mimeRender ctypeproxy $ x
349+ BoundaryStrategyGeneral f ->
350+ let go = (>> flush) . write . BB.lazyByteString . f . mimeRender ctypeproxy
321− write . BB.lazyByteString . terminate (Proxy :: Proxy framing) $ (Proxy :: Proxy ctype)
352+ write . BB.lazyByteString $ terminate framingproxy ctypeproxy
322− where method = reflectMethod (Proxy :: Proxy method)
325-- | If you use 'Header' in one of the endpoints for your API,
354-- | If you use 'Header' in one of the endpoints for your API,
326-- this automatically requires your server-side handler to be a function
355-- this automatically requires your server-side handler to be a function