{-# LANGUAGE RecordWildCards #-}

module Network.HTTP2.Frame.Encode (
    encodeFrame,
    encodeFrameChunks,
    encodeFrameHeader,
    encodeFrameHeaderBuf,
    encodeFramePayload,
    EncodeInfo (..),
    encodeInfo,
) where

import qualified Data.ByteString as BS
import Data.ByteString.Internal (unsafeCreate)
import Foreign.Ptr (Ptr, plusPtr)
import qualified Network.ByteOrder as N
import Network.Control (WindowSize)

import Imports
import Network.HTTP2.Frame.Types

----------------------------------------------------------------

type Builder = [ByteString] -> [ByteString]

-- | Auxiliary information for frame encoding.
data EncodeInfo = EncodeInfo
    { EncodeInfo -> FrameFlags
encodeFlags :: FrameFlags
    -- ^ Flags to be set in a frame header
    , EncodeInfo -> StreamId
encodeStreamId :: StreamId
    -- ^ Stream id to be set in a frame header
    , EncodeInfo -> Maybe Padding
encodePadding :: Maybe Padding
    -- ^ Padding if any. In the case where this value is set but the priority flag is not set, this value gets preference over the priority flag. So, if this value is set, the priority flag is also set.
    }
    deriving (StreamId -> EncodeInfo -> ShowS
[EncodeInfo] -> ShowS
EncodeInfo -> String
forall a.
(StreamId -> a -> ShowS)
-> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EncodeInfo] -> ShowS
$cshowList :: [EncodeInfo] -> ShowS
show :: EncodeInfo -> String
$cshow :: EncodeInfo -> String
showsPrec :: StreamId -> EncodeInfo -> ShowS
$cshowsPrec :: StreamId -> EncodeInfo -> ShowS
Show, ReadPrec [EncodeInfo]
ReadPrec EncodeInfo
StreamId -> ReadS EncodeInfo
ReadS [EncodeInfo]
forall a.
(StreamId -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [EncodeInfo]
$creadListPrec :: ReadPrec [EncodeInfo]
readPrec :: ReadPrec EncodeInfo
$creadPrec :: ReadPrec EncodeInfo
readList :: ReadS [EncodeInfo]
$creadList :: ReadS [EncodeInfo]
readsPrec :: StreamId -> ReadS EncodeInfo
$creadsPrec :: StreamId -> ReadS EncodeInfo
Read)

----------------------------------------------------------------

-- | A smart builder of 'EncodeInfo'.
--
-- >>> encodeInfo setAck 0
-- EncodeInfo {encodeFlags = 1, encodeStreamId = 0, encodePadding = Nothing}
encodeInfo
    :: (FrameFlags -> FrameFlags)
    -> Int
    -- ^ stream identifier
    -> EncodeInfo
encodeInfo :: (FrameFlags -> FrameFlags) -> StreamId -> EncodeInfo
encodeInfo FrameFlags -> FrameFlags
set StreamId
sid = FrameFlags -> StreamId -> Maybe Padding -> EncodeInfo
EncodeInfo (FrameFlags -> FrameFlags
set FrameFlags
defaultFlags) StreamId
sid forall a. Maybe a
Nothing

----------------------------------------------------------------

-- | Encoding an HTTP/2 frame to 'ByteString'.
-- This function is not efficient enough for high performace
-- program because of the concatenation of 'ByteString'.
--
-- >>> encodeFrame (encodeInfo id 1) (DataFrame "body")
-- "\NUL\NUL\EOT\NUL\NUL\NUL\NUL\NUL\SOHbody"
encodeFrame :: EncodeInfo -> FramePayload -> ByteString
encodeFrame :: EncodeInfo -> FramePayload -> Padding
encodeFrame EncodeInfo
einfo FramePayload
payload = [Padding] -> Padding
BS.concat forall a b. (a -> b) -> a -> b
$ EncodeInfo -> FramePayload -> [Padding]
encodeFrameChunks EncodeInfo
einfo FramePayload
payload

-- | Encoding an HTTP/2 frame to ['ByteString'].
--   This is suitable for sendMany.
encodeFrameChunks :: EncodeInfo -> FramePayload -> [ByteString]
encodeFrameChunks :: EncodeInfo -> FramePayload -> [Padding]
encodeFrameChunks EncodeInfo
einfo FramePayload
payload = Padding
bs forall a. a -> [a] -> [a]
: [Padding]
bss
  where
    ftid :: FrameType
ftid = FramePayload -> FrameType
framePayloadToFrameType FramePayload
payload
    bs :: Padding
bs = FrameType -> FrameHeader -> Padding
encodeFrameHeader FrameType
ftid FrameHeader
header
    (FrameHeader
header, [Padding]
bss) = EncodeInfo -> FramePayload -> (FrameHeader, [Padding])
encodeFramePayload EncodeInfo
einfo FramePayload
payload

-- | Encoding an HTTP/2 frame header.
--   The frame header must be completed.
encodeFrameHeader :: FrameType -> FrameHeader -> ByteString
encodeFrameHeader :: FrameType -> FrameHeader -> Padding
encodeFrameHeader FrameType
ftid FrameHeader
fhdr = StreamId -> (Ptr FrameFlags -> IO ()) -> Padding
unsafeCreate StreamId
frameHeaderLength forall a b. (a -> b) -> a -> b
$ FrameType -> FrameHeader -> Ptr FrameFlags -> IO ()
encodeFrameHeaderBuf FrameType
ftid FrameHeader
fhdr

-- | Writing an encoded HTTP/2 frame header to the buffer.
--   The length of the buffer must be larger than or equal to 9 bytes.
encodeFrameHeaderBuf :: FrameType -> FrameHeader -> Ptr Word8 -> IO ()
encodeFrameHeaderBuf :: FrameType -> FrameHeader -> Ptr FrameFlags -> IO ()
encodeFrameHeaderBuf FrameType
ftid FrameHeader{StreamId
FrameFlags
streamId :: FrameHeader -> StreamId
flags :: FrameHeader -> FrameFlags
payloadLength :: FrameHeader -> StreamId
streamId :: StreamId
flags :: FrameFlags
payloadLength :: StreamId
..} Ptr FrameFlags
ptr = do
    Word32 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke24 Word32
plen Ptr FrameFlags
ptr StreamId
0
    FrameFlags -> Ptr FrameFlags -> StreamId -> IO ()
N.poke8 FrameFlags
typ Ptr FrameFlags
ptr StreamId
3
    FrameFlags -> Ptr FrameFlags -> StreamId -> IO ()
N.poke8 FrameFlags
flags Ptr FrameFlags
ptr StreamId
4
    Word32 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke32 Word32
sid Ptr FrameFlags
ptr StreamId
5
  where
    plen :: Word32
plen = forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
payloadLength
    typ :: FrameFlags
typ = FrameType -> FrameFlags
fromFrameType FrameType
ftid
    sid :: Word32
sid = forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
streamId

-- | Encoding an HTTP/2 frame payload.
--   This returns a complete frame header and chunks of payload.
encodeFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, [ByteString])
encodeFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, [Padding])
encodeFramePayload EncodeInfo
einfo FramePayload
payload = (FrameHeader
header, Builder
builder [])
  where
    (FrameHeader
header, Builder
builder) = EncodeInfo -> FramePayload -> (FrameHeader, Builder)
buildFramePayload EncodeInfo
einfo FramePayload
payload

