on master help sign in
Added Network.Wai.Enumerator and lazy-test
b8ba4fdMichael Snoyman
Network/Wai/Enumerator.hsnew file+44
@@ -0,0 +1,44 @@
1+-- | A collection of utility functions for dealing with 'Enumerator's.
2+module Network.Wai.Enumerator
3+ ( -- * Lazy byte strings
4+ toLBS
5+ , fromLBS
6+ , fromLBS'
7+ -- * Source
8+ , toSource
9+ ) where
10+
11+import Network.Wai (Enumerator)
12+import qualified Data.ByteString.Lazy as L
13+import qualified Data.ByteString as B
14+import System.IO.Unsafe (unsafeInterleaveIO)
15+
16+-- | This uses 'unsafeInterleaveIO' to lazily read from an enumerator. All
17+-- normal lazy I/O warnings apply.
18+toLBS :: Enumerator (Maybe B.ByteString) -> IO L.ByteString
19+toLBS e = L.fromChunks `fmap` helper where
20+ helper = unsafeInterleaveIO $ do
21+ x <- toSource e
22+ case x of
23+ Nothing -> return []
24+ Just x' -> do
25+ xs <- helper
26+ return $ x' : xs
27+
28+fromLBS :: L.ByteString -> Enumerator a
29+fromLBS lbs iter a0 = helper a0 $ L.toChunks lbs where
30+ helper a [] = return a
31+ helper a (x:xs) = do
32+ ea <- iter a x
33+ case ea of
34+ Left a' -> return a'
35+ Right a' -> helper a' xs
36+
37+fromLBS' :: IO L.ByteString -> Enumerator a
38+fromLBS' lbs' iter a0 = lbs' >>= \lbs -> fromLBS lbs iter a0
39+
40+-- | A source is a more standard way of accessing data from an 'Enumerator'.
41+-- Each time you call it, it returns the next chunk of data if available, or
42+-- 'Nothing' if the data has been completely consumed.
43+toSource :: Enumerator (Maybe B.ByteString) -> IO (Maybe B.ByteString)
44+toSource e = e (const $ return . Left . Just) Nothing
Network/Wai/Handler/SimpleServer.hs+7−2
@@ -138,8 +138,10 @@ requestBodyHandle :: Handle -> MVar Int -> Enumerator a
138requestBodyHandle h mlen iter accum = modifyMVar mlen (helper accum) where
138requestBodyHandle h mlen iter accum = modifyMVar mlen (helper accum) where
139 helper a 0 = return (0, a)
139 helper a 0 = return (0, a)
140 helper a len = do
140 helper a len = do
141+ let maxChunkSize = 1024
141− bs <- BS.hGet h len
142+ bs <- BS.hGet h $ min len maxChunkSize
142 let newLen = len - BS.length bs
143 let newLen = len - BS.length bs
144+ putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
143 ea' <- iter a bs
145 ea' <- iter a bs
144 case ea' of
146 case ea' of
145 Left a' -> return (newLen, a')
147 Left a' -> return (newLen, a')
@@ -170,7 +172,10 @@ sendResponse h res = do
170 Left fp -> unsafeSendFile h fp
172 Left fp -> unsafeSendFile h fp
171 Right enum -> enum myPut h >> return ()
173 Right enum -> enum myPut h >> return ()
172 where
174 where
175+ myPut _ bs = do
176+ putStrLn $ "sending a chunk of size " ++ show (BS.length bs)
177+ BS.hPut h bs
173− myPut _ bs = BS.hPut h bs >> return (Right h)
178+ return (Right h)
174 putHeader (x, y) = do
179 putHeader (x, y) = do
175 BS.hPut h $ responseHeaderToBS x
180 BS.hPut h $ responseHeaderToBS x
176 BS.hPut h $ SL.pack ": "
181 BS.hPut h $ SL.pack ": "
lazy-test.hsnew file+30
@@ -0,0 +1,30 @@
1+{-# LANGUAGE Rank2Types #-}
2+import Network.Wai
3+import Network.Wai.Enumerator
4+import Network.Wai.Handler.SimpleServer
5+import qualified Data.ByteString.Char8 as B8
6+
7+main :: IO ()
8+main = putStrLn "http://localhost:3000/" >> run 3000 app
9+
10+app :: Application
11+app req = case B8.unpack $ pathInfo req of
12+ "/post/" -> postResponse $ requestBody req
13+ _ -> indexResponse
14+
15+indexResponse :: IO Response
16+indexResponse = return Response
17+ { status = Status200
18+ , headers = [(ContentType, B8.pack "text/html")]
19+ , body = index
20+ }
21+
22+postResponse :: (forall a. Enumerator a) -> IO Response
23+postResponse rb = return Response
24+ { status = Status200
25+ , headers = [(ContentType, B8.pack "text/plain")]
26+ , body = Right $ fromLBS' $ toLBS rb
27+ }
28+
29+index :: Either FilePath a
30+index = Left "index.html"
wai.cabal+1
@@ -16,4 +16,5 @@ Library
16 Build-Depends: base >= 3 && < 5,
16 Build-Depends: base >= 3 && < 5,
17 bytestring >= 0.9 && < 0.10
17 bytestring >= 0.9 && < 0.10
18 Exposed-modules: Network.Wai
18 Exposed-modules: Network.Wai
19+ Network.Wai.Enumerator
19 ghc-options: -Wall
20 ghc-options: -Wall