@@ -18,7 +18,7 @@ import Data.Maybe (isNothing)
18import Data.Word (Word8, Word32)
18import Data.Word (Word8, Word32)
19import Foreign.Ptr (Ptr, plusPtr)
19import Foreign.Ptr (Ptr, plusPtr)
20import Foreign.Storable (poke)
20import Foreign.Storable (poke)
21−import Network.HPACK (setLimitForEncoding)
21+import Network.HPACK (setLimitForEncoding, toHeaderTable)
22import Network.HTTP2
22import Network.HTTP2
23import Network.HTTP2.Priority (isEmptySTM, dequeueSTM, Precedence)
23import Network.HTTP2.Priority (isEmptySTM, dequeueSTM, Precedence)
24import Network.Wai
24import Network.Wai
@@ -122,16 +122,16 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
122 Nothing -> return ()
122 Nothing -> return ()
123 Just siz -> setLimitForEncoding siz encodeDynamicTable
123 Just siz -> setLimitForEncoding siz encodeDynamicTable
125− output out@(Output strm _ _ tell (ONext curr)) off0 lim = do
125+ output out@(Output strm _ _ tell getH2D (ONext curr)) off0 lim = do
126 -- Data frame payload
126 -- Data frame payload
127 let !buf = connWriteBuffer `plusPtr` off0
127 let !buf = connWriteBuffer `plusPtr` off0
128 !siz = connBufferSize - off0
128 !siz = connBufferSize - off0
129 Next datPayloadLen mnext <- curr buf siz lim
129 Next datPayloadLen mnext <- curr buf siz lim
130− off <- fillDataHeader strm off0 datPayloadLen mnext tell
130+ off <- fillDataHeader strm off0 datPayloadLen mnext tell getH2D
131 maybeEnqueueNext out mnext
131 maybeEnqueueNext out mnext
132 return off
132 return off
134− output out@(Output strm rspn ii tell ORspn) off0 lim = do
134+ output out@(Output strm rspn ii tell getH2D ORspn) off0 lim = do
135 -- Header frame and Continuation frame
135 -- Header frame and Continuation frame
136 let !sid = streamNumber strm
136 let !sid = streamNumber strm
137 !endOfStream = case rspn of
137 !endOfStream = case rspn of
@@ -149,7 +149,7 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
149 let payloadOff = off + frameHeaderLength
149 let payloadOff = off + frameHeaderLength
150 Next datPayloadLen mnext <-
150 Next datPayloadLen mnext <-
151 fillFileBodyGetNext conn ii payloadOff lim path mpart
151 fillFileBodyGetNext conn ii payloadOff lim path mpart
152− off' <- fillDataHeader strm off datPayloadLen mnext tell
152+ off' <- fillDataHeader strm off datPayloadLen mnext tell getH2D
153 maybeEnqueueNext out mnext
153 maybeEnqueueNext out mnext
154 return off'
154 return off'
155 RspnBuilder _ _ builder -> do
155 RspnBuilder _ _ builder -> do
@@ -157,24 +157,24 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
157 let payloadOff = off + frameHeaderLength
157 let payloadOff = off + frameHeaderLength
158 Next datPayloadLen mnext <-
158 Next datPayloadLen mnext <-
159 fillBuilderBodyGetNext conn ii payloadOff lim builder
159 fillBuilderBodyGetNext conn ii payloadOff lim builder
160− off' <- fillDataHeader strm off datPayloadLen mnext tell
160+ off' <- fillDataHeader strm off datPayloadLen mnext tell getH2D
161 maybeEnqueueNext out mnext
161 maybeEnqueueNext out mnext
162 return off'
162 return off'
163 RspnStreaming _ _ tbq -> do
163 RspnStreaming _ _ tbq -> do
164 let payloadOff = off + frameHeaderLength
164 let payloadOff = off + frameHeaderLength
165 Next datPayloadLen mnext <-
165 Next datPayloadLen mnext <-
166 fillStreamBodyGetNext conn payloadOff lim tbq strm
166 fillStreamBodyGetNext conn payloadOff lim tbq strm
167− off' <- fillDataHeader strm off datPayloadLen mnext tell
167+ off' <- fillDataHeader strm off datPayloadLen mnext tell getH2D
168 maybeEnqueueNext out mnext
168 maybeEnqueueNext out mnext
169 return off'
169 return off'
171− output (Output strm rspn ii tell (OPush ths pid)) off0 lim = do
171+ output out@(Output strm _ _ _ _ (OPush ths pid)) off0 lim = do
172 -- Creating a push promise header
172 -- Creating a push promise header
173 -- Frame id should be associated stream id from the client.
173 -- Frame id should be associated stream id from the client.
174 let !sid = streamNumber strm
174 let !sid = streamNumber strm
175 len <- pushPromise pid sid ths off0
175 len <- pushPromise pid sid ths off0
176 off <- sendHeadersIfNecessary $ off0 + frameHeaderLength + len
176 off <- sendHeadersIfNecessary $ off0 + frameHeaderLength + len
177− output (Output strm rspn ii tell ORspn) off lim
177+ output out{ outputType = ORspn } off lim
179 output _ _ _ = undefined -- never reach
179 output _ _ _ = undefined -- never reach
@@ -183,9 +183,12 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
183 if isClosed state then
183 if isClosed state then
184 return off
184 return off
185 else case out of
185 else case out of
186− Output strm' rsp ii wait OWait -> do
186+ Output _ _ _ wait _ OWait -> do
187 -- Checking if all push are done.
187 -- Checking if all push are done.
188− let out' = Output strm' rsp ii (return ()) ORspn
188+ let out' = out {
189+ outputHook = return ()
190+ , outputType = ORspn
189 forkAndEnqueueWhenReady wait outputQ out' mgr
192 forkAndEnqueueWhenReady wait outputQ out' mgr
190 return off
193 return off
191 _ -> case mtbq of
194 _ -> case mtbq of
@@ -268,21 +271,36 @@ frameSender ctx@Context{outputQ,controlQ,connectionWindow,encodeDynamicTable}
268 flushN off
271 flushN off
274+ fillDataHeader strm@Stream{streamWindow,streamNumber}
271− fillDataHeader strm off datPayloadLen mnext tell = do
275+ off datPayloadLen mnext tell getH2D = do
272 -- Data frame header
276 -- Data frame header
273− let !sid = streamNumber strm
277+ mh2d <- getH2D
278+ let (!trailers,!noTrailers) = case http2dataTrailers <$> mh2d of
279+ Nothing -> ([], True)
280+ Just ts -> (ts, null ts)
274 !buf = connWriteBuffer `plusPtr` off
281 !buf = connWriteBuffer `plusPtr` off
275 !off' = off + frameHeaderLength + datPayloadLen
282 !off' = off + frameHeaderLength + datPayloadLen
276− !done = isNothing mnext
283+ !noMoreBody = isNothing mnext
277− flag | done = setEndStream defaultFlags
284+ flag | noMoreBody && noTrailers = setEndStream defaultFlags
278− | otherwise = defaultFlags
285+ | otherwise = defaultFlags
279− fillFrameHeader FrameData datPayloadLen sid flag buf
286+ fillFrameHeader FrameData datPayloadLen streamNumber flag buf
280− when done $ do
287+ off'' <- handleEndOfBody noMoreBody off' noTrailers trailers
288+ atomically $ modifyTVar' connectionWindow (subtract datPayloadLen)
289+ atomically $ modifyTVar' streamWindow (subtract datPayloadLen)
292+ handleTrailers True off0 _ = return off0
293+ handleTrailers _ off0 trailers = do
294+ (ths,_) <- toHeaderTable trailers
295+ kvlen <- headerContinue streamNumber ths True off0
296+ sendHeadersIfNecessary $ off0 + frameHeaderLength + kvlen
297+ handleEndOfBody True off0 noTrailers trailers = do
298+ off1 <- handleTrailers noTrailers off0 trailers
281 void $ tell
299 void $ tell
282 closed ctx strm Finished
300 closed ctx strm Finished
283− atomically $ modifyTVar' connectionWindow (subtract datPayloadLen)
301+ return off1
284− atomically $ modifyTVar' (streamWindow strm) (subtract datPayloadLen)
302+ handleEndOfBody False off0 _ _ = return off0
287 pushPromise pid sid ths off = do
305 pushPromise pid sid ths off = do
288 let !offsid = off + frameHeaderLength
306 let !offsid = off + frameHeaderLength