----------------------------------------------------------------

buildFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, Builder)
buildFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, Builder)
buildFramePayload EncodeInfo
einfo (DataFrame Padding
body) =
    EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadData EncodeInfo
einfo Padding
body
buildFramePayload EncodeInfo
einfo (HeadersFrame Maybe Priority
mpri Padding
hdr) =
    EncodeInfo -> Maybe Priority -> Padding -> (FrameHeader, Builder)
buildFramePayloadHeaders EncodeInfo
einfo Maybe Priority
mpri Padding
hdr
buildFramePayload EncodeInfo
einfo (PriorityFrame Priority
pri) =
    EncodeInfo -> Priority -> (FrameHeader, Builder)
buildFramePayloadPriority EncodeInfo
einfo Priority
pri
buildFramePayload EncodeInfo
einfo (RSTStreamFrame ErrorCode
e) =
    EncodeInfo -> ErrorCode -> (FrameHeader, Builder)
buildFramePayloadRSTStream EncodeInfo
einfo ErrorCode
e
buildFramePayload EncodeInfo
einfo (SettingsFrame SettingsList
settings) =
    EncodeInfo -> SettingsList -> (FrameHeader, Builder)
buildFramePayloadSettings EncodeInfo
einfo SettingsList
settings
buildFramePayload EncodeInfo
einfo (PushPromiseFrame StreamId
sid Padding
hdr) =
    EncodeInfo -> StreamId -> Padding -> (FrameHeader, Builder)
