-
Notifications
You must be signed in to change notification settings - Fork 260
/
IO.hs
50 lines (48 loc) · 2.32 KB
/
IO.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module Network.Wai.Handler.Warp.IO where
import Control.Exception (mask_)
import Data.ByteString.Builder (Builder)
import Data.ByteString.Builder.Extra (Next (Chunk, Done, More), runBuilder)
import Data.IORef (IORef, readIORef, writeIORef)
import Network.Wai.Handler.Warp.Buffer
import Network.Wai.Handler.Warp.Imports
import Network.Wai.Handler.Warp.Types
toBufIOWith
:: Int -> IORef WriteBuffer -> (ByteString -> IO ()) -> Builder -> IO Integer
toBufIOWith maxRspBufSize writeBufferRef io builder = do
writeBuffer <- readIORef writeBufferRef
loop writeBuffer firstWriter 0
where
firstWriter = runBuilder builder
loop writeBuffer writer bytesSent = do
let buf = bufBuffer writeBuffer
size = bufSize writeBuffer
(len, signal) <- writer buf size
bufferIO buf len io
let totalBytesSent = toInteger len + bytesSent
case signal of
Done -> return totalBytesSent
More minSize next
| size < minSize -> do
when (minSize > maxRspBufSize) $
error $
"Sending a Builder response required a buffer of size "
++ show minSize
++ " which is bigger than the specified maximum of "
++ show maxRspBufSize
++ "!"
-- The current WriteBuffer is too small to fit the next
-- batch of bytes from the Builder so we free it and
-- create a new bigger one. Freeing the current buffer,
-- creating a new one and writing it to the IORef need
-- to be performed atomically to prevent both double
-- frees and missed frees. So we mask async exceptions:
biggerWriteBuffer <- mask_ $ do
bufFree writeBuffer
biggerWriteBuffer <- createWriteBuffer minSize
writeIORef writeBufferRef biggerWriteBuffer
return biggerWriteBuffer
loop biggerWriteBuffer next totalBytesSent
| otherwise -> loop writeBuffer next totalBytesSent
Chunk bs next -> do
io bs
loop writeBuffer next totalBytesSent