on master help sign in
packing frames.
commit45170d1f3be940bad12f162fe6dd272e96f46bf2 authorKazu Yamamoto <kazu@iij.ad.jp> dateThu 24 Dec 2015, 15:03 (11 years ago) parent2de0e76
2 files changed+176−166
warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+175−165 warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+1−1
warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+175−165
@@ -9,14 +9,14 @@ import Control.Applicative
99#endif
1010import Control.Concurrent.STM
1111import qualified Control.Exception as E
12−import Control.Monad (unless, void, when)
12+import Control.Monad (void, when)
1313import qualified Data.ByteString as BS
1414import qualified Data.ByteString.Builder.Extra as B
1515import Data.Maybe (isNothing)
1616import Foreign.Ptr
1717import Network.HPACK (setLimitForEncoding)
1818import Network.HTTP2
19−import Network.HTTP2.Priority (dequeueSTM)
19+import Network.HTTP2.Priority (isEmptySTM, dequeueSTM, Precedence)
2020import Network.Wai
2121import Network.Wai.Handler.Warp.Buffer
2222import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
@@ -25,9 +25,6 @@ import Network.Wai.Handler.Warp.HTTP2.Manager (Manager)
2525import Network.Wai.Handler.Warp.HTTP2.Types
2626import Network.Wai.Handler.Warp.IORef
2727import qualified Network.Wai.Handler.Warp.Settings as S
28−#ifndef WINDOWS
29−import qualified Network.Wai.Handler.Warp.Timeout as T
30−#endif
3128import Network.Wai.Handler.Warp.Types
3229import Network.Wai.Internal (Response(..))
3330
@@ -36,6 +33,7 @@ import qualified System.IO as IO
3633#else
3734import Network.Wai.Handler.Warp.FdCache
3835import Network.Wai.Handler.Warp.SendFile (positionRead)
36+import qualified Network.Wai.Handler.Warp.Timeout as T
3937import System.Posix.IO (openFd, OpenFileFlags(..), defaultFileFlags, OpenMode(ReadOnly), closeFd)
4038import System.Posix.Types
4139#endif
@@ -61,30 +59,48 @@ waitStreaming tbq = do
6159 isEmpty <- isEmptyTBQueue tbq
6260 check (isEmpty == False)
6361
62+data Switch = C Control
63+ | O (StreamId,Precedence,Output)
64+ | Flush
65+
6466frameSender :: Context -> Connection -> InternalInfo -> S.Settings -> Manager -> IO ()
6567frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
6668 conn@Connection{connWriteBuffer,connBufferSize,connSendAll}
67− ii settings mgr = loop `E.catch` ignore
69+ ii settings mgr = loop 0 `E.catch` ignore
6870 where
69− dequeueControl = Left <$> readTQueue controlQ
70− dequeueOutput = Right <$> do
71− w <- readTVar connectionWindow
72− check (w > 0)
73− dequeueSTM outputQ
74−
75− loop = do
76− ex <- atomically (dequeueControl `orElse` dequeueOutput)
77− case ex of
78− Left ctl -> control ctl
79− Right (_,pre,out) -> do
80− writeIORef (streamPrecedence (outputStream out)) pre
81− output out
82−
83− control CFinish = return ()
84− control (CGoaway frame) = connSendAll frame
85− control (CFrame frame) = do
86− connSendAll frame
87− loop
71+ dequeue off = do
72+ isEmpty <- isEmptyTQueue controlQ
73+ if isEmpty then do
74+ w <- readTVar connectionWindow
75+ check (w > 0)
76+ emp <- isEmptySTM outputQ
77+ if emp then
78+ if off /= 0 then return Flush else retry
79+ else
80+ O <$> dequeueSTM outputQ
81+ else
82+ C <$> readTQueue controlQ
83+
84+ loop off = do
85+ x <- atomically $ dequeue off
86+ case x of
87+ C ctl -> do
88+ when (off /= 0) $ flushN off
89+ cont <- control ctl
90+ when cont $ loop 0
91+ O (_,pre,out) -> do
92+ let strm = outputStream out
93+ writeIORef (streamPrecedence strm) pre
94+ off' <- whenReadyOrEnqueueAgain out off $ output out off
95+ case off' of
96+ 0 -> loop 0
97+ _ | off' > 12288 -> flushN off' >> loop 0 -- fixme: hard-coding
98+ | otherwise -> loop off'
99+ Flush -> flushN off >> loop 0
100+
101+ control CFinish = return False
102+ control (CGoaway frame) = connSendAll frame >> return False
103+ control (CFrame frame) = connSendAll frame >> return True
88104 control (CSettings frame alist) = do
89105 connSendAll frame
90106 case lookup SettingsHeaderTableSize alist of
@@ -92,166 +108,159 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
92108 Just siz -> do
93109 dyntbl <- readIORef encodeDynamicTable
94110 setLimitForEncoding siz dyntbl
95− loop
96−
97− output out@(ONext strm binfo curr) = do
98− whenReadyOrEnqueueAgain strm binfo out $ \sws -> do
99− cws <- atomically $ readTVar connectionWindow
100− let !lim = min cws sws
101− -- Data frame payload
102− Next datPayloadLen mnext <- curr lim
103− fillDataHeaderSend strm 0 datPayloadLen mnext
104− maybeEnqueueNext strm mnext binfo
105− loop
106− output out@(OResponse strm binfo rsp) = do
107− whenReadyOrEnqueueAgain strm binfo out $ \sws -> do
108− -- Header frame and Continuation frame
109− let sid = streamNumber strm
110− endOfStream = case binfo of
111− Persist{} -> False
112− OneshotWithBody -> False
113− OneshotWithoutBody -> True
114− len <- headerContinue sid rsp endOfStream
115− let total = len + frameHeaderLength
116− case binfo of
117− OneshotWithBody -> do
118− -- Data frame payload
119− (off, _) <- sendHeadersIfNecessary total
120− let payloadOff = off + frameHeaderLength
121− cws <- atomically $ readTVar connectionWindow
122− let !lim = min cws sws
123− Next datPayloadLen mnext <-
124− fillResponseBodyGetNext conn ii payloadOff lim rsp
125− fillDataHeaderSend strm total datPayloadLen mnext
126− maybeEnqueueNext strm mnext binfo
127− OneshotWithoutBody -> do
128− -- "closed" must be before "connSendAll". If not,
129− -- the context would be switched to the receiver,
130− -- resulting the inconsistency of concurrency.
131− closed ctx strm Finished
132− flushN total
133− Persist sq -> do
134− (off, needSend) <- sendHeadersIfNecessary total
135− let payloadOff = off + frameHeaderLength
136− cws <- atomically $ readTVar connectionWindow
137− let !lim = min cws sws
138− Next datPayloadLen mnext <-
139− fillStreamBodyGetNext conn payloadOff lim sq strm
140− -- If no data was immediately available, avoid sending an
141− -- empty data frame.
142− if datPayloadLen > 0 then
143− fillDataHeaderSend strm total datPayloadLen mnext
144− else
145− when needSend $ flushN off
146− maybeEnqueueNext strm mnext binfo
147− loop
148−
149− whenReadyOrEnqueueAgain strm binfo out body = E.handle resetStream $ do
111+ return True
112+
113+ output (ONext strm binfo curr) off0 lim = do
114+ -- Data frame payload
115+ let !buf = connWriteBuffer `plusPtr` off0
116+ !siz = connBufferSize - off0
117+ Next datPayloadLen mnext <- curr buf siz lim
118+ off <- fillDataHeader strm off0 datPayloadLen mnext
119+ maybeEnqueueNext strm binfo mnext
120+ return off
121+
122+ output (OResponse strm binfo rsp) off0 lim = do
123+ -- Header frame and Continuation frame
124+ let sid = streamNumber strm
125+ endOfStream = case binfo of
126+ Persist{} -> False
127+ OneshotWithBody -> False
128+ OneshotWithoutBody -> True
129+ kvlen <- headerContinue sid rsp endOfStream off0
130+ off <- sendHeadersIfNecessary $ off0 + frameHeaderLength + kvlen
131+ case binfo of
132+ OneshotWithoutBody -> do
133+ closed ctx strm Finished
134+ return off
135+ OneshotWithBody -> do
136+ -- Data frame payload
137+ let payloadOff = off + frameHeaderLength
138+ Next datPayloadLen mnext <-
139+ fillResponseBodyGetNext conn ii payloadOff lim rsp
140+ off' <- fillDataHeader strm off datPayloadLen mnext
141+ maybeEnqueueNext strm binfo mnext
142+ return off'
143+ Persist sq -> do
144+ let payloadOff = off + frameHeaderLength
145+ Next datPayloadLen mnext <-
146+ fillStreamBodyGetNext conn payloadOff lim sq strm
147+ off' <- fillDataHeader strm off datPayloadLen mnext
148+ maybeEnqueueNext strm binfo mnext
149+ return off'
150+
151+ whenReadyOrEnqueueAgain out off body = E.handle resetStream $ do
150152 state <- readIORef $ streamState strm
151− unless (isClosed state) $ case binfo of
153+ if isClosed state then
154+ return off
155+ else case binfo of
152156 Persist tbq -> checkStreaming tbq
153157 _ -> checkStreamWindowSize
154158 where
159+ strm = outputStream out
160+ binfo = outputBodyInfo out
155161 checkStreaming tbq = do
156162 isEmpty <- atomically $ isEmptyTBQueue tbq
157− if isEmpty then
163+ if isEmpty then do
158164 forkAndEnqueueWhenReady (waitStreaming tbq) outputQ out mgr
165+ return off
159166 else
160167 checkStreamWindowSize
161168 checkStreamWindowSize = do
162169 sws <- getStreamWindowSize strm
163170 if sws == 0 then do
164171 forkAndEnqueueWhenReady (waitStreamWindowSize strm) outputQ out mgr
165− else
166− body sws
172+ return off
173+ else do
174+ cws <- atomically $ readTVar connectionWindow -- not 0
175+ let !lim = min cws sws
176+ body lim
167177 resetStream e = do
168178 closed ctx strm (ResetByMe e)
169179 let !rst = resetFrame InternalError $ streamNumber strm
170180 enqueueControl controlQ $ CFrame rst
181+ return off
171182
172183 -- Flush the connection buffer to the socket, where the first 'n' bytes of
173184 -- the buffer are filled.
174185 flushN :: Int -> IO ()
175186 flushN n = bufferIO connWriteBuffer n connSendAll
176187
177− headerContinue sid rsp endOfStream = do
188+ headerContinue sid rsp endOfStream off = do
178189 builder <- hpackEncodeHeader ctx ii settings rsp
179− (len, signal) <- B.runBuilder builder bufHeaderPayload headerPayloadLim
190+ let !offkv = off + frameHeaderLength
191+ let !bufkv = connWriteBuffer `plusPtr` offkv
192+ !limkv = connBufferSize - offkv
193+ (kvlen, signal) <- B.runBuilder builder bufkv limkv
180194 let flag0 = case signal of
181195 B.Done -> setEndHeader defaultFlags
182196 _ -> defaultFlags
183197 flag = if endOfStream then setEndStream flag0 else flag0
184− fillFrameHeader FrameHeaders len sid flag connWriteBuffer
185− continue sid len signal
198+ let buf = connWriteBuffer `plusPtr` off
199+ fillFrameHeader FrameHeaders kvlen sid flag buf
200+ continue sid kvlen signal
186201
187− continue _ len B.Done = return len
188− continue sid len (B.More _ writer) = do
189− flushN $ len + frameHeaderLength
190− (len', signal') <- writer bufHeaderPayload headerPayloadLim
202+ bufHeaderPayload = connWriteBuffer `plusPtr` frameHeaderLength
203+ headerPayloadLim = connBufferSize - frameHeaderLength
204+
205+ continue _ kvlen B.Done = return kvlen
206+ continue sid kvlen (B.More _ writer) = do
207+ flushN $ kvlen + frameHeaderLength
208+ -- Now off is 0
209+ (kvlen', signal') <- writer bufHeaderPayload headerPayloadLim
191210 let flag = case signal' of
192211 B.Done -> setEndHeader defaultFlags
193212 _ -> defaultFlags
194− fillFrameHeader FrameContinuation len' sid flag connWriteBuffer
195− continue sid len' signal'
196− continue sid len (B.Chunk bs writer) = do
197− flushN $ len + frameHeaderLength
213+ fillFrameHeader FrameContinuation kvlen' sid flag connWriteBuffer
214+ continue sid kvlen' signal'
215+ continue sid kvlen (B.Chunk bs writer) = do
216+ flushN $ kvlen + frameHeaderLength
217+ -- Now off is 0
198218 let (bs1,bs2) = BS.splitAt headerPayloadLim bs
199− len' = BS.length bs1
219+ kvlen' = BS.length bs1
200220 void $ copy bufHeaderPayload bs1
201− fillFrameHeader FrameContinuation len' sid defaultFlags connWriteBuffer
221+ fillFrameHeader FrameContinuation kvlen' sid defaultFlags connWriteBuffer
202222 if bs2 == "" then
203− continue sid len' (B.More 0 writer)
223+ continue sid kvlen' (B.More 0 writer)
204224 else
205− continue sid len' (B.Chunk bs2 writer)
206−
207− -- True if the connection buffer has room for a 1-byte data frame.
208− canFitDataFrame total = total + frameHeaderLength < connBufferSize
225+ continue sid kvlen' (B.Chunk bs2 writer)
209226
210227 -- Re-enqueue the stream in the output queue.
211− maybeEnqueueNext :: Stream -> Maybe DynaNext -> BodyInfo -> IO ()
212− maybeEnqueueNext strm (Just next) binfo = do
213− let !out = ONext strm binfo next
214− enqueueOutput outputQ out
215− maybeEnqueueNext _ _ _ = return ()
216−
228+ maybeEnqueueNext :: Stream -> BodyInfo -> Maybe DynaNext -> IO ()
229+ maybeEnqueueNext _ _ Nothing = return ()
230+ maybeEnqueueNext strm binfo (Just next) = enqueueOutput outputQ out
231+ where
232+ !out = ONext strm binfo next
217233
218234 -- Send headers if there is not room for a 1-byte data frame, and return
219− -- the offset of the next frame's first header byte and whether the headers
220− -- still need to be sent.
221− sendHeadersIfNecessary total
222− | canFitDataFrame total = return (total, True)
223− | otherwise = do
224− flushN total
225− return (0, False)
226−
227− fillDataHeaderSend strm otherLen datPayloadLen mnext = do
235+ -- the offset of the next frame's first header byte.
236+ sendHeadersIfNecessary off
237+ -- True if the connection buffer has room for a 1-byte data frame.
238+ | off + frameHeaderLength < connBufferSize = return off
239+ | otherwise = do
240+ flushN off
241+ return 0
242+
243+ fillDataHeader strm off datPayloadLen mnext = do
228244 -- Data frame header
229− let sid = streamNumber strm
230− buf = connWriteBuffer `plusPtr` otherLen
231− total = otherLen + frameHeaderLength + datPayloadLen
245+ let !sid = streamNumber strm
246+ !buf = connWriteBuffer `plusPtr` off
247+ !off' = off + frameHeaderLength + datPayloadLen
232248 flag = case mnext of
233249 Nothing -> setEndStream defaultFlags
234250 _ -> defaultFlags
235251 fillFrameHeader FrameData datPayloadLen sid flag buf
236− -- "closed" must be before "flushN". If not,
237− -- the context would be switched to the receiver,
238− -- resulting the inconsistency of concurrency.
239252 when (isNothing mnext) $ closed ctx strm Finished
240− flushN total
241253 atomically $ modifyTVar' connectionWindow (subtract datPayloadLen)
242254 atomically $ modifyTVar' (streamWindow strm) (subtract datPayloadLen)
255+ return off'
243256
244257 fillFrameHeader ftyp len sid flag buf = encodeFrameHeaderBuf ftyp hinfo buf
245258 where
246259 hinfo = FrameHeader len flag sid
247260
248− bufHeaderPayload = connWriteBuffer `plusPtr` frameHeaderLength
249− headerPayloadLim = connBufferSize - frameHeaderLength
250−
251261 ignore :: E.SomeException -> IO ()
252262 ignore _ = return ()
253263
254−
255264----------------------------------------------------------------
256265
257266{-
@@ -267,7 +276,7 @@ fillResponseBodyGetNext Connection{connWriteBuffer,connBufferSize}
267276 let datBuf = connWriteBuffer `plusPtr` off
268277 room = min (connBufferSize - off) lim
269278 (len, signal) <- B.runBuilder bb datBuf room
270− return $ nextForBuilder connWriteBuffer connBufferSize len signal
279+ return $ nextForBuilder len signal
271280
272281#ifdef WINDOWS
273282fillResponseBodyGetNext Connection{connWriteBuffer,connBufferSize}
@@ -280,7 +289,8 @@ fillResponseBodyGetNext Connection{connWriteBuffer,connBufferSize}
280289 IO.hSeek h IO.AbsoluteSeek start
281290 len <- IO.hGetBufSome h datBuf (mini room bytes)
282291 let bytes' = bytes - fromIntegral len
283− return $ nextForFile len connWriteBuffer connBufferSize h bytes' (return ())
292+ -- fixme: connWriteBuffer connBufferSize
293+ return $ nextForFile len h bytes' (return ())
284294#else
285295fillResponseBodyGetNext Connection{connWriteBuffer,connBufferSize}
286296 ii off lim (ResponseFile _ _ path mpart) = do
@@ -296,7 +306,7 @@ fillResponseBodyGetNext Connection{connWriteBuffer,connBufferSize}
296306 len <- positionRead fd datBuf (mini room bytes) start
297307 refresh
298308 let len' = fromIntegral len
299− return $ nextForFile len connWriteBuffer connBufferSize fd (start + len') (bytes - len') refresh
309+ return $ nextForFile len fd (start + len') (bytes - len') refresh
300310#endif
301311
302312fillResponseBodyGetNext _ _ _ _ _ = error "fillResponseBodyGetNext"
@@ -314,12 +324,12 @@ fillStreamBodyGetNext Connection{connWriteBuffer,connBufferSize}
314324 let datBuf = connWriteBuffer `plusPtr` off
315325 room = min (connBufferSize - off) lim
316326 (leftover, cont, len) <- runStreamBuilder datBuf room sq
317− return $ nextForStream connWriteBuffer connBufferSize sq strm leftover cont len
327+ return $ nextForStream sq strm leftover cont len
318328
319329----------------------------------------------------------------
320330
321−fillBufBuilder :: Buffer -> BufSize -> Leftover -> DynaNext
322−fillBufBuilder buf0 siz0 leftover lim = do
331+fillBufBuilder :: Leftover -> DynaNext
332+fillBufBuilder leftover buf0 siz0 lim = do
323333 let payloadBuf = buf0 `plusPtr` frameHeaderLength
324334 room = min (siz0 - frameHeaderLength) lim
325335 case leftover of
@@ -338,15 +348,15 @@ fillBufBuilder buf0 siz0 leftover lim = do
338348 void $ copy payloadBuf bs1
339349 getNext room (B.Chunk bs2 writer)
340350 where
341− getNext l s = return $ nextForBuilder buf0 siz0 l s
351+ getNext l s = return $ nextForBuilder l s
342352
343−nextForBuilder :: Buffer -> BufSize -> BytesFilled -> B.Next -> Next
344−nextForBuilder _ _ len B.Done
353+nextForBuilder :: BytesFilled -> B.Next -> Next
354+nextForBuilder len B.Done
345355 = Next len Nothing
346−nextForBuilder buf siz len (B.More _ writer)
347− = Next len $ Just (fillBufBuilder buf siz (LOne writer))
348−nextForBuilder buf siz len (B.Chunk bs writer)
349− = Next len $ Just (fillBufBuilder buf siz (LTwo bs writer))
356+nextForBuilder len (B.More _ writer)
357+ = Next len $ Just (fillBufBuilder (LOne writer))
358+nextForBuilder len (B.Chunk bs writer)
359+ = Next len $ Just (fillBufBuilder (LTwo bs writer))
350360
351361----------------------------------------------------------------
352362
@@ -368,8 +378,8 @@ runStreamBuilder buf0 room0 sq = loop buf0 room0 0
368378 Just SFlush -> return (LZero, True, total)
369379 Just SFinish -> return (LZero, False, total)
370380
371−fillBufStream :: Buffer -> BufSize -> Leftover -> TBQueue Sequence -> Stream -> DynaNext
372−fillBufStream buf0 siz0 leftover0 sq strm lim0 = do
381+fillBufStream :: Leftover -> TBQueue Sequence -> Stream -> DynaNext
382+fillBufStream leftover0 sq strm buf0 siz0 lim0 = do
373383 let payloadBuf = buf0 `plusPtr` frameHeaderLength
374384 room0 = min (siz0 - frameHeaderLength) lim0
375385 case leftover0 of
@@ -387,7 +397,7 @@ fillBufStream buf0 siz0 leftover0 sq strm lim0 = do
387397 void $ copy payloadBuf bs1
388398 getNext (LTwo bs2 writer) True room0
389399 where
390− getNext l b r = return $ nextForStream buf0 siz0 sq strm l b r
400+ getNext l b r = return $ nextForStream sq strm l b r
391401 write writer1 buf room sofar = do
392402 (len, signal) <- writer1 buf room
393403 case signal of
@@ -402,45 +412,45 @@ fillBufStream buf0 siz0 leftover0 sq strm lim0 = do
402412 let !total = sofar + len
403413 getNext (LTwo bs writer) True total
404414
405−nextForStream :: Buffer -> BufSize -> TBQueue Sequence -> Stream
415+nextForStream :: TBQueue Sequence -> Stream
406416 -> Leftover -> Bool -> BytesFilled
407417 -> Next
408−nextForStream _ _ _ _ _ False len = Next len Nothing
409−nextForStream buf siz sq strm leftOrZero True len =
410− Next len $ Just (fillBufStream buf siz leftOrZero sq strm)
418+nextForStream _ _ _ False len = Next len Nothing
419+nextForStream sq strm leftOrZero True len =
420+ Next len $ Just (fillBufStream leftOrZero sq strm)
411421
412422----------------------------------------------------------------
413423
414424#ifdef WINDOWS
415−fillBufFile :: Buffer -> BufSize -> IO.Handle -> Integer -> IO () -> DynaNext
416−fillBufFile buf siz h bytes refresh lim = do
425+fillBufFile :: IO.Handle -> Integer -> IO () -> DynaNext
426+fillBufFile h bytes refresh buf siz lim = do
417427 let payloadBuf = buf `plusPtr` frameHeaderLength
418428 room = min (siz - frameHeaderLength) lim
419429 len <- IO.hGetBufSome h payloadBuf room
420430 refresh
421431 let bytes' = bytes - fromIntegral len
422− return $ nextForFile len buf siz h bytes' refresh
432+ return $ nextForFile len h bytes' refresh
423433
424−nextForFile :: BytesFilled -> Buffer -> BufSize -> IO.Handle -> Integer -> IO () -> Next
425−nextForFile 0 _ _ _ _ _ = Next 0 Nothing
426−nextForFile len _ _ _ 0 _ = Next len Nothing
427−nextForFile len buf siz h bytes refresh =
428− Next len $ Just (fillBufFile buf siz h bytes refresh)
434+nextForFile :: BytesFilled -> IO.Handle -> Integer -> IO () -> Next
435+nextForFile 0 _ _ _ = Next 0 Nothing
436+nextForFile len _ 0 _ = Next len Nothing
437+nextForFile len h bytes refresh =
438+ Next len $ Just (fillBufFile h bytes refresh)
429439#else
430−fillBufFile :: Buffer -> BufSize -> Fd -> Integer -> Integer -> IO () -> DynaNext
431−fillBufFile buf siz fd start bytes refresh lim = do
440+fillBufFile :: Fd -> Integer -> Integer -> IO () -> DynaNext
441+fillBufFile fd start bytes refresh buf siz lim = do
432442 let payloadBuf = buf `plusPtr` frameHeaderLength
433443 room = min (siz - frameHeaderLength) lim
434444 len <- positionRead fd payloadBuf (mini room bytes) start
435445 let len' = fromIntegral len
436446 refresh
437− return $ nextForFile len buf siz fd (start + len') (bytes - len') refresh
447+ return $ nextForFile len fd (start + len') (bytes - len') refresh
438448
439−nextForFile :: BytesFilled -> Buffer -> BufSize -> Fd -> Integer -> Integer -> IO () -> Next
440−nextForFile 0 _ _ _ _ _ _ = Next 0 Nothing
441−nextForFile len _ _ _ _ 0 _ = Next len Nothing
442−nextForFile len buf siz fd start bytes refresh =
443− Next len $ Just (fillBufFile buf siz fd start bytes refresh)
449+nextForFile :: BytesFilled -> Fd -> Integer -> Integer -> IO () -> Next
450+nextForFile 0 _ _ _ _ = Next 0 Nothing
451+nextForFile len _ _ 0 _ = Next len Nothing
452+nextForFile len fd start bytes refresh =
453+ Next len $ Just (fillBufFile fd start bytes refresh)
444454#endif
445455
446456mini :: Int -> Integer -> Int
warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+1−1
@@ -45,7 +45,7 @@ data Input = Input Stream Request
4545
4646----------------------------------------------------------------
4747
48−type DynaNext = WindowSize -> IO Next
48+type DynaNext = Buffer -> BufSize -> WindowSize -> IO Next
4949
5050type BytesFilled = Int
5151