@@ -32,9 +32,8 @@ import Data.Function (on)
32import System.Directory (removeFile, getTemporaryDirectory)
32import System.Directory (removeFile, getTemporaryDirectory)
33import System.IO (hClose, openBinaryTempFile, Handle)
33import System.IO (hClose, openBinaryTempFile, Handle)
34import Network.Wai
34import Network.Wai
35−import Data.Enumerator (Iteratee, yield)
36−import qualified Data.Enumerator as E
35+import qualified Data.Conduit as C
37−import qualified Data.Enumerator.List as EL
36+import qualified Data.Conduit.List as CL
38import Control.Monad.IO.Class (liftIO)
37import Control.Monad.IO.Class (liftIO)
39import qualified Network.HTTP.Types as H
38import qualified Network.HTTP.Types as H
@@ -129,7 +128,7 @@ type File y = (S.ByteString, FileInfo y)
130parseRequestBody :: Sink x y
129parseRequestBody :: Sink x y
131 -> Request
130 -> Request
132− -> Iteratee S.ByteString IO ([Param], [File y])
131+ -> C.Sink S.ByteString IO ([Param], [File y])
133parseRequestBody sink req = do
132parseRequestBody sink req = do
134 case ctype of
133 case ctype of
135 Nothing -> return ([], [])
134 Nothing -> return ([], [])
@@ -137,7 +136,7 @@ parseRequestBody sink req = do
137 -- NOTE: in general, url-encoded data will be in a single chunk.
136 -- NOTE: in general, url-encoded data will be in a single chunk.
138 -- Therefore, I'm optimizing for the usual case by sticking with
137 -- Therefore, I'm optimizing for the usual case by sticking with
139 -- strict byte strings here.
138 -- strict byte strings here.
140− bs <- EL.consume
139+ bs <- CL.consume
141 return (H.parseSimpleQuery $ S.concat bs, [])
140 return (H.parseSimpleQuery $ S.concat bs, [])
142 Just (Just bound) -> -- multi-part
141 Just (Just bound) -> -- multi-part
143 let bound'' = S8.pack "--" `S.append` bound
142 let bound'' = S8.pack "--" `S.append` bound
@@ -162,24 +161,20 @@ parseRequestBody sink req = do
162 Just x -> Just $ Just x
161 Just x -> Just $ Just x
163 Nothing -> Nothing
162 Nothing -> Nothing
165−takeLine :: Iteratee S.ByteString IO (Maybe S.ByteString)
164+takeLine :: C.Sink S.ByteString IO (Maybe S.ByteString)
166−takeLine = do
165+takeLine =
167− mbs <- EL.head
166+ C.sinkState id push close
168− case mbs of
167+ where
169− Nothing -> return Nothing
168+ close _ = return Nothing
170− Just bs ->
169+ push front bs = do
171− let (x, y) = S.break (== 10) bs -- LF
170+ let (x, y) = S.break (== 10) $ front bs -- LF
172− in if S.null y
171+ in if S.null y
173− then do
172+ then return (S.append x, C.Processing)
176− Nothing -> return $ Just $ killCR x
177− Just x'' -> return $ Just $ killCR $ S.append x x''
179− E.yield () $ E.Chunks [S.drop 1 y]
174+ let lo = if S.length y > 1 then Just (S.drop 1 y) else Nothing
180− return $ Just $ killCR x
175+ return (error "takeLine", C.Done lo $ Just $ killCR x)
182−takeLines :: Iteratee S.ByteString IO [S.ByteString]
177+takeLines :: C.Sink S.ByteString IO [S.ByteString]
183takeLines = do
178takeLines = do
184 res <- takeLine
179 res <- takeLine
185 case res of
180 case res of
@@ -191,7 +186,7 @@ takeLines = do
191 return $ l : ls
186 return $ l : ls
193parsePieces :: Sink x y -> S.ByteString
188parsePieces :: Sink x y -> S.ByteString
194− -> Iteratee S.ByteString IO ([Param], [File y])
189+ -> C.Sink S.ByteString IO ([Param], [File y])
195parsePieces sink bound = do
190parsePieces sink bound = do
196 _boundLine <- takeLine
191 _boundLine <- takeLine
197 res' <- takeLines
192 res' <- takeLines
@@ -271,56 +266,32 @@ findBound b bs = go [0..S.length bs - 1]
271sinkTillBound :: S.ByteString
266sinkTillBound :: S.ByteString
272 -> (x -> S.ByteString -> IO x)
267 -> (x -> S.ByteString -> IO x)
274− -> Iteratee S.ByteString IO (x, Bool)
269+ -> C.Sink S.ByteString IO (x, Bool)
275−sinkTillBound bound iter seed = do
270+sinkTillBound bound iter seed0 = C.sinkState
276− mbs <- EL.head
271+ (id, seed0)
277− case mbs of
272+ push
278− Nothing -> return (seed, False)
273+ close
281− go bs =
275+ close (front, seed) = do
276+ seed' <- liftIO $ iter seed $ front S.empty
277+ return (seed', False)
278+ push (front, seed) bs' = do
282 case findBound bound bs of
280 case findBound bound bs of
283 FoundBound before after -> do
281 FoundBound before after -> do
284 let before' = killCRLF before
282 let before' = killCRLF before
285 seed' <- liftIO $ iter seed before'
283 seed' <- liftIO $ iter seed before'
286− yield () $ E.Chunks [after]
284+ return (undefined, C.Done (Just after) (seed', True))
287− return (seed', True)
292− seed' <- liftIO $ iter seed bs
293− return (seed', False)
295− let bs' = bs `S.append` bs2
296− yield () $ E.Chunks [bs']
297− sinkTillBound bound iter seed
298 NoBound -> do
285 NoBound -> do
299− mbs <- EL.head
286+ -- don't emit newlines, in case it's part of a bound
300− case mbs of
287+ let (toEmit, front') =
302− seed' <- liftIO $ iter seed bs
303− sinkTillBound bound iter seed'
305− -- this funny bit is to catch when there's a
306− -- newline at the end of the previous chunk
308− if not (S8.null bs) && S8.last bs `elem` "\n\r"
288+ if not (S8.null bs) && S8.last bs `elem` "\r\n"
311− S.splitAt (S.length bs - 2) bs
289+ then let (x, y) = S.splitAt (S.length bs - 2) bs
312− seed' <- liftIO $ iter seed front
313− return (seed', back `S.append` bs')
290+ in (x, S.append y)
314− else do
291+ else (bs, id)
315− seed' <- liftIO $ iter seed bs
292+ seed' <- liftIO $ iter seed toEmit
316− return (seed', bs')
293+ return ((front', seed'), C.Processing)
317− yield () $ E.Chunks [bs'']
294+ PartialBound -> return ((S.append bs, seed), C.Processing)
318− sinkTillBound bound iter seed'
322− Just (bs', src') -> do
325parseAttrs :: S.ByteString -> [(S.ByteString, S.ByteString)]
296parseAttrs :: S.ByteString -> [(S.ByteString, S.ByteString)]
326parseAttrs = map go . S.split 59 -- semicolon
297parseAttrs = map go . S.split 59 -- semicolon