on master help sign in
using orElse to dequeue data and control frames.
commit8e05db46c25d619742db276b4dd08c36f7aef131 authorKazu Yamamoto <kazu@iij.ad.jp> dateSun 20 Dec 2015, 10:10 (11 years ago) parentfb850ff
4 files changed+60−53
warp/Network/Wai/Handler/Warp/HTTP2/Receiver.hs+12−12 warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+35−30 warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+11−9 warp/Network/Wai/Handler/Warp/HTTP2/Worker.hs+2−2
warp/Network/Wai/Handler/Warp/HTTP2/Receiver.hs+12−12
@@ -36,18 +36,18 @@ frameReceiver ctx mkreq recvN = loop 0 `E.catch` sendGoaway
3636 , continued
3737 , currentStreamId
3838 , inputQ
39− , outputQ
39+ , controlQ
4040 } = ctx
4141 sendGoaway e
4242 | Just (ConnectionError err msg) <- E.fromException e = do
4343 csid <- readIORef currentStreamId
4444 let !frame = goawayFrame csid err msg
45− enqueueOutputControl outputQ $ OGoaway frame
45+ enqueueControl controlQ $ CGoaway frame
4646 | otherwise = return ()
4747
4848 sendReset err sid = do
4949 let !frame = resetFrame err sid
50− enqueueOutputControl outputQ $ OFrame frame
50+ enqueueControl controlQ $ CFrame frame
5151
5252 loop :: Int -> IO ()
5353 loop !n
@@ -57,7 +57,7 @@ frameReceiver ctx mkreq recvN = loop 0 `E.catch` sendGoaway
5757 | otherwise = do
5858 hd <- recvN frameHeaderLength
5959 if BS.null hd then
60− enqueueOutputControl outputQ OFinish
60+ enqueueControl controlQ CFinish
6161 else do
6262 cont <- processStreamGuardingError $ decodeFrameHeader hd
6363 when cont $ loop (n + 1)
@@ -178,7 +178,7 @@ initialFrame = settingsFrame id [(SettingsMaxConcurrentStreams,recommendedConcur
178178----------------------------------------------------------------
179179
180180control :: FrameTypeId -> FrameHeader -> ByteString -> Context -> IO Bool
181−control FrameSettings header@FrameHeader{flags} bs Context{http2settings, outputQ,firstSettings} = do
181+control FrameSettings header@FrameHeader{flags} bs Context{http2settings, controlQ,firstSettings} = do
182182 SettingsFrame alist <- guardIt $ decodeSettingsFrame header bs
183183 case checkSettingsList alist of
184184 Just x -> E.throwIO x
@@ -189,19 +189,19 @@ control FrameSettings header@FrameHeader{flags} bs Context{http2settings, output
189189 sent <- readIORef firstSettings
190190 let !frame' = if sent then frame else BS.append initialFrame frame
191191 unless sent $ writeIORef firstSettings True
192− enqueueOutputControl outputQ $ OSettings frame' alist
192+ enqueueControl controlQ $ CSettings frame' alist
193193 return True
194194
195−control FramePing FrameHeader{flags} bs Context{outputQ} =
195+control FramePing FrameHeader{flags} bs Context{controlQ} =
196196 if testAck flags then
197197 E.throwIO $ ConnectionError ProtocolError "the ack flag of this ping frame must not be set"
198198 else do
199199 let !frame = pingFrame bs
200− enqueueOutputControl outputQ $ OFrame frame
200+ enqueueControl controlQ $ CFrame frame
201201 return True
202202
203−control FrameGoAway _ _ Context{outputQ} = do
204− enqueueOutputControl outputQ OFinish
203+control FrameGoAway _ _ Context{controlQ} = do
204+ enqueueControl controlQ CFinish
205205 return False
206206
207207control FrameWindowUpdate header bs Context{connectionWindow} = do
@@ -264,7 +264,7 @@ stream FrameHeaders header@FrameHeader{flags} bs _ (Open (Body q)) _ = do
264264stream FrameData
265265 header@FrameHeader{flags,payloadLength,streamId}
266266 bs
267− Context{outputQ} s@(Open (Body q))
267+ Context{controlQ} s@(Open (Body q))
268268 Stream{streamNumber,streamBodyLength,streamContentLength} = do
269269 DataFrame body <- guardIt $ decodeDataFrame header bs
270270 let !endOfStream = testEndStream flags
@@ -275,7 +275,7 @@ stream FrameData
275275 let !frame1 = windowUpdateFrame 0 payloadLength
276276 !frame2 = windowUpdateFrame streamNumber payloadLength
277277 !frame = frame1 `BS.append` frame2
278− enqueueOutputControl outputQ $ OFrame frame
278+ enqueueControl controlQ $ CFrame frame
279279 atomically $ writeTQueue q body
280280 if endOfStream then do
281281 mcl <- readIORef streamContentLength
warp/Network/Wai/Handler/Warp/HTTP2/Sender.hs+35−30
@@ -16,7 +16,7 @@ import Data.Maybe (isNothing)
1616import Foreign.Ptr
1717import Network.HPACK (setLimitForEncoding)
1818import Network.HTTP2
19−import Network.HTTP2.Priority (dequeue)
19+import Network.HTTP2.Priority (dequeueSTM)
2020import Network.Wai
2121import Network.Wai.Handler.Warp.Buffer
2222import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
@@ -47,12 +47,6 @@ data Leftover = LZero
4747
4848----------------------------------------------------------------
4949
50−getConnectionWindowSizeWhenReady :: Context -> IO WindowSize
51−getConnectionWindowSizeWhenReady Context{connectionWindow} = atomically $ do
52− w <- readTVar connectionWindow
53− check (w > 0)
54− return w
55−
5650getStreamWindowSize :: Stream -> IO WindowSize
5751getStreamWindowSize Stream{streamWindow} = atomically $ readTVar streamWindow
5852
@@ -67,24 +61,30 @@ waitStreaming tbq = do
6761 check (isEmpty == False)
6862
6963frameSender :: Context -> Connection -> InternalInfo -> S.Settings -> IO ()
70−frameSender ctx@Context{outputQ,connectionWindow,encodeDynamicTable}
64+frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
7165 conn@Connection{connWriteBuffer,connBufferSize,connSendAll}
7266 ii settings = loop `E.catch` ignore
7367 where
74− bufHeaderPayload = connWriteBuffer `plusPtr` frameHeaderLength
75− headerPayloadLim = connBufferSize - frameHeaderLength
76−
77− loop = dequeue outputQ >>= \(_sid,pre,out) -> switch out pre
78−
79− ignore :: E.SomeException -> IO ()
80− ignore _ = return ()
81−
82− switch OFinish _ = return ()
83− switch (OGoaway frame) _ = connSendAll frame
84− switch (OFrame frame) _ = do
68+ dequeueControl = Left <$> readTQueue controlQ
69+ dequeueData = Right <$> do
70+ w <- readTVar connectionWindow
71+ check (w > 0)
72+ dequeueSTM outputQ
73+
74+ loop = do
75+ ex <- atomically (dequeueControl `orElse` dequeueData)
76+ case ex of
77+ Left ctl -> control ctl
78+ Right (_,pre,out) -> do
79+ writeIORef (streamPrecedence (outputStream out)) pre
80+ switch out
81+
82+ control CFinish = return ()
83+ control (CGoaway frame) = connSendAll frame
84+ control (CFrame frame) = do
8585 connSendAll frame
8686 loop
87− switch (OSettings frame alist) _ = do
87+ control (CSettings frame alist) = do
8888 connSendAll frame
8989 case lookup SettingsHeaderTableSize alist of
9090 Nothing -> return ()
@@ -92,18 +92,17 @@ frameSender ctx@Context{outputQ,connectionWindow,encodeDynamicTable}
9292 dyntbl <- readIORef encodeDynamicTable
9393 setLimitForEncoding siz dyntbl
9494 loop
95− switch out@(ONext strm curr binfo) pre = do
96− writeIORef (streamPrecedence strm) pre
95+
96+ switch out@(ONext strm curr binfo) = do
9797 whenReadyOrEnqueueAgain strm binfo out $ \sws -> do
98− cws <- getConnectionWindowSizeWhenReady ctx
98+ cws <- atomically $ readTVar connectionWindow
9999 let !lim = min cws sws
100100 -- Data frame payload
101101 Next datPayloadLen mnext <- curr lim
102102 fillDataHeaderSend strm 0 datPayloadLen mnext
103103 maybeEnqueueNext strm mnext binfo
104104 loop
105− switch out@(OResponse strm rsp binfo) pre = do
106− writeIORef (streamPrecedence strm) pre
105+ switch out@(OResponse strm rsp binfo) = do
107106 whenReadyOrEnqueueAgain strm binfo out $ \sws -> do
108107 -- Header frame and Continuation frame
109108 let sid = streamNumber strm
@@ -118,7 +117,7 @@ frameSender ctx@Context{outputQ,connectionWindow,encodeDynamicTable}
118117 -- Data frame payload
119118 (off, _) <- sendHeadersIfNecessary total
120119 let payloadOff = off + frameHeaderLength
121− cws <- getConnectionWindowSizeWhenReady ctx
120+ cws <- atomically $ readTVar connectionWindow
122121 let !lim = min cws sws
123122 Next datPayloadLen mnext <-
124123 fillResponseBodyGetNext conn ii payloadOff lim rsp
@@ -133,7 +132,7 @@ frameSender ctx@Context{outputQ,connectionWindow,encodeDynamicTable}
133132 Persist sq -> do
134133 (off, needSend) <- sendHeadersIfNecessary total
135134 let payloadOff = off + frameHeaderLength
136− cws <- getConnectionWindowSizeWhenReady ctx
135+ cws <- atomically $ readTVar connectionWindow
137136 let !lim = min cws sws
138137 Next datPayloadLen mnext <-
139138 fillStreamBodyGetNext conn payloadOff lim sq strm
@@ -166,9 +165,8 @@ frameSender ctx@Context{outputQ,connectionWindow,encodeDynamicTable}
166165 body sws
167166 resetStream e = do
168167 closed ctx strm (ResetByMe e)
169− let rst = resetFrame InternalError $ streamNumber strm
170− eout = OFrame rst
171− enqueueOutputControl outputQ eout
168+ let !rst = resetFrame InternalError $ streamNumber strm
169+ enqueueControl controlQ $ CFrame rst
172170
173171 -- Flush the connection buffer to the socket, where the first 'n' bytes of
174172 -- the buffer are filled.
@@ -246,6 +244,13 @@ frameSender ctx@Context{outputQ,connectionWindow,encodeDynamicTable}
246244 where
247245 hinfo = FrameHeader len flag sid
248246
247+ bufHeaderPayload = connWriteBuffer `plusPtr` frameHeaderLength
248+ headerPayloadLim = connBufferSize - frameHeaderLength
249+
250+ ignore :: E.SomeException -> IO ()
251+ ignore _ = return ()
252+
253+
249254----------------------------------------------------------------
250255
251256{-
warp/Network/Wai/Handler/Warp/HTTP2/Types.hs+11−9
@@ -48,17 +48,17 @@ type BytesFilled = Int
4848
4949data Next = Next !BytesFilled (Maybe DynaNext)
5050
51−data Output = OFinish
52− | OGoaway !ByteString
53− | OFrame !ByteString
54− | OSettings !ByteString !SettingsList
55− | OResponse !Stream !Response !BodyInfo
51+data Output = OResponse !Stream !Response !BodyInfo
5652 | ONext !Stream !DynaNext !BodyInfo
5753
5854outputStream :: Output -> Stream
5955outputStream (OResponse strm _ _) = strm
6056outputStream (ONext strm _ _) = strm
61−outputStream _ = error "outputStream"
57+
58+data Control = CFinish
59+ | CGoaway !ByteString
60+ | CFrame !ByteString
61+ | CSettings !ByteString !SettingsList
6262
6363----------------------------------------------------------------
6464
@@ -87,6 +87,7 @@ data Context = Context {
8787 , currentStreamId :: !(IORef StreamId)
8888 , inputQ :: !(TQueue Input)
8989 , outputQ :: !(PriorityTree Output)
90+ , controlQ :: !(TQueue Control)
9091 , encodeDynamicTable :: !(IORef DynamicTable)
9192 , decodeDynamicTable :: !(IORef DynamicTable)
9293 , connectionWindow :: !(TVar WindowSize)
@@ -104,6 +105,7 @@ newContext = Context <$> newIORef defaultSettings
104105 <*> newIORef 0
105106 <*> newTQueueIO
106107 <*> newPriorityTree
108+ <*> newTQueueIO
107109 <*> (newDynamicTableForEncoding defaultDynamicTableSize >>= newIORef)
108110 <*> (newDynamicTableForDecoding defaultDynamicTableSize >>= newIORef)
109111 <*> newTVarIO defaultInitialWindowSize
@@ -226,6 +228,6 @@ enqueueOutput outQ out = do
226228 pre <- readIORef streamPrecedence
227229 enqueue outQ streamNumber pre out
228230
229−{-# INLINE enqueueOutputControl #-}
230−enqueueOutputControl :: PriorityTree Output -> Output -> IO ()
231−enqueueOutputControl outQ out = enqueueControl outQ 0 out
231+{-# INLINE enqueueControl #-}
232+enqueueControl :: TQueue Control -> Control -> IO ()
233+enqueueControl ctlQ ctl = atomically $ writeTQueue ctlQ ctl
warp/Network/Wai/Handler/Warp/HTTP2/Worker.hs+2−2
@@ -129,7 +129,7 @@ response ii settings Context{outputQ} mgr tconf th strm req rsp
129129 return ResponseReceived
130130
131131worker :: Context -> S.Settings -> Application -> Responder -> T.Manager -> IO ()
132−worker ctx@Context{inputQ,outputQ} set app responder tm = do
132+worker ctx@Context{inputQ,controlQ} set app responder tm = do
133133 sinfo <- newStreamInfo
134134 tcont <- newThreadContinue
135135 E.bracket (T.registerKillThread tm) T.cancel $ go sinfo tcont
@@ -165,7 +165,7 @@ worker ctx@Context{inputQ,outputQ} set app responder tm = do
165165 Just (Input strm req) -> do
166166 closed ctx strm Killed
167167 let frame = resetFrame InternalError (streamNumber strm)
168− enqueueOutputControl outputQ $ OFrame frame
168+ enqueueControl controlQ $ CFrame frame
169169 case me of
170170 Nothing -> return ()
171171 Just e -> S.settingsOnException set (Just req) e