buildFramePayloadPushPromise EncodeInfo
einfo StreamId
sid Padding
hdr
buildFramePayload EncodeInfo
einfo (PingFrame Padding
opaque) =
    EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadPing EncodeInfo
einfo Padding
opaque
buildFramePayload EncodeInfo
einfo (GoAwayFrame StreamId
sid ErrorCode
e Padding
debug) =
    EncodeInfo
-> StreamId -> ErrorCode -> Padding -> (FrameHeader, Builder)
buildFramePayloadGoAway EncodeInfo
einfo StreamId
sid ErrorCode
e Padding
debug
buildFramePayload EncodeInfo
einfo (WindowUpdateFrame StreamId
size) =
    EncodeInfo -> StreamId -> (FrameHeader, Builder)
buildFramePayloadWindowUpdate EncodeInfo
einfo StreamId
size
buildFramePayload EncodeInfo
einfo (ContinuationFrame Padding
hdr) =
    EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadContinuation EncodeInfo
einfo Padding
hdr
buildFramePayload EncodeInfo
einfo (UnknownFrame FrameType
_ Padding
opaque) =
    EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadUnknown EncodeInfo
einfo Padding
opaque

----------------------------------------------------------------

buildPadding
    :: EncodeInfo
    -> Builder
    -> Int
    -- ^ Payload length.
    -> (FrameHeader, Builder)
buildPadding :: EncodeInfo -> Builder -> StreamId -> (FrameHeader, Builder)
buildPadding EncodeInfo{encodePadding :: EncodeInfo -> Maybe Padding
encodePadding = Maybe Padding
Nothing, StreamId
FrameFlags
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} Builder
builder StreamId
len =
    (FrameHeader
header, Builder
builder)
  where
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
len FrameFlags
encodeFlags StreamId
encodeStreamId
buildPadding EncodeInfo{encodePadding :: EncodeInfo -> Maybe Padding
encodePadding = Just Padding
padding, StreamId
FrameFlags
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} Builder
btarget StreamId
targetLength =
    (FrameHeader
header, Builder
builder)
  where
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
len FrameFlags
newflags StreamId
encodeStreamId
    builder :: Builder
builder = (Padding
b1 forall a. a -> [a] -> [a]
:) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder
btarget forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Padding
padding forall a. a -> [a] -> [a]
:)
    b1 :: Padding
b1 = FrameFlags -> Padding
BS.singleton forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
paddingLength
    paddingLength :: StreamId
paddingLength = Padding -> StreamId
BS.length Padding
padding
    len :: StreamId
len = StreamId
targetLength forall a. Num a => a -> a -> a
+ StreamId
paddingLength forall a. Num a => a -> a -> a
+ StreamId
1
    newflags :: FrameFlags
newflags = FrameFlags -> FrameFlags
setPadded FrameFlags
encodeFlags

buildPriority :: Priority -> Builder
buildPriority :: Priority -> Builder
buildPriority Priority{Bool
StreamId
weight :: Priority -> StreamId
streamDependency :: Priority -> StreamId
exclusive :: Priority -> Bool
weight :: StreamId
streamDependency :: StreamId
exclusive :: Bool
..} = Builder
builder
  where
    builder :: Builder
builder = (Padding
priority forall a. a -> [a] -> [a]
:)
    estream :: StreamId
estream
        | Bool
exclusive = StreamId -> StreamId
setExclusive StreamId
streamDependency
        | Bool
otherwise = StreamId
streamDependency
    priority :: Padding
priority = StreamId -> (Ptr FrameFlags -> IO ()) -> Padding
unsafeCreate StreamId
5 forall a b. (a -> b) -> a -> b
$ \Ptr FrameFlags
ptr -> do
        let esid :: Word32
esid = forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
estream
            w :: FrameFlags
w = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ StreamId
weight forall a. Num a => a -> a -> a
- StreamId
1
        Word32 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke32 Word32
esid Ptr FrameFlags
ptr StreamId
0
        FrameFlags -> Ptr FrameFlags -> StreamId -> IO ()
N.poke8 FrameFlags
w Ptr FrameFlags
ptr StreamId
4

----------------------------------------------------------------

buildFramePayloadData :: EncodeInfo -> ByteString -> (FrameHeader, Builder)
buildFramePayloadData :: EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadData EncodeInfo
einfo Padding
body = EncodeInfo -> Builder -> StreamId -> (FrameHeader, Builder)
buildPadding EncodeInfo
einfo Builder
builder StreamId
len
  where
    builder :: Builder
