@@ -7,9 +7,10 @@ module Network.Wai.Handler.Warp.HTTP2.Sender (frameSender) where
7#if __GLASGOW_HASKELL__ < 709
7#if __GLASGOW_HASKELL__ < 709
8import Control.Applicative
8import Control.Applicative
10+import Control.Concurrent.MVar (putMVar)
10import Control.Concurrent.STM
11import Control.Concurrent.STM
11import qualified Control.Exception as E
12import qualified Control.Exception as E
12−import Control.Monad (unless, void, when)
13+import Control.Monad (void, when)
13import qualified Data.ByteString as BS
14import qualified Data.ByteString as BS
14import qualified Data.ByteString.Builder as B (int32BE)
15import qualified Data.ByteString.Builder as B (int32BE)
15import qualified Data.ByteString.Builder.Extra as B
16import qualified Data.ByteString.Builder.Extra as B
@@ -49,17 +50,18 @@ type OpenFile = Fd
50----------------------------------------------------------------
51----------------------------------------------------------------
52−unlessClosed :: Connection -> Stream -> IO () -> IO ()
53+unlessClosed :: Connection -> Stream -> IO () -> IO Bool
53unlessClosed Connection{connSendAll}
54unlessClosed Connection{connSendAll}
54 strm@Stream{streamState,streamNumber}
55 strm@Stream{streamState,streamNumber}
55 body = E.handle resetStream $ do
56 body = E.handle resetStream $ do
56 state <- readIORef streamState
57 state <- readIORef streamState
57− unless (isClosed state) body
58+ if (isClosed state) then return False else body >> return True
59 resetStream e = do
60 resetStream e = do
60 closed strm (ResetByMe e)
61 closed strm (ResetByMe e)
61 let rst = resetFrame InternalError streamNumber
62 let rst = resetFrame InternalError streamNumber
62 connSendAll rst
63 connSendAll rst
64getWindowSize :: TVar WindowSize -> TVar WindowSize -> IO WindowSize
66getWindowSize :: TVar WindowSize -> TVar WindowSize -> IO WindowSize
65getWindowSize connWindow strmWindow = do
67getWindowSize connWindow strmWindow = do
@@ -98,20 +100,20 @@ frameSender ctx@Context{outputQ,connectionWindow}
98 connSendAll frame
100 connSendAll frame
100 switch (OResponse strm s h aux) = do
102 switch (OResponse strm s h aux) = do
101− unlessClosed conn strm $
103+ _ <- unlessClosed conn strm $
102 getWindowSize connectionWindow (streamWindow strm) >>=
104 getWindowSize connectionWindow (streamWindow strm) >>=
103 sendResponse strm s h aux
105 sendResponse strm s h aux
105 switch (ONext strm curr) = do
107 switch (ONext strm curr) = do
106− unlessClosed conn strm $ do
108+ _ <- unlessClosed conn strm $ do
107 lim <- getWindowSize connectionWindow (streamWindow strm)
109 lim <- getWindowSize connectionWindow (streamWindow strm)
108 -- Data frame payload
110 -- Data frame payload
109 Next datPayloadLen mnext <- curr lim
111 Next datPayloadLen mnext <- curr lim
110 fillDataHeaderSend strm 0 datPayloadLen mnext
112 fillDataHeaderSend strm 0 datPayloadLen mnext
111 maybeEnqueueNext strm mnext
113 maybeEnqueueNext strm mnext
113− switch (OPush oldStrm push strm s h aux) = do
115+ switch (OPush oldStrm push mvar strm s h aux) = do
114− unlessClosed conn oldStrm $ do
116+ pushed <- unlessClosed conn oldStrm $ do
115 lim <- getWindowSize connectionWindow (streamWindow strm)
117 lim <- getWindowSize connectionWindow (streamWindow strm)
116 -- Write and send the promise.
118 -- Write and send the promise.
117 builder <- hpackEncodeCIHeaders ctx $ promiseHeaders push
119 builder <- hpackEncodeCIHeaders ctx $ promiseHeaders push
@@ -120,9 +122,10 @@ frameSender ctx@Context{outputQ,connectionWindow}
120 -- TODO(awpr): refactor sendResponse to be able to handle non-zero
122 -- TODO(awpr): refactor sendResponse to be able to handle non-zero
121 -- initial offsets and use that to potentially avoid the extra syscall.
123 -- initial offsets and use that to potentially avoid the extra syscall.
122 sendResponse strm s h aux lim
124 sendResponse strm s h aux lim
124 switch (OTrailers strm []) = do
127 switch (OTrailers strm []) = do
125− unlessClosed conn strm $ do
128+ _ <- unlessClosed conn strm $ do
126 -- An empty data frame should be used to end the stream instead
129 -- An empty data frame should be used to end the stream instead
127 -- when there are no trailers.
130 -- when there are no trailers.
128 let flag = setEndStream defaultFlags
131 let flag = setEndStream defaultFlags
@@ -131,7 +134,7 @@ frameSender ctx@Context{outputQ,connectionWindow}
131 flushN frameHeaderLength
134 flushN frameHeaderLength
133 switch (OTrailers strm trailers) = do
136 switch (OTrailers strm trailers) = do
134− unlessClosed conn strm $ do
137+ _ <- unlessClosed conn strm $ do
135 -- Trailers always indicate the end of a stream; send them in
138 -- Trailers always indicate the end of a stream; send them in
136 -- consecutive header+continuation frames and end the stream.
139 -- consecutive header+continuation frames and end the stream.
137 builder <- hpackEncodeCIHeaders ctx trailers
140 builder <- hpackEncodeCIHeaders ctx trailers