@@ -134,27 +134,6 @@ frameSender ctx@Context{outputQ,connectionWindow}
134134 sendResponse strm s h aux lim
135135 putMVar mvar pushed
136136 loop
137− switch (OTrailers strm trailers) = do
138− _ <- unlessClosed conn strm $ do
139− -- Trailers always indicate the end of a stream; send them in
140− -- consecutive header+continuation frames and end the stream. Some
141− -- clients dislike empty headers frames, so end the stream with an
142− -- empty data frame instead, as recommended by the spec.
143− toFlush <- case trailers of
144− [] -> frameHeaderLength <$ fillFrameHeader FrameData 0
145− (streamNumber strm)
146− (setEndStream defaultFlags)
147− connWriteBuffer
148− _ -> do
149− builder <- hpackEncodeCIHeaders ctx trailers
150− off <- headerContinue (streamNumber strm) builder True
151− return (off + frameHeaderLength)
152− -- 'closed' must be before 'flushN'. If not, the context would be
153− -- switched to the receiver, resulting in the inconsistency of
154− -- concurrency.
155− closed strm Finished
156− flushN toFlush
157− loop
158137
159138 -- Send the response headers and as much of the response as is immediately
160139 -- available; shared by normal responses and pushed streams.
@@ -177,6 +156,27 @@ frameSender ctx@Context{outputQ,connectionWindow}
177156 when needSend $ flushN off
178157 dispatchNext strm mnext
179158
159+ -- Send the stream's trailers and close the stream.
160+ sendTrailers :: Stream -> Trailers -> IO ()
161+ sendTrailers strm trailers = do
162+ -- Trailers always indicate the end of a stream; send them in
163+ -- consecutive header+continuation frames and end the stream. Some
164+ -- clients dislike empty headers frames, so end the stream with an
165+ -- empty data frame instead, as recommended by the spec.
166+ toFlush <- case trailers of
167+ [] -> frameHeaderLength <$ fillFrameHeader FrameData 0
168+ (streamNumber strm)
169+ (setEndStream defaultFlags)
170+ connWriteBuffer
171+ _ -> do
172+ builder <- hpackEncodeCIHeaders ctx trailers
173+ off <- headerContinue (streamNumber strm) builder True
174+ return (off + frameHeaderLength)
175+ -- 'closed' must be before 'flushN'. If not, the context would be
176+ -- switched to the receiver, resulting in the inconsistency of
177+ -- concurrency.
178+ closed strm Finished
179+ flushN toFlush
180180
181181 -- Flush the connection buffer to the socket, where the first 'n' bytes of
182182 -- the buffer are filled.
@@ -237,14 +237,11 @@ frameSender ctx@Context{outputQ,connectionWindow}
237237 -- This is done after sending any part of the stream body, so it's shared
238238 -- by 'sendResponse' and @switch (ONext ...)@.
239239 dispatchNext :: Stream -> Control DynaNext -> IO ()
240− dispatchNext strm (CNext next) = do
240+ dispatchNext _ CNone = return ()
241+ dispatchNext strm (CFinish trailers) = sendTrailers strm trailers
242+ dispatchNext strm (CNext next) = do
241243 let out = ONext strm next
242244 enqueueOrSpawnTemporaryWaiter strm outputQ out
243− dispatchNext strm (CFinish trailers) = do
244− let out = OTrailers strm trailers
245− pri <- readIORef $ streamPriority strm
246− enqueue outputQ out pri
247− dispatchNext _ _ = return ()
248245
249246
250247 -- Send headers if there is not room for a 1-byte data frame, and return