on master help sign in
Simpler definition of Source
aab9bc3Snoyman
Network/Wai.hs+6−11
@@ -311,19 +311,14 @@ statusMessage Status405 = B8.pack "Method Not Allowed"
311statusMessage Status500 = B8.pack "Internal Server Error"
311statusMessage Status500 = B8.pack "Internal Server Error"
312statusMessage (Status _ m) = m
312statusMessage (Status _ m) = m
313
313
314−-- | This is a source for 'B.ByteString's. It is composed of two pieces: a
314+-- | This is a source for 'B.ByteString's. It is a function (wrapped in a
315−-- state variable, and a function to produce the output. The type of the state
315+-- newtype) that will return Nothing if the data has been completely consumed,
316−-- variable is completely unknown to the user; some examples might be an 'Int'
316+-- or return the next 'B.ByteString' from the source along with a new 'Source'
317−-- for the remaining length of the content, or a list of 'B.ByteString's from
317+-- to continue reading from.
318−-- which to generate content.
319--
318--
320−-- The function accepts that state variable as its first argument. If input has
321−-- been fully consumed, it returns 'Nothing'; otherwise, it returns the next
322−-- piece of data and the next state.
323−--
324−-- Be certain not to reuse a state variable! It might work fine with some
319+-- Be certain not to reuse a 'Source'! It might work fine with some
325-- implementations of 'Source', while causing bugs with others.
320-- implementations of 'Source', while causing bugs with others.
326−data Source = forall a. Source a (a -> IO (Maybe (B.ByteString, a)))
321+newtype Source = Source { runSource :: IO (Maybe (B.ByteString, Source)) }
327
322
328-- | An enumerator is a data producer. It takes two arguments: a function to
323-- | An enumerator is a data producer. It takes two arguments: a function to
329-- enumerate over (the iteratee) and an accumulating parameter. As the
324-- enumerate over (the iteratee) and an accumulating parameter. As the
Network/Wai/Enumerator.hs+5−5
@@ -69,7 +69,7 @@ toSource :: Enumerator -> IO Source
69toSource (Enumerator e) = do
69toSource (Enumerator e) = do
70 buffer <- newEmptyMVar
70 buffer <- newEmptyMVar
71 _ <- forkIO $ e (helper buffer) () >> putMVar buffer Nothing
71 _ <- forkIO $ e (helper buffer) () >> putMVar buffer Nothing
72− return $ Source () $ source buffer
72+ return $ source buffer
73 where
73 where
74 helper :: MVar (Maybe B.ByteString)
74 helper :: MVar (Maybe B.ByteString)
75 -> ()
75 -> ()
@@ -78,9 +78,9 @@ toSource (Enumerator e) = do
78 helper buffer _ bs = do
78 helper buffer _ bs = do
79 putMVar buffer $ Just bs
79 putMVar buffer $ Just bs
80 return $ Right ()
80 return $ Right ()
81− source :: MVar (Maybe B.ByteString) -> ()
81+ source :: MVar (Maybe B.ByteString)
82− -> IO (Maybe (B.ByteString, ()))
82+ -> Source
83− source mmbs () = do
83+ source mmbs = Source $ do
84 mbs <- takeMVar mmbs
84 mbs <- takeMVar mmbs
85 case mbs of
85 case mbs of
86 Nothing -> do
86 Nothing -> do
@@ -88,7 +88,7 @@ toSource (Enumerator e) = do
88 -- again without causing a deadlock.
88 -- again without causing a deadlock.
89 putMVar mmbs Nothing
89 putMVar mmbs Nothing
90 return Nothing
90 return Nothing
91− Just bs -> return $ Just (bs, ())
91+ Just bs -> return $ Just (bs, source mmbs)
92
92
93-- | Read a chunk of data from the given 'Handle' at a time. We use
93-- | Read a chunk of data from the given 'Handle' at a time. We use
94-- 'defaultChunkSize' from the bytestring package to determine the largest
94-- 'defaultChunkSize' from the bytestring package to determine the largest
Network/Wai/Handler/SimpleServer.hs+5−5
@@ -128,19 +128,19 @@ parseRequest port lines' handle remoteHost' = do
128 , serverPort = port
128 , serverPort = port
129 , requestHeaders = heads
129 , requestHeaders = heads
130 , urlScheme = HTTP
130 , urlScheme = HTTP
131− , requestBody = Source len $ requestBodyHandle handle
131+ , requestBody = requestBodyHandle handle len
132 , errorHandler = System.IO.hPutStr System.IO.stderr
132 , errorHandler = System.IO.hPutStr System.IO.stderr
133 , remoteHost = B8.pack remoteHost'
133 , remoteHost = B8.pack remoteHost'
134 }
134 }
135
135
136−requestBodyHandle :: Handle -> Int -> IO (Maybe (B8.ByteString, Int))
136+requestBodyHandle :: Handle -> Int -> Source
137−requestBodyHandle _ 0 = return Nothing
137+requestBodyHandle _ 0 = Source $ return Nothing
138−requestBodyHandle h len = do
138+requestBodyHandle h len = Source $ do
139 let maxChunkSize = 1024
139 let maxChunkSize = 1024
140 bs <- BS.hGet h $ min len maxChunkSize
140 bs <- BS.hGet h $ min len maxChunkSize
141 let newLen = len - BS.length bs
141 let newLen = len - BS.length bs
142 putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
142 putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
143− return $ Just (bs, newLen)
143+ return $ Just (bs, requestBodyHandle h newLen)
144
144
145parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>
145parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>
146 s
146 s
Network/Wai/Source.hs+10−10
@@ -13,25 +13,25 @@ import System.IO.Unsafe (unsafeInterleaveIO)
13-- 'Enumerator' (which pushes the data to you). There should be no significant
13-- 'Enumerator' (which pushes the data to you). There should be no significant
14-- performance impact from its use, and it uses no unsafe functions.
14-- performance impact from its use, and it uses no unsafe functions.
15toEnumerator :: Source -> Enumerator
15toEnumerator :: Source -> Enumerator
16−toEnumerator (Source b0 source) = Enumerator $ helper b0 where
16+toEnumerator source0 = Enumerator $ helper source0 where
17− helper b iter a = do
17+ helper source iter a = do
18− next <- source b
18+ next <- runSource source
19 case next of
19 case next of
20 Nothing -> return $ Right a
20 Nothing -> return $ Right a
21− Just (bs, b') -> do
21+ Just (bs, source') -> do
22 res <- iter a bs
22 res <- iter a bs
23 case res of
23 case res of
24 Left a' -> return $ Left a'
24 Left a' -> return $ Left a'
25− Right a' -> helper b' iter a'
25+ Right a' -> helper source' iter a'
26
26
27-- | Uses lazy I\/O (via 'unsafeInterleaveIO') to provide a lazy interface to
27-- | Uses lazy I\/O (via 'unsafeInterleaveIO') to provide a lazy interface to
28-- the given 'Source'. Normal lazy I\/O warnings apply.
28-- the given 'Source'. Normal lazy I\/O warnings apply.
29toLBS :: Source -> IO L.ByteString
29toLBS :: Source -> IO L.ByteString
30−toLBS (Source b0 source) = L.fromChunks `fmap` helper b0 where
30+toLBS source0 = L.fromChunks `fmap` helper source0 where
31− helper b = unsafeInterleaveIO $ do
31+ helper source = unsafeInterleaveIO $ do
32− next <- source b
32+ next <- runSource source
33 case next of
33 case next of
34 Nothing -> return []
34 Nothing -> return []
35− Just (bs, b') -> do
35+ Just (bs, source') -> do
36− rest <- helper b'
36+ rest <- helper source'
37 return $ bs : rest
37 return $ bs : rest