@@ -134,27 +134,6 @@ frameSender ctx@Context{outputQ,connectionWindow}
134 sendResponse strm s h aux lim
134 sendResponse strm s h aux lim
135 putMVar mvar pushed
135 putMVar mvar pushed
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
146− (setEndStream defaultFlags)
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
155− closed strm Finished
159 -- Send the response headers and as much of the response as is immediately
138 -- Send the response headers and as much of the response as is immediately
160 -- available; shared by normal responses and pushed streams.
139 -- available; shared by normal responses and pushed streams.
@@ -177,6 +156,27 @@ frameSender ctx@Context{outputQ,connectionWindow}
177 when needSend $ flushN off
156 when needSend $ flushN off
178 dispatchNext strm mnext
157 dispatchNext strm mnext
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
169+ (setEndStream defaultFlags)
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
178+ closed strm Finished
181 -- Flush the connection buffer to the socket, where the first 'n' bytes of
181 -- Flush the connection buffer to the socket, where the first 'n' bytes of
182 -- the buffer are filled.
182 -- the buffer are filled.
@@ -237,14 +237,11 @@ frameSender ctx@Context{outputQ,connectionWindow}
237 -- This is done after sending any part of the stream body, so it's shared
237 -- This is done after sending any part of the stream body, so it's shared
238 -- by 'sendResponse' and @switch (ONext ...)@.
238 -- by 'sendResponse' and @switch (ONext ...)@.
239 dispatchNext :: Stream -> Control DynaNext -> IO ()
239 dispatchNext :: Stream -> Control DynaNext -> IO ()
240+ dispatchNext _ CNone = return ()
241+ dispatchNext strm (CFinish trailers) = sendTrailers strm trailers
240− dispatchNext strm (CNext next) = do
242+ dispatchNext strm (CNext next) = do
241 let out = ONext strm next
243 let out = ONext strm next
242 enqueueOrSpawnTemporaryWaiter strm outputQ out
244 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 ()
250 -- Send headers if there is not room for a 1-byte data frame, and return
247 -- Send headers if there is not room for a 1-byte data frame, and return