@@ -11,12 +11,14 @@ import Control.Concurrent.STM
11import qualified Control.Exception as E
11import qualified Control.Exception as E
12import Control.Monad (unless, void, when)
12import Control.Monad (unless, void, when)
13import qualified Data.ByteString as BS
13import qualified Data.ByteString as BS
14+import qualified Data.ByteString.Builder as B (int32BE)
14import qualified Data.ByteString.Builder.Extra as B
15import qualified Data.ByteString.Builder.Extra as B
16+import Data.Monoid ((<>))
15import Foreign.Ptr
17import Foreign.Ptr
16import qualified Network.HTTP.Types as H
18import qualified Network.HTTP.Types as H
17import Network.HTTP2
19import Network.HTTP2
18import Network.HTTP2.Priority
20import Network.HTTP2.Priority
19−import Network.Wai.HTTP2 (Trailers)
21+import Network.Wai.HTTP2 (Trailers, absurd)
20import Network.Wai.Handler.Warp.Buffer
22import Network.Wai.Handler.Warp.Buffer
21import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
23import Network.Wai.Handler.Warp.HTTP2.EncodeFrame
22import Network.Wai.Handler.Warp.HTTP2.HPACK
24import Network.Wai.Handler.Warp.HTTP2.HPACK
@@ -82,7 +84,7 @@ frameSender ctx@Context{outputQ,connectionWindow}
82 switch (OFrame frame) = do
84 switch (OFrame frame) = do
83 connSendAll frame
85 connSendAll frame
85− switch out@(OResponse strm s h aux) = do
87+ switch (OResponse strm s h aux) = do
86 unlessClosed ctx conn strm $
88 unlessClosed ctx conn strm $
87 getWindowSize connectionWindow (streamWindow strm) >>=
89 getWindowSize connectionWindow (streamWindow strm) >>=
88 sendResponse strm s h aux
90 sendResponse strm s h aux
@@ -95,6 +97,18 @@ frameSender ctx@Context{outputQ,connectionWindow}
95 fillDataHeaderSend strm 0 datPayloadLen mnext
97 fillDataHeaderSend strm 0 datPayloadLen mnext
96 maybeEnqueueNext strm mnext
98 maybeEnqueueNext strm mnext
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.
110+ sendResponse strm s h aux lim
98 switch (OTrailers strm []) = do
112 switch (OTrailers strm []) = do
99 let flag = setEndStream defaultFlags
113 let flag = setEndStream defaultFlags
100 fillFrameHeader FrameData 0 (streamNumber strm) flag connWriteBuffer
114 fillFrameHeader FrameData 0 (streamNumber strm) flag connWriteBuffer
@@ -141,8 +155,17 @@ frameSender ctx@Context{outputQ,connectionWindow}
141 maybeEndHeaders B.Done = setEndHeader defaultFlags
155 maybeEndHeaders B.Done = setEndHeader defaultFlags
142 maybeEndHeaders _ = defaultFlags
156 maybeEndHeaders _ = defaultFlags
144− -- Write header and possibly continuation frames into the connection
158+ -- Write PUSH_PROMISE and possibly CONTINUATION frames into the connection
145− -- buffer, using the given builder as their contents.
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
168+ -- Write HEADER and possibly CONTINUATION frames.
146 headerContinue sid builder endOfStream = do
169 headerContinue sid builder endOfStream = do
147 (len, signal) <- B.runBuilder builder bufHeaderPayload headerPayloadLim
170 (len, signal) <- B.runBuilder builder bufHeaderPayload headerPayloadLim
148 let flag0 = maybeEndHeaders signal
171 let flag0 = maybeEndHeaders signal