@@ -11,12 +11,14 @@ import Control.Concurrent.STM
1111import qualified Control.Exception as E
1212import Control.Monad (unless, void, when)
1313import qualified Data.ByteString as BS
14+import qualified Data.ByteString.Builder as B (int32BE)
1415import qualified Data.ByteString.Builder.Extra as B
16+import Data.Monoid ((<>))
1517import Foreign.Ptr
1618import qualified Network.HTTP.Types as H
1719import Network.HTTP2
1820import Network.HTTP2.Priority
19−import Network.Wai.HTTP2 (Trailers)
21+import Network.Wai.HTTP2 (Trailers, absurd)
2022import Network.Wai.Handler.Warp.Buffer
2123import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
2224import Network.Wai.Handler.Warp.HTTP2.HPACK
@@ -82,7 +84,7 @@ frameSender ctx@Context{outputQ,connectionWindow}
8284 switch (OFrame frame) = do
8385 connSendAll frame
8486 loop
85− switch out@(OResponse strm s h aux) = do
87+ switch (OResponse strm s h aux) = do
8688 unlessClosed ctx conn strm $
8789 getWindowSize connectionWindow (streamWindow strm) >>=
8890 sendResponse strm s h aux
@@ -95,6 +97,18 @@ frameSender ctx@Context{outputQ,connectionWindow}
9597 fillDataHeaderSend strm 0 datPayloadLen mnext
9698 maybeEnqueueNext strm mnext
9799 loop
100+ switch (OPush oldStrm push strm s h aux) = do
101+ unlessClosed ctx conn oldStrm $ do
102+ lim <- getWindowSize connectionWindow (streamWindow strm)
103+ -- Write and send the promise.
104+ builder <- hpackEncodeCIHeaders ctx $ absurd push
105+ off <- pushContinue (streamNumber oldStrm) (streamNumber strm) builder
106+ flushN $ off + frameHeaderLength
107+ -- TODO(awpr): refactor sendResponse to be able to handle non-zero
108+ -- initial offsets and use that to potentially avoid the extra syscall.
109+
110+ sendResponse strm s h aux lim
111+ loop
98112 switch (OTrailers strm []) = do
99113 let flag = setEndStream defaultFlags
100114 fillFrameHeader FrameData 0 (streamNumber strm) flag connWriteBuffer
@@ -141,8 +155,17 @@ frameSender ctx@Context{outputQ,connectionWindow}
141155 maybeEndHeaders B.Done = setEndHeader defaultFlags
142156 maybeEndHeaders _ = defaultFlags
143157
144− -- Write header and possibly continuation frames into the connection
145− -- buffer, using the given builder as their contents.
158+ -- Write PUSH_PROMISE and possibly CONTINUATION frames into the connection
159+ -- buffer, using the given builder as their contents; flush them to the
160+ -- socket as necessary.
161+ pushContinue sid newSid builder = do
162+ let builder' = B.int32BE (fromIntegral newSid) <> builder
163+ (len, signal) <- B.runBuilder builder' bufHeaderPayload headerPayloadLim
164+ let flag = maybeEndHeaders signal
165+ fillFrameHeader FramePushPromise len sid flag connWriteBuffer
166+ continue sid len signal
167+
168+ -- Write HEADER and possibly CONTINUATION frames.
146169 headerContinue sid builder endOfStream = do
147170 (len, signal) <- B.runBuilder builder bufHeaderPayload headerPayloadLim
148171 let flag0 = maybeEndHeaders signal