builder = (Padding
body forall a. a -> [a] -> [a]
:)
    len :: StreamId
len = Padding -> StreamId
BS.length Padding
body

buildFramePayloadHeaders
    :: EncodeInfo
    -> Maybe Priority
    -> HeaderBlockFragment
    -> (FrameHeader, Builder)
buildFramePayloadHeaders :: EncodeInfo -> Maybe Priority -> Padding -> (FrameHeader, Builder)
buildFramePayloadHeaders EncodeInfo
einfo Maybe Priority
Nothing Padding
hdr =
    EncodeInfo -> Builder -> StreamId -> (FrameHeader, Builder)
buildPadding EncodeInfo
einfo Builder
builder StreamId
len
  where
    builder :: Builder
builder = (Padding
hdr forall a. a -> [a] -> [a]
:)
    len :: StreamId
len = Padding -> StreamId
BS.length Padding
hdr
buildFramePayloadHeaders EncodeInfo
einfo (Just Priority
pri) Padding
hdr =
    EncodeInfo -> Builder -> StreamId -> (FrameHeader, Builder)
buildPadding EncodeInfo
einfo' Builder
builder StreamId
len
  where
    builder :: Builder
builder = Priority -> Builder
buildPriority Priority
pri forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Padding
hdr forall a. a -> [a] -> [a]
:)
    len :: StreamId
len = Padding -> StreamId
BS.length Padding
hdr forall a. Num a => a -> a -> a
+ StreamId
5
    einfo' :: EncodeInfo
einfo' = EncodeInfo
einfo{encodeFlags :: FrameFlags
encodeFlags = FrameFlags -> FrameFlags
setPriority (EncodeInfo -> FrameFlags
encodeFlags EncodeInfo
einfo)}

buildFramePayloadPriority :: EncodeInfo -> Priority -> (FrameHeader, Builder)
buildFramePayloadPriority :: EncodeInfo -> Priority -> (FrameHeader, Builder)
buildFramePayloadPriority EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} Priority
p = (FrameHeader
header, Builder
builder)
  where
    builder :: Builder
builder = Priority -> Builder
buildPriority Priority
p
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
5 FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadRSTStream :: EncodeInfo -> ErrorCode -> (FrameHeader, Builder)
buildFramePayloadRSTStream :: EncodeInfo -> ErrorCode -> (FrameHeader, Builder)
buildFramePayloadRSTStream EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} ErrorCode
e = (FrameHeader
header, Builder
builder)
  where
    builder :: Builder
builder = (Padding
b4 forall a. a -> [a] -> [a]
:)
    b4 :: Padding
b4 = Word32 -> Padding
N.bytestring32 forall a b. (a -> b) -> a -> b
$ ErrorCode -> Word32
fromErrorCode ErrorCode
e
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
4 FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadSettings
    :: EncodeInfo -> SettingsList -> (FrameHeader, Builder)
buildFramePayloadSettings :: EncodeInfo -> SettingsList -> (FrameHeader, Builder)
buildFramePayloadSettings EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} SettingsList
alist = (FrameHeader
header, Builder
builder)
  where
    builder :: Builder
builder = (Padding
settings forall a. a -> [a] -> [a]
:)
    settings :: Padding
settings = StreamId -> (Ptr FrameFlags -> IO ()) -> Padding
unsafeCreate StreamId
len forall a b. (a -> b) -> a -> b
$ \Ptr FrameFlags
ptr -> forall {a}.
Integral a =>
Ptr FrameFlags -> [(SettingsKey, a)] -> IO ()
go Ptr FrameFlags
ptr SettingsList
alist
    go :: Ptr FrameFlags -> [(SettingsKey, a)] -> IO ()
go Ptr FrameFlags
_ [] = forall (m :: * -> *) a. Monad m => a -> m a
return ()
    go Ptr FrameFlags
p ((SettingsKey
k, a
v) : [(SettingsKey, a)]
kvs) = do
        Word16 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke16 (SettingsKey -> Word16
fromSettingsKey SettingsKey
k) Ptr FrameFlags
p StreamId
0
        Word32 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke32 (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
v) Ptr FrameFlags
p StreamId
2
        Ptr FrameFlags -> [(SettingsKey, a)] -> IO ()
go (Ptr FrameFlags
p forall a b. Ptr a -> StreamId -> Ptr b
`plusPtr` StreamId
6) [(SettingsKey, a)]
kvs
    len :: StreamId
len = forall (t :: * -> *) a. Foldable t => t a -> StreamId
length SettingsList
alist forall a. Num a => a -> a -> a
* StreamId
6
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
len FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadPushPromise
    :: EncodeInfo -> StreamId -> HeaderBlockFragment -> (FrameHeader, Builder)
buildFramePayloadPushPromise :: EncodeInfo -> StreamId -> Padding -> (FrameHeader, Builder)
buildFramePayloadPushPromise EncodeInfo
einfo StreamId
sid Padding
hdr = EncodeInfo -> Builder -> StreamId -> (FrameHeader, Builder)
buildPadding EncodeInfo
einfo Builder
builder StreamId
len
  where
    builder :: Builder
builder = (Padding
b4 forall a. a -> [a] -> [a]
:) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Padding
hdr forall a. a -> [a] -> [a]
:)
    b4 :: Padding
b4 = Word32 -> Padding
N.bytestring32 forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
sid
    len :: StreamId
len = StreamId
4 forall a. Num a => a -> a -> a
+ Padding -> StreamId
BS.length Padding
hdr

buildFramePayloadPing :: EncodeInfo -> ByteString -> (FrameHeader, Builder)
buildFramePayloadPing :: EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadPing EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} Padding
odata = (FrameHeader
header, Builder
builder)
  where
    builder :: Builder
builder = (Padding
odata forall a. a -> [a] -> [a]
:)
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
8 FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadGoAway
    :: EncodeInfo -> StreamId -> ErrorCode -> ByteString -> (FrameHeader, Builder)
buildFramePayloadGoAway :: EncodeInfo
-> StreamId -> ErrorCode -> Padding -> (FrameHeader, Builder)
buildFramePayloadGoAway EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} StreamId
sid ErrorCode
e Padding
debug = (FrameHeader
header, Builder
builder)
  where
    builder :: Builder
builder = (Padding
b8 forall a. a -> [a] -> [a]
:) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Padding
debug forall a. a -> [a] -> [a]
:)
    len0 :: StreamId
len0 = StreamId
8
    b8 :: Padding
b8 = StreamId -> (Ptr FrameFlags -> IO ()) -> Padding
unsafeCreate StreamId
len0 forall a b. (a -> b) -> a -> b
$ \Ptr FrameFlags
ptr -> do
        Word32 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke32 (forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
sid) Ptr FrameFlags
ptr StreamId
0
        Word32 -> Ptr FrameFlags -> StreamId -> IO ()
N.poke32 (ErrorCode -> Word32
fromErrorCode ErrorCode
e) Ptr FrameFlags
ptr StreamId
4
    len :: StreamId
len = StreamId
len0 forall a. Num a => a -> a -> a
+ Padding -> StreamId
BS.length Padding
debug
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
len FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadWindowUpdate
    :: EncodeInfo -> WindowSize -> (FrameHeader, Builder)
buildFramePayloadWindowUpdate :: EncodeInfo -> StreamId -> (FrameHeader, Builder)
buildFramePayloadWindowUpdate EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} StreamId
size = (FrameHeader
header, Builder
builder)
  where
    -- fixme: reserve bit
    builder :: Builder
builder = (Padding
b4 forall a. a -> [a] -> [a]
:)
    b4 :: Padding
b4 = Word32 -> Padding
N.bytestring32 forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral StreamId
size
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
4 FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadContinuation
    :: EncodeInfo -> HeaderBlockFragment -> (FrameHeader, Builder)
buildFramePayloadContinuation :: EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadContinuation EncodeInfo{StreamId
Maybe Padding
FrameFlags
encodePadding :: Maybe Padding
encodeStreamId :: StreamId
encodeFlags :: FrameFlags
encodePadding :: EncodeInfo -> Maybe Padding
encodeStreamId :: EncodeInfo -> StreamId
encodeFlags :: EncodeInfo -> FrameFlags
..} Padding
hdr = (FrameHeader
header, Builder
builder)
  where
    builder :: Builder
builder = (Padding
hdr forall a. a -> [a] -> [a]
:)
    len :: StreamId
len = Padding -> StreamId
BS.length Padding
hdr
    header :: FrameHeader
header = StreamId -> FrameFlags -> StreamId -> FrameHeader
FrameHeader StreamId
len FrameFlags
encodeFlags StreamId
encodeStreamId

buildFramePayloadUnknown :: EncodeInfo -> ByteString -> (FrameHeader, Builder)
buildFramePayloadUnknown :: EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadUnknown = EncodeInfo -> Padding -> (FrameHeader, Builder)
buildFramePayloadData