@@ -7,9 +7,10 @@ module Network.Wai.Handler.Warp.HTTP2.Sender (frameSender) where
77#if __GLASGOW_HASKELL__ < 709
88import Control.Applicative
99#endif
10+import Control.Concurrent.MVar (putMVar)
1011import Control.Concurrent.STM
1112import qualified Control.Exception as E
12−import Control.Monad (unless, void, when)
13+import Control.Monad (void, when)
1314import qualified Data.ByteString as BS
1415import qualified Data.ByteString.Builder as B (int32BE)
1516import qualified Data.ByteString.Builder.Extra as B
@@ -49,17 +50,18 @@ type OpenFile = Fd
4950
5051----------------------------------------------------------------
5152
52−unlessClosed :: Connection -> Stream -> IO () -> IO ()
53+unlessClosed :: Connection -> Stream -> IO () -> IO Bool
5354unlessClosed Connection{connSendAll}
5455 strm@Stream{streamState,streamNumber}
5556 body = E.handle resetStream $ do
5657 state <- readIORef streamState
57− unless (isClosed state) body
58+ if (isClosed state) then return False else body >> return True
5859 where
5960 resetStream e = do
6061 closed strm (ResetByMe e)
6162 let rst = resetFrame InternalError streamNumber
6263 connSendAll rst
64+ return False
6365
6466getWindowSize :: TVar WindowSize -> TVar WindowSize -> IO WindowSize
6567getWindowSize connWindow strmWindow = do
@@ -98,20 +100,20 @@ frameSender ctx@Context{outputQ,connectionWindow}
98100 connSendAll frame
99101 loop
100102 switch (OResponse strm s h aux) = do
101− unlessClosed conn strm $
103+ _ <- unlessClosed conn strm $
102104 getWindowSize connectionWindow (streamWindow strm) >>=
103105 sendResponse strm s h aux
104106 loop
105107 switch (ONext strm curr) = do
106− unlessClosed conn strm $ do
108+ _ <- unlessClosed conn strm $ do
107109 lim <- getWindowSize connectionWindow (streamWindow strm)
108110 -- Data frame payload
109111 Next datPayloadLen mnext <- curr lim
110112 fillDataHeaderSend strm 0 datPayloadLen mnext
111113 maybeEnqueueNext strm mnext
112114 loop
113− switch (OPush oldStrm push strm s h aux) = do
114− unlessClosed conn oldStrm $ do
115+ switch (OPush oldStrm push mvar strm s h aux) = do
116+ pushed <- unlessClosed conn oldStrm $ do
115117 lim <- getWindowSize connectionWindow (streamWindow strm)
116118 -- Write and send the promise.
117119 builder <- hpackEncodeCIHeaders ctx $ promiseHeaders push
@@ -120,9 +122,10 @@ frameSender ctx@Context{outputQ,connectionWindow}
120122 -- TODO(awpr): refactor sendResponse to be able to handle non-zero
121123 -- initial offsets and use that to potentially avoid the extra syscall.
122124 sendResponse strm s h aux lim
125+ putMVar mvar pushed
123126 loop
124127 switch (OTrailers strm []) = do
125− unlessClosed conn strm $ do
128+ _ <- unlessClosed conn strm $ do
126129 -- An empty data frame should be used to end the stream instead
127130 -- when there are no trailers.
128131 let flag = setEndStream defaultFlags
@@ -131,7 +134,7 @@ frameSender ctx@Context{outputQ,connectionWindow}
131134 flushN frameHeaderLength
132135 loop
133136 switch (OTrailers strm trailers) = do
134− unlessClosed conn strm $ do
137+ _ <- unlessClosed conn strm $ do
135138 -- Trailers always indicate the end of a stream; send them in
136139 -- consecutive header+continuation frames and end the stream.
137140 builder <- hpackEncodeCIHeaders ctx trailers