on master help sign in
Replaced requestBody Enumerator with Source
commitb407d2aa65ac92fe192c72e60accb113d773f020 authorSnoyman <snoyman@snoytop-karmic.(none)> dateFri 26 Feb 2010, 10:01 (17 years ago) parentcc5ce73
6 files changed+50−17
Network/Wai.hs+5−1 Network/Wai/Handler/SimpleServer.hs+9−13 Network/Wai/Source.hs+30 lazy-test.hs+3−2 test.hs+2−1 wai.cabal+1
Network/Wai.hs+5−1
@@ -1,4 +1,5 @@
11{-# LANGUAGE Rank2Types #-}
2+{-# LANGUAGE ExistentialQuantification #-}
23{-|
34
45This module defines a generic web application interface. It is a common
@@ -56,6 +57,7 @@ module Network.Wai
5657 , statusCode
5758 , statusMessage
5859 -- * Enumerator
60+ , Source (..)
5961 , Enumerator (..)
6062 -- * WAI interface
6163 , Request (..)
@@ -308,6 +310,8 @@ statusMessage Status405 = B8.pack "Method Not Allowed"
308310statusMessage Status500 = B8.pack "Internal Server Error"
309311statusMessage (Status _ m) = m
310312
313+data Source = forall a. Source a (a -> IO (Maybe (B.ByteString, a)))
314+
311315-- | An enumerator is a data producer. It takes two arguments: a function to
312316-- enumerate over (the iteratee) and an accumulating parameter. As the
313317-- enumerator produces output, it calls the iteratee, thereby avoiding the need
@@ -363,7 +367,7 @@ data Request = Request
363367 , serverPort :: Int
364368 , requestHeaders :: [(RequestHeader, B.ByteString)]
365369 , urlScheme :: UrlScheme
366− , requestBody :: Enumerator
370+ , requestBody :: Source
367371 , errorHandler :: String -> IO ()
368372 -- | The client\'s host information.
369373 , remoteHost :: B.ByteString
Network/Wai/Handler/SimpleServer.hs+9−13
@@ -128,23 +128,19 @@ parseRequest port lines' handle remoteHost' = do
128128 , serverPort = port
129129 , requestHeaders = heads
130130 , urlScheme = HTTP
131− , requestBody = requestBodyHandle handle len
131+ , requestBody = Source len $ requestBodyHandle handle
132132 , errorHandler = System.IO.hPutStr System.IO.stderr
133133 , remoteHost = B8.pack remoteHost'
134134 }
135135
136−requestBodyHandle :: Handle -> Int -> Enumerator
137−requestBodyHandle h len0 = Enumerator $ helper len0 where
138− helper 0 _ a = return $ Right a
139− helper len iter a = do
140− let maxChunkSize = 1024
141− bs <- BS.hGet h $ min len maxChunkSize
142− let newLen = len - BS.length bs
143− putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
144− ea' <- iter a bs
145− case ea' of
146− Left a' -> return $ Left a'
147− Right a' -> helper newLen iter a'
136+requestBodyHandle :: Handle -> Int -> IO (Maybe (B8.ByteString, Int))
137+requestBodyHandle _ 0 = return Nothing
138+requestBodyHandle h len = do
139+ let maxChunkSize = 1024
140+ bs <- BS.hGet h $ min len maxChunkSize
141+ let newLen = len - BS.length bs
142+ putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
143+ return $ Just (bs, newLen)
148144
149145parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>
150146 s
Network/Wai/Source.hsnew file+30
@@ -0,0 +1,30 @@
1+module Network.Wai.Source
2+ ( toEnumerator
3+ , toLBS
4+ ) where
5+
6+import Network.Wai
7+import qualified Data.ByteString.Lazy as L
8+import System.IO.Unsafe (unsafeInterleaveIO)
9+
10+toEnumerator :: Source -> Enumerator
11+toEnumerator (Source b0 source) = Enumerator $ helper b0 where
12+ helper b iter a = do
13+ next <- source b
14+ case next of
15+ Nothing -> return $ Right a
16+ Just (bs, b') -> do
17+ res <- iter a bs
18+ case res of
19+ Left a' -> return $ Left a'
20+ Right a' -> helper b' iter a'
21+
22+toLBS :: Source -> IO L.ByteString
23+toLBS (Source b0 source) = L.fromChunks `fmap` helper b0 where
24+ helper b = unsafeInterleaveIO $ do
25+ next <- source b
26+ case next of
27+ Nothing -> return []
28+ Just (bs, b') -> do
29+ rest <- helper b'
30+ return $ bs : rest
lazy-test.hs+3−2
@@ -1,6 +1,7 @@
11{-# LANGUAGE Rank2Types #-}
22import Network.Wai
33import Network.Wai.Enumerator
4+import qualified Network.Wai.Source as Source
45import Network.Wai.Handler.SimpleServer
56import qualified Data.ByteString.Char8 as B8
67
@@ -19,11 +20,11 @@ indexResponse = return Response
1920 , responseBody = index
2021 }
2122
22−postResponse :: Enumerator -> IO Response
23+postResponse :: Source -> IO Response
2324postResponse rb = return Response
2425 { status = Status200
2526 , responseHeaders = [(ContentType, B8.pack "text/plain")]
26− , responseBody = Right $ fromLBS' $ toLBS rb
27+ , responseBody = Right $ fromLBS' $ Source.toLBS rb
2728 }
2829
2930index :: Either FilePath a
test.hs+2−1
@@ -2,13 +2,14 @@
22import Network.Wai
33import Network.Wai.Handler.SimpleServer
44import qualified Data.ByteString.Char8 as B8
5+import qualified Network.Wai.Source as Source
56
67main :: IO ()
78main = putStrLn "http://localhost:3000/" >> run 3000 app
89
910app :: Application
1011app req = case B8.unpack $ pathInfo req of
11− "/post/" -> postResponse $ requestBody req
12+ "/post/" -> postResponse $ Source.toEnumerator $ requestBody req
1213 _ -> indexResponse
1314
1415indexResponse :: IO Response
wai.cabal+1
@@ -17,4 +17,5 @@ Library
1717 bytestring >= 0.9 && < 0.10
1818 Exposed-modules: Network.Wai
1919 Network.Wai.Enumerator
20+ Network.Wai.Source
2021 ghc-options: -Wall