@@ -10,9 +10,10 @@ module Network.Wai.Parse
1010 , getRequestBodyType
1111 , sinkRequestBody
1212 , conduitRequestBody
13− , lbsSink
14− , tempFileSink
15− , tempFileSinkOpts
13+ , BackEnd
14+ , lbsBackEnd
15+ , tempFileBackEnd
16+ , tempFileBackEndOpts
1617 , Param
1718 , File
1819 , FileInfo (..)
@@ -72,19 +73,21 @@ parseHttpAccept = map fst
7273 trimWhite = S.dropWhile (== 32) -- space
7374
7475-- | Store uploaded files in memory
75−lbsSink :: Monad m => Sink S.ByteString m L.ByteString
76−lbsSink = fmap L.fromChunks CL.consume
76+lbsBackEnd :: Monad m => ignored1 -> ignored2 -> Sink S.ByteString m L.ByteString
77+lbsBackEnd _ _ = fmap L.fromChunks CL.consume
7778
7879-- | Save uploaded files on disk as temporary files
79−tempFileSink :: MonadResource m => Sink S.ByteString m FilePath
80−tempFileSink = tempFileSinkOpts getTemporaryDirectory "webenc.buf"
80+tempFileBackEnd :: MonadResource m => ignored1 -> ignored2 -> Sink S.ByteString m FilePath
81+tempFileBackEnd = tempFileBackEndOpts getTemporaryDirectory "webenc.buf"
8182
8283-- | Same as 'tempFileSink', but use configurable temp folders and patterns.
83−tempFileSinkOpts :: MonadResource m
84− => IO FilePath -- ^ get temporary directory
85− -> String -- ^ filename pattern
86− -> Sink S.ByteString m FilePath
87−tempFileSinkOpts getTmpDir pattern = do
84+tempFileBackEndOpts :: MonadResource m
85+ => IO FilePath -- ^ get temporary directory
86+ -> String -- ^ filename pattern
87+ -> ignored1
88+ -> ignored2
89+ -> Sink S.ByteString m FilePath
90+tempFileBackEndOpts getTmpDir pattern _ _ = do
8891 (key, (fp, h)) <- lift $ allocate (do
8992 tempDir <- getTmpDir
9093 openBinaryTempFile tempDir pattern) (\(_, h) -> hClose h)
@@ -104,6 +107,12 @@ data FileInfo c = FileInfo
104107type Param = (S.ByteString, S.ByteString)
105108type File y = (S.ByteString, FileInfo y)
106109
110+-- | A file uploading backend. Takes the parameter name, file name, and content
111+-- type, and returns a `Sink` for storing the contents.
112+type BackEnd a = S.ByteString -- ^ parameter name
113+ -> FileInfo ()
114+ -> Sink S.ByteString (ResourceT IO) a
115+
107116data RequestBodyType = UrlEncoded | Multipart S.ByteString
108117
109118getRequestBodyType :: Request -> Maybe RequestBodyType
@@ -127,7 +136,7 @@ getRequestBodyType req = do
127136 else Nothing
128137 else Nothing
129138
130−parseRequestBody :: Sink S.ByteString (ResourceT IO) y
139+parseRequestBody :: BackEnd y
131140 -> Request
132141 -> ResourceT IO ([Param], [File y])
133142parseRequestBody s r =
@@ -135,12 +144,12 @@ parseRequestBody s r =
135144 Nothing -> return ([], [])
136145 Just rbt -> fmap partitionEithers $ requestBody r $$ conduitRequestBody s rbt =$ CL.consume
137146
138−sinkRequestBody :: Sink S.ByteString (ResourceT IO) y
147+sinkRequestBody :: BackEnd y
139148 -> RequestBodyType
140149 -> Sink S.ByteString (ResourceT IO) ([Param], [File y])
141150sinkRequestBody s r = fmap partitionEithers $ conduitRequestBody s r =$ CL.consume
142151
143−conduitRequestBody :: Sink S.ByteString (ResourceT IO) y
152+conduitRequestBody :: BackEnd y
144153 -> RequestBodyType
145154 -> Conduit S.ByteString (ResourceT IO) (Either Param (File y))
146155conduitRequestBody _ UrlEncoded = do
@@ -178,7 +187,7 @@ takeLines = do
178187 ls <- takeLines
179188 return $ l : ls
180189
181−parsePieces :: Sink S.ByteString (ResourceT IO) y
190+parsePieces :: BackEnd y
182191 -> S.ByteString
183192 -> Pipe S.ByteString S.ByteString (Either Param (File y)) u (ResourceT IO) ()
184193parsePieces sink bound =
@@ -198,10 +207,9 @@ parsePieces sink bound =
198207 case x of
199208 Just (mct, name, Just filename) -> do
200209 let ct = fromMaybe "application/octet-stream" mct
201− (wasFound, y) <- sinkTillBound' bound sink
202− let fi = FileInfo filename ct y
203− let y' = (name, fi)
204− yield $ Right y'
210+ fi0 = FileInfo filename ct ()
211+ (wasFound, y) <- sinkTillBound' bound name fi0 sink
212+ yield $ Right (name, fi0 { fileContent = y })
205213 when wasFound loop
206214 Just (_ct, name, Nothing) -> do
207215 let seed = id
@@ -253,9 +261,11 @@ findBound b bs = handleBreak $ Search.breakOn b bs
253261 | otherwise = True
254262
255263sinkTillBound' :: S.ByteString
256− -> Sink S.ByteString (ResourceT IO) y
264+ -> S.ByteString
265+ -> FileInfo ()
266+ -> BackEnd y
257267 -> Pipe S.ByteString S.ByteString o u (ResourceT IO) (Bool, y)
258−sinkTillBound' bound sink = conduitTillBound bound >+> withUpstream (sinkToPipe sink)
268+sinkTillBound' bound name fi sink = conduitTillBound bound >+> withUpstream (sinkToPipe $ sink name fi)
259269
260270conduitTillBound :: Monad m
261271 => S.ByteString -- bound