on master help sign in
Added enumerator buffer function.
1b2f9deMichael Snoyman
Network/Wai/Enumerator.hs+28−5
@@ -15,6 +15,8 @@ module Network.Wai.Enumerator
15 -- ** FilePath
15 -- ** FilePath
16 , fromFile
16 , fromFile
17 , fromEitherFile
17 , fromEitherFile
18+ -- * Filters
19+ , buffer
18 ) where
20 ) where
19
21
20import Network.Wai (Enumerator (..), Source (..))
22import Network.Wai (Enumerator (..), Source (..))
@@ -67,16 +69,16 @@ fromLBS' lbs' = Enumerator $ \iter a0 -> lbs' >>= \lbs ->
67-- deadlocked.
69-- deadlocked.
68toSource :: Enumerator -> IO Source
70toSource :: Enumerator -> IO Source
69toSource (Enumerator e) = do
71toSource (Enumerator e) = do
70− buffer <- newEmptyMVar
72+ buff <- newEmptyMVar
71− _ <- forkIO $ e (helper buffer) () >> putMVar buffer Nothing
73+ _ <- forkIO $ e (helper buff) () >> putMVar buff Nothing
72− return $ source buffer
74+ return $ source buff
73 where
75 where
74 helper :: MVar (Maybe B.ByteString)
76 helper :: MVar (Maybe B.ByteString)
75 -> ()
77 -> ()
76 -> B.ByteString
78 -> B.ByteString
77 -> IO (Either () ())
79 -> IO (Either () ())
78− helper buffer _ bs = do
80+ helper buff _ bs = do
79− putMVar buffer $ Just bs
81+ putMVar buff $ Just bs
80 return $ Right ()
82 return $ Right ()
81 source :: MVar (Maybe B.ByteString)
83 source :: MVar (Maybe B.ByteString)
82 -> Source
84 -> Source
@@ -115,3 +117,24 @@ fromFile fp = Enumerator $ \iter a0 -> withBinaryFile fp ReadMode $ \h ->
115-- be convenient for server implementations not optimizing file sending.
117-- be convenient for server implementations not optimizing file sending.
116fromEitherFile :: Either FilePath Enumerator -> Enumerator
118fromEitherFile :: Either FilePath Enumerator -> Enumerator
117fromEitherFile = either fromFile id
119fromEitherFile = either fromFile id
120+
121+-- | Buffer chunks until we have a chunk of 'defaultChunkSize', and then send
122+-- it.
123+buffer :: Enumerator -> Enumerator
124+buffer (Enumerator e) =
125+ Enumerator go
126+ where
127+ go iter seed = do
128+ res <- e (iter' iter) (B.empty, seed)
129+ case res of
130+ Left (_, seed') -> return $ Left seed'
131+ Right (buff, seed') -> iter seed' buff
132+ iter' iter (buff, seed) bs = do
133+ if B.length buff + B.length bs < defaultChunkSize
134+ then return $ Right (buff `B.append` bs, seed)
135+ else do
136+ let (x, y) = B.splitAt (defaultChunkSize - B.length buff) bs
137+ res <- iter seed $ buff `B.append` x
138+ case res of
139+ Left seed' -> return $ Left (y, seed') -- y is ignored
140+ Right seed' -> return $ Right (y, seed')
test.hs+2−1
@@ -1,5 +1,6 @@
1{-# LANGUAGE Rank2Types #-}
1{-# LANGUAGE Rank2Types #-}
2import Network.Wai
2import Network.Wai
3+import Network.Wai.Enumerator (buffer)
3import Network.Wai.Handler.SimpleServer
4import Network.Wai.Handler.SimpleServer
4import qualified Data.ByteString.Char8 as B8
5import qualified Data.ByteString.Char8 as B8
5import qualified Network.Wai.Source as Source
6import qualified Network.Wai.Source as Source
@@ -23,7 +24,7 @@ postResponse :: Enumerator -> IO Response
23postResponse rb = return Response
24postResponse rb = return Response
24 { status = Status200
25 { status = Status200
25 , responseHeaders = [(ContentType, B8.pack "text/plain")]
26 , responseHeaders = [(ContentType, B8.pack "text/plain")]
26− , responseBody = Right rb
27+ , responseBody = Right $ buffer rb
27 }
28 }
28
29
29index :: Either FilePath a
30index :: Either FilePath a
wai.cabal+1−1
@@ -1,5 +1,5 @@
1Name: wai
1Name: wai
2−Version: 0.0.0
2+Version: 0.0.1
3Synopsis: Web Application Interface.
3Synopsis: Web Application Interface.
4Description: Provides a common protocol for communication between web aplications and web servers.
4Description: Provides a common protocol for communication between web aplications and web servers.
5License: BSD3
5License: BSD3