on master help sign in
Enumerator returns Either; fromHandle/File
edf1eabMichael Snoyman
Network/Wai.hs+3−1
@@ -235,7 +235,9 @@ statusMessage Status405 = B8.pack "Method Not Allowed"
235statusMessage Status500 = B8.pack "Internal Server Error"
235statusMessage Status500 = B8.pack "Internal Server Error"
236statusMessage (Status _ m) = m
236statusMessage (Status _ m) = m
237
237
238−type Enumerator a = (a -> B.ByteString -> IO (Either a a)) -> a -> IO a
238+type Enumerator a = (a -> B.ByteString -> IO (Either a a))
239+ -> a
240+ -> IO (Either a a)
239
241
240data Request = Request
242data Request = Request
241 { requestMethod :: Method
243 { requestMethod :: Method
Network/Wai/Enumerator.hs+31−3
@@ -6,12 +6,18 @@ module Network.Wai.Enumerator
6 , fromLBS'
6 , fromLBS'
7 -- * Source
7 -- * Source
8 , toSource
8 , toSource
9+ -- * Handle
10+ , fromHandle
11+ -- * FilePath
12+ , fromFile
13+ , fromEitherFile
9 ) where
14 ) where
10
15
11import Network.Wai (Enumerator)
16import Network.Wai (Enumerator)
12import qualified Data.ByteString.Lazy as L
17import qualified Data.ByteString.Lazy as L
13import qualified Data.ByteString as B
18import qualified Data.ByteString as B
14import System.IO.Unsafe (unsafeInterleaveIO)
19import System.IO.Unsafe (unsafeInterleaveIO)
20+import System.IO (withBinaryFile, IOMode (ReadMode), Handle, hIsEOF)
15
21
16-- | This uses 'unsafeInterleaveIO' to lazily read from an enumerator. All
22-- | This uses 'unsafeInterleaveIO' to lazily read from an enumerator. All
17-- normal lazy I/O warnings apply.
23-- normal lazy I/O warnings apply.
@@ -27,11 +33,11 @@ toLBS e = L.fromChunks `fmap` helper where
27
33
28fromLBS :: L.ByteString -> Enumerator a
34fromLBS :: L.ByteString -> Enumerator a
29fromLBS lbs iter a0 = helper a0 $ L.toChunks lbs where
35fromLBS lbs iter a0 = helper a0 $ L.toChunks lbs where
30− helper a [] = return a
36+ helper a [] = return $ Right a
31 helper a (x:xs) = do
37 helper a (x:xs) = do
32 ea <- iter a x
38 ea <- iter a x
33 case ea of
39 case ea of
34− Left a' -> return a'
40+ Left a' -> return $ Left a'
35 Right a' -> helper a' xs
41 Right a' -> helper a' xs
36
42
37fromLBS' :: IO L.ByteString -> Enumerator a
43fromLBS' :: IO L.ByteString -> Enumerator a
@@ -41,4 +47,26 @@ fromLBS' lbs' iter a0 = lbs' >>= \lbs -> fromLBS lbs iter a0
41-- Each time you call it, it returns the next chunk of data if available, or
47-- Each time you call it, it returns the next chunk of data if available, or
42-- 'Nothing' if the data has been completely consumed.
48-- 'Nothing' if the data has been completely consumed.
43toSource :: Enumerator (Maybe B.ByteString) -> IO (Maybe B.ByteString)
49toSource :: Enumerator (Maybe B.ByteString) -> IO (Maybe B.ByteString)
44−toSource e = e (const $ return . Left . Just) Nothing
50+toSource e = fmap (either id id) $ e (const $ return . Left . Just) Nothing
51+
52+chunkSize :: Int
53+chunkSize = 1024 -- FIXME
54+
55+fromHandle :: Handle -> Enumerator a
56+fromHandle h iter a = do
57+ eof <- hIsEOF h
58+ if eof
59+ then return $ Right a
60+ else do
61+ bs <- B.hGet h chunkSize
62+ ea' <- iter a bs
63+ case ea' of
64+ Left a' -> return $ Left a'
65+ Right a' -> fromHandle h iter a'
66+
67+fromFile :: FilePath -> Enumerator a
68+fromFile fp iter a0 = withBinaryFile fp ReadMode $ \h -> fromHandle h iter a0
69+
70+fromEitherFile :: Either FilePath (Enumerator a) -> Enumerator a
71+fromEitherFile (Left fp) = fromFile fp
72+fromEitherFile (Right e) = e
Network/Wai/Handler/SimpleServer.hs+2−2
@@ -136,7 +136,7 @@ parseRequest port lines' handle remoteHost' = do
136
136
137requestBodyHandle :: Handle -> MVar Int -> Enumerator a
137requestBodyHandle :: 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, Right a)
140 helper a len = do
140 helper a len = do
141 let maxChunkSize = 1024
141 let maxChunkSize = 1024
142 bs <- BS.hGet h $ min len maxChunkSize
142 bs <- BS.hGet h $ min len maxChunkSize
@@ -144,7 +144,7 @@ requestBodyHandle h mlen iter accum = modifyMVar mlen (helper accum) where
144 putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
144 putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
145 ea' <- iter a bs
145 ea' <- iter a bs
146 case ea' of
146 case ea' of
147− Left a' -> return (newLen, a')
147+ Left a' -> return (newLen, Left a')
148 Right a' -> helper a' newLen
148 Right a' -> helper a' newLen
149
149
150parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>
150parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>