@@ -34,7 +34,7 @@ import qualified Data.Conduit as C
3434import qualified Data.Conduit.List as CL
3535
3636import System.Console.ANSI
37−import Data.IORef
37+import Data.IORef.Lifted
3838import System.IO.Unsafe
3939
4040import Data.Default (Default (def))
@@ -198,7 +198,24 @@ detailedMiddleware' cb getAddColor app req = do
198198 body <- requestBody req C.$$ CL.consume
199199 -- logging the body here consumes it, so fill it back up
200200 -- obviously not efficient, but this is the development logger
201− let req' = req { requestBody = CL.sourceList body }
201+ --
202+ -- Note: previously, we simply used CL.sourceList. However,
203+ -- that meant that you could read the request body in twice.
204+ -- While that in itself is not a problem, the issue is that,
205+ -- in production, you wouldn't be able to do this, and
206+ -- therefore some bugs wouldn't show up during testing. This
207+ -- implementation ensures that each chunk is only returned
208+ -- once.
209+ ichunks <- newIORef body
210+ let rbody = do
211+ chunks <- readIORef ichunks
212+ case chunks of
213+ [] -> return ()
214+ x:xs -> do
215+ writeIORef ichunks xs
216+ C.yield x
217+ rbody
218+ let req' = req { requestBody = rbody }
202219 return (req', body)
203220 _ -> return (req, [])
204221