@@ -6,6 +6,9 @@
6module Network.Wai.Parse
6module Network.Wai.Parse
7 ( parseHttpAccept
7 ( parseHttpAccept
8 , parseRequestBody
8 , parseRequestBody
9+ , RequestBodyType (..)
9 , conduitRequestBody
12 , conduitRequestBody
10 , lbsBackEnd
13 , lbsBackEnd
11 , tempFileBackEnd
14 , tempFileBackEnd
@@ -146,29 +149,16 @@ data FileInfo c = FileInfo
146type Param = (S.ByteString, S.ByteString)
149type Param = (S.ByteString, S.ByteString)
147type File y = (S.ByteString, FileInfo y)
150type File y = (S.ByteString, FileInfo y)
149−parseRequestBody :: BackEnd y
152+data RequestBodyType = UrlEncoded | Multipart S.ByteString
151− -> C.Sink S.ByteString IO ([Param], [File y])
152−parseRequestBody s r = fmap partitionEithers $ conduitRequestBody s r C.=$ CL.consume
154−conduitRequestBody :: BackEnd y
154+getRequestBodyType :: Request -> Maybe RequestBodyType
155− -> Request
155+getRequestBodyType req = do
156− -> C.Conduit S.ByteString IO (Either Param (File y))
156+ ctype <- lookup "Content-Type" $ requestHeaders req
157−conduitRequestBody sink req = do
157+ if urlenc `S.isPrefixOf` ctype
158+ then Just UrlEncoded
158− case ctype of
159+ else case boundary ctype of
159− Nothing -> C.Conduit
160+ Just x -> Just $ Multipart x
160− { C.conduitPush = \bs -> return $ C.Finished (Just bs) []
161+ Nothing -> Nothing
161− , C.conduitClose = return []
163− Just Nothing -> C.sequenceSink () $ \() -> do -- url-encoded
164− -- NOTE: in general, url-encoded data will be in a single chunk.
165− -- Therefore, I'm optimizing for the usual case by sticking with
166− -- strict byte strings here.
168− return $ C.Emit () $ map Left $ H.parseSimpleQuery $ S.concat bs
169− Just (Just bound) -> -- multi-part
170− let bound'' = S8.pack "--" `S.append` bound
171− in parsePieces sink bound''
173 urlenc = S8.pack "application/x-www-form-urlencoded"
163 urlenc = S8.pack "application/x-www-form-urlencoded"
174 formBound = S8.pack "multipart/form-data;"
164 formBound = S8.pack "multipart/form-data;"
@@ -181,13 +171,31 @@ conduitRequestBody sink req = do
181 then Just $ S.drop (S.length bound') s'
171 then Just $ S.drop (S.length bound') s'
182 else Nothing
172 else Nothing
183 else Nothing
173 else Nothing
185− ctype' <- lookup "Content-Type" $ requestHeaders req
175+parseRequestBody :: BackEnd y
186− if urlenc `S.isPrefixOf` ctype'
176+ -> Request
187− then Just Nothing
177+ -> C.ResourceT IO ([Param], [File y])
188− else case boundary ctype' of
178+parseRequestBody s r =
189− Just x -> Just $ Just x
179+ case getRequestBodyType r of
190− Nothing -> Nothing
180+ Nothing -> return ([], [])
181+ Just rbt -> fmap partitionEithers $ requestBody r C.$$ conduitRequestBody s rbt C.=$ CL.consume
183+sinkRequestBody :: BackEnd y
185+ -> C.Sink S.ByteString IO ([Param], [File y])
186+sinkRequestBody s r = fmap partitionEithers $ conduitRequestBody s r C.=$ CL.consume
188+conduitRequestBody :: BackEnd y
190+ -> C.Conduit S.ByteString IO (Either Param (File y))
191+conduitRequestBody _ UrlEncoded = C.sequenceSink () $ \() -> do -- url-encoded
192+ -- NOTE: in general, url-encoded data will be in a single chunk.
193+ -- Therefore, I'm optimizing for the usual case by sticking with
194+ -- strict byte strings here.
196+ return $ C.Emit () $ map Left $ H.parseSimpleQuery $ S.concat bs
197+conduitRequestBody backend (Multipart bound) =
198+ parsePieces backend $ S8.pack "--" `S.append` bound
192takeLine :: C.Sink S.ByteString IO (Maybe S.ByteString)
200takeLine :: C.Sink S.ByteString IO (Maybe S.ByteString)
193takeLine =
201takeLine =