Network.HTTP2

http2-1.6.0: HTTP/2.0 library including frames and HPACK

Safe Haskell | None
Language | Haskell2010

Network.HTTP2

Contents

- Frame
- Encoding
- Decoding
- Decoding payload
- Frame type ID
- Frame type
- Priority
- Stream identifier
- Stream identifier related
- Flags
- SettingsList
- Settings
- Window
- Error code
- Error
- Predefined values

Description

Framing in HTTP/2(https://tools.ietf.org/html/rfc7540).

Synopsis

- data Frame = Frame {
  - frameHeader :: !FrameHeader
  - framePayload :: !FramePayload
  }
- data FrameHeader = FrameHeader {
  - payloadLength :: !Int
  - flags :: !FrameFlags
  - streamId :: !StreamId
  }
- data FramePayload
  - = DataFrame !ByteString
  - | HeadersFrame !(Maybe Priority) !HeaderBlockFragment
  - | PriorityFrame !Priority
  - | RSTStreamFrame !ErrorCodeId
  - | SettingsFrame !SettingsList
  - | PushPromiseFrame !StreamId !HeaderBlockFragment
  - | PingFrame !ByteString
  - | GoAwayFrame !StreamId !ErrorCodeId !ByteString
  - | WindowUpdateFrame !WindowSize
  - | ContinuationFrame !HeaderBlockFragment
  - | UnknownFrame !FrameType !ByteString
- type HeaderBlockFragment = ByteString
- type Padding = ByteString
- isPaddingDefined :: FramePayload -> Bool
- encodeFrame :: EncodeInfo -> FramePayload -> ByteString
- encodeFrameChunks :: EncodeInfo -> FramePayload -> [ByteString]
- encodeFrameHeader :: FrameTypeId -> FrameHeader -> ByteString
- encodeFrameHeaderBuf :: FrameTypeId -> FrameHeader -> Ptr Word8 -> IO ()
- encodeFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, [ByteString])
- data EncodeInfo = EncodeInfo {
  - encodeFlags :: !FrameFlags
  - encodeStreamId :: !StreamId
  - encodePadding :: !(Maybe Padding)
  }
- encodeInfo :: (FrameFlags -> FrameFlags) -> Int -> EncodeInfo
- decodeFrame :: Settings -> ByteString -> Either HTTP2Error Frame
- decodeFrameHeader :: ByteString -> (FrameTypeId, FrameHeader)
- checkFrameHeader :: Settings -> (FrameTypeId, FrameHeader) -> Either HTTP2Error (FrameTypeId, FrameHeader)
- decodeFramePayload :: FrameTypeId -> FramePayloadDecoder
- type FramePayloadDecoder = FrameHeader -> ByteString -> Either HTTP2Error FramePayload
- decodeDataFrame :: FramePayloadDecoder
- decodeHeadersFrame :: FramePayloadDecoder
- decodePriorityFrame :: FramePayloadDecoder
- decoderstStreamFrame :: FramePayloadDecoder
- decodeSettingsFrame :: FramePayloadDecoder
- decodePushPromiseFrame :: FramePayloadDecoder
- decodePingFrame :: FramePayloadDecoder
- decodeGoAwayFrame :: FramePayloadDecoder
- decodeWindowUpdateFrame :: FramePayloadDecoder
- decodeContinuationFrame :: FramePayloadDecoder
- data FrameTypeId
  - = FrameData
  - | FrameHeaders
  - | FramePriority
  - | FrameRSTStream
  - | FrameSettings
  - | FramePushPromise
  - | FramePing
  - | FrameGoAway
  - | FrameWindowUpdate
  - | FrameContinuation
  - | FrameUnknown FrameType
- framePayloadToFrameTypeId :: FramePayload -> FrameTypeId
- type FrameType = Word8
- fromFrameTypeId :: FrameTypeId -> FrameType
- toFrameTypeId :: FrameType -> FrameTypeId
- data Priority = Priority {
  - exclusive :: !Bool
  - streamDependency :: !StreamId
  - weight :: !Weight
  }
- type Weight = Int
- defaultPriority :: Priority
- highestPriority :: Priority
- type StreamId = Int
- isControl :: StreamId -> Bool
- isRequest :: StreamId -> Bool
- isResponse :: StreamId -> Bool
- testExclusive :: StreamId -> Bool
- setExclusive :: StreamId -> StreamId
- clearExclusive :: StreamId -> StreamId
- type FrameFlags = Word8
- defaultFlags :: FrameFlags
- testEndStream :: FrameFlags -> Bool
- testAck :: FrameFlags -> Bool
- testEndHeader :: FrameFlags -> Bool
- testPadded :: FrameFlags -> Bool
- testPriority :: FrameFlags -> Bool
- setEndStream :: FrameFlags -> FrameFlags
- setAck :: FrameFlags -> FrameFlags
- setEndHeader :: FrameFlags -> FrameFlags
- setPadded :: FrameFlags -> FrameFlags
- setPriority :: FrameFlags -> FrameFlags
- type SettingsList = [(SettingsKeyId, SettingsValue)]
- data SettingsKeyId
  - = SettingsHeaderTableSize
  - | SettingsEnablePush
  - | SettingsMaxConcurrentStreams
  - | SettingsInitialWindowSize
  - | SettingsMaxFrameSize
  - | SettingsMaxHeaderBlockSize
- type SettingsValue = Int
- fromSettingsKeyId :: SettingsKeyId -> Word16
- toSettingsKeyId :: Word16 -> Maybe SettingsKeyId
- checkSettingsList :: SettingsList -> Maybe HTTP2Error
- data Settings = Settings {
  - headerTableSize :: !Int
  - enablePush :: !Bool
  - maxConcurrentStreams :: !(Maybe Int)
  - initialWindowSize :: !WindowSize
  - maxFrameSize :: !Int
  - maxHeaderBlockSize :: !(Maybe Int)
  }
- defaultSettings :: Settings
- updateSettings :: Settings -> SettingsList -> Settings
- type WindowSize = Int
- defaultInitialWindowSize :: WindowSize
- maxWindowSize :: WindowSize
- isWindowOverflow :: WindowSize -> Bool
- type ErrorCode = Word32
- data ErrorCodeId
  - = NoError
  - | ProtocolError
  - | InternalError
  - | FlowControlError
  - | SettingsTimeout
  - | StreamClosed
  - | FrameSizeError
  - | RefusedStream
  - | Cancel
  - | CompressionError
  - | ConnectError
  - | EnhanceYourCalm
  - | InadequateSecurity
  - | HTTP11Required
  - | UnknownErrorCode ErrorCode
- fromErrorCodeId :: ErrorCodeId -> ErrorCode
- toErrorCodeId :: ErrorCode -> ErrorCodeId
- data HTTP2Error
  - = ConnectionError !ErrorCodeId !ByteString
  - | StreamError !ErrorCodeId !StreamId
- errorCodeId :: HTTP2Error -> ErrorCodeId
- connectionPreface :: ByteString
- connectionPrefaceLength :: Int
- frameHeaderLength :: Int
- maxPayloadLength :: Int
- recommendedConcurrency :: Int

# Frame

data Frame

The data type for HTTP/2 frames.

Constructors

Frame |
Fields frameHeader :: !FrameHeader framePayload :: !FramePayload

Instances

Eq Frame |
Read Frame |
Show Frame |

data FrameHeader

The data type for HTTP/2 frame headers.

Constructors

FrameHeader |
Fields payloadLength :: !Int flags :: !FrameFlags streamId :: !StreamId

Instances

Eq FrameHeader |
Read FrameHeader |
Show FrameHeader |

data FramePayload

The data type for HTTP/2 frame payloads.

Constructors

DataFrame !ByteString |
HeadersFrame !(Maybe Priority) !HeaderBlockFragment |
PriorityFrame !Priority |
RSTStreamFrame !ErrorCodeId |
SettingsFrame !SettingsList |
PushPromiseFrame !StreamId !HeaderBlockFragment |
PingFrame !ByteString |
GoAwayFrame !StreamId !ErrorCodeId !ByteString |
WindowUpdateFrame !WindowSize |
ContinuationFrame !HeaderBlockFragment |
UnknownFrame !FrameType !ByteString |

Instances

Eq FramePayload |
Read FramePayload |
Show FramePayload |

type HeaderBlockFragment = ByteString

The type for fragments of a header encoded with HPACK.

type Padding = ByteString

The type for padding in payloads.

isPaddingDefined :: FramePayload -> Bool

Checking if padding is defined in this frame type.

    >>> isPaddingDefined $ DataFrame ""
    True
    >>> isPaddingDefined $ PingFrame ""
    False

# Encoding

encodeFrame :: EncodeInfo -> FramePayload -> ByteString

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"

encodeFrameChunks :: EncodeInfo -> FramePayload -> [ByteString]

Encoding an HTTP/2 frame to [`ByteString`]. This is suitable for sendMany.

encodeFrameHeader :: FrameTypeId -> FrameHeader -> ByteString

Encoding an HTTP/2 frame header. The frame header must be completed.

encodeFrameHeaderBuf :: FrameTypeId -> FrameHeader -> Ptr Word8 -> IO ()

Writing an encoded HTTP/2 frame header to the buffer. The length of the buffer must be larger than or equal to 9 bytes.

encodeFramePayload :: EncodeInfo -> FramePayload -> (FrameHeader, [ByteString])

Encoding an HTTP/2 frame payload. This returns a complete frame header and chunks of payload.

data EncodeInfo

Auxiliary information for frame encoding.

Constructors

EncodeInfo |
Fields encodeFlags :: !FrameFlags Flags to be set in a frame header encodeStreamId :: !StreamId Stream id to be set in a frame header 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.

Instances

Read EncodeInfo |
Show EncodeInfo |

encodeInfo

Arguments

:: (FrameFlags -> FrameFlags) |
-> Int | stream identifier
-> EncodeInfo |

A smart builder of `EncodeInfo`.

    >>> encodeInfo setAck 0
    EncodeInfo {encodeFlags = 1, encodeStreamId = 0, encodePadding = Nothing}

# Decoding

decodeFrame

Arguments

:: Settings | HTTP/2 settings
-> ByteString | Input byte-stream
-> Either HTTP2Error Frame | Decoded frame

Decoding an HTTP/2 frame to `ByteString`. The second argument must be include the entire of frame. So, this function is not useful for real applications but useful for testing.

decodeFrameHeader :: ByteString -> (FrameTypeId, FrameHeader)

Decoding an HTTP/2 frame header. Must supply 9 bytes.

checkFrameHeader :: Settings -> (FrameTypeId, FrameHeader) -> Either HTTP2Error (FrameTypeId, FrameHeader)

Checking a frame header and reporting an error if any.

    >>> checkFrameHeader defaultSettings (FrameData,(FrameHeader 100 0 0))
    Left (ConnectionError ProtocolError "cannot used in control stream")

# Decoding payload

decodeFramePayload :: FrameTypeId -> FramePayloadDecoder

Decoding an HTTP/2 frame payload. This function is considered to return a frame payload decoder according to a frame type.

type FramePayloadDecoder = FrameHeader -> ByteString -> Either HTTP2Error FramePayload

The type for frame payload decoder.

decodeDataFrame :: FramePayloadDecoder

Frame payload decoder for DATA frame.

decodeHeadersFrame :: FramePayloadDecoder

Frame payload decoder for HEADERS frame.

decodePriorityFrame :: FramePayloadDecoder

Frame payload decoder for PRIORITY frame.

decoderstStreamFrame :: FramePayloadDecoder

Frame payload decoder for RST_STREAM frame.

decodeSettingsFrame :: FramePayloadDecoder

Frame payload decoder for SETTINGS frame.

decodePushPromiseFrame :: FramePayloadDecoder

Frame payload decoder for PUSH_PROMISE frame.

decodePingFrame :: FramePayloadDecoder

Frame payload decoder for PING frame.

decodeGoAwayFrame :: FramePayloadDecoder

Frame payload decoder for GOAWAY frame.

decodeWindowUpdateFrame :: FramePayloadDecoder

Frame payload decoder for WINDOW_UPDATE frame.

decodeContinuationFrame :: FramePayloadDecoder

Frame payload decoder for CONTINUATION frame.

# Frame type ID

data FrameTypeId

The type for frame type.

Constructors

FrameData |
FrameHeaders |
FramePriority |
FrameRSTStream |
FrameSettings |
FramePushPromise |
FramePing |
FrameGoAway |
FrameWindowUpdate |
FrameContinuation |
FrameUnknown FrameType |

Instances

Eq FrameTypeId |
Ord FrameTypeId |
Show FrameTypeId |

framePayloadToFrameTypeId :: FramePayload -> FrameTypeId

Getting `FrameType` from `FramePayload`.

    >>> framePayloadToFrameTypeId (DataFrame "body")
    FrameData

# Frame type

type FrameType = Word8

The type for raw frame type.

fromFrameTypeId :: FrameTypeId -> FrameType

Converting `FrameTypeId` to `FrameType`.

    >>> fromFrameTypeId FrameData
    0
    >>> fromFrameTypeId FrameContinuation
    9
    >>> fromFrameTypeId (FrameUnknown 10)
    10

toFrameTypeId :: FrameType -> FrameTypeId

Converting `FrameType` to `FrameTypeId`.

    >>> toFrameTypeId 0
    FrameData
    >>> toFrameTypeId 9
    FrameContinuation
    >>> toFrameTypeId 10
    FrameUnknown 10

# Priority

data Priority

Type for stream priority

Constructors

Priority |
Fields exclusive :: !Bool streamDependency :: !StreamId weight :: !Weight

Instances

Eq Priority |
Read Priority |
Show Priority |

type Weight = Int

The type for weight in priority. Its values are from 1 to 256.

defaultPriority :: Priority

Default priority which depends on stream 0.

    >>> defaultPriority
    Priority {exclusive = False, streamDependency = 0, weight = 16}

highestPriority :: Priority

Highest priority which depends on stream 0.

    >>> highestPriority
    Priority {exclusive = False, streamDependency = 0, weight = 256}

# Stream identifier

type StreamId = Int

The type for stream identifier

isControl :: StreamId -> Bool

Checking if the stream identifier for control.

    >>> isControl 0
    True
    >>> isControl 1
    False

isRequest :: StreamId -> Bool

Checking if the stream identifier for request.

    >>> isRequest 0
    False
    >>> isRequest 1
    True

isResponse :: StreamId -> Bool

Checking if the stream identifier for response.

    >>> isResponse 0
    False
    >>> isResponse 2
    True

# Stream identifier related

testExclusive :: StreamId -> Bool

Checking if the exclusive flag is set.

setExclusive :: StreamId -> StreamId

Setting the exclusive flag.

clearExclusive :: StreamId -> StreamId

Clearing the exclusive flag.

# Flags

type FrameFlags = Word8

The type for flags.

defaultFlags :: FrameFlags

The initial value of flags. No flags are set.

    >>> defaultFlags
    0

testEndStream :: FrameFlags -> Bool

Checking if the END_STREAM flag is set. >>> testEndStream 0x1 True

testAck :: FrameFlags -> Bool

Checking if the ACK flag is set. >>> testAck 0x1 True

testEndHeader :: FrameFlags -> Bool

Checking if the END_HEADERS flag is set.

    >>> testEndHeader 0x4
    True

testPadded :: FrameFlags -> Bool

Checking if the PADDED flag is set.

    >>> testPadded 0x8
    True

testPriority :: FrameFlags -> Bool

Checking if the PRIORITY flag is set.

    >>> testPriority 0x20
    True

setEndStream :: FrameFlags -> FrameFlags

Setting the END_STREAM flag.

    >>> setEndStream 0
    1

setAck :: FrameFlags -> FrameFlags

Setting the ACK flag.

    >>> setAck 0
    1

setEndHeader :: FrameFlags -> FrameFlags

Setting the END_HEADERS flag.

    >>> setEndHeader 0
    4

setPadded :: FrameFlags -> FrameFlags

Setting the PADDED flag.

    >>> setPadded 0
    8

setPriority :: FrameFlags -> FrameFlags

Setting the PRIORITY flag.

    >>> setPriority 0
    32

# SettingsList

type SettingsList = [(SettingsKeyId, SettingsValue)]

Association list of SETTINGS.

data SettingsKeyId

The type for SETTINGS key.

Constructors

SettingsHeaderTableSize |
SettingsEnablePush |
SettingsMaxConcurrentStreams |
SettingsInitialWindowSize |
SettingsMaxFrameSize |
SettingsMaxHeaderBlockSize |

Instances

Bounded SettingsKeyId |
Enum SettingsKeyId |
Eq SettingsKeyId |
Ord SettingsKeyId |
Read SettingsKeyId |
Show SettingsKeyId |

type SettingsValue = Int

The type for raw SETTINGS value.

fromSettingsKeyId :: SettingsKeyId -> Word16

Converting `SettingsKeyId` to raw value.

    >>> fromSettingsKeyId SettingsHeaderTableSize
    1
    >>> fromSettingsKeyId SettingsMaxHeaderBlockSize
    6

toSettingsKeyId :: Word16 -> Maybe SettingsKeyId

Converting raw value to `SettingsKeyId`.

    >>> toSettingsKeyId 0
    Nothing
    >>> toSettingsKeyId 1
    Just SettingsHeaderTableSize
    >>> toSettingsKeyId 6
    Just SettingsMaxHeaderBlockSize
    >>> toSettingsKeyId 7
    Nothing

checkSettingsList :: SettingsList -> Maybe HTTP2Error

Checking `SettingsList` and reporting an error if any.

    >>> checkSettingsList [(SettingsEnablePush,2)]
    Just (ConnectionError ProtocolError "enable push must be 0 or 1")

# Settings

data Settings

Cooked version of settings. This is suitable to be stored in a HTTP/2 context.

Constructors

Settings |
Fields headerTableSize :: !Int enablePush :: !Bool maxConcurrentStreams :: !(Maybe Int) initialWindowSize :: !WindowSize maxFrameSize :: !Int maxHeaderBlockSize :: !(Maybe Int)

Instances

Show Settings |

defaultSettings :: Settings

The default settings.

    >>> defaultSettings
    Settings {headerTableSize = 4096, enablePush = True, maxConcurrentStreams = Nothing, initialWindowSize = 65535, maxFrameSize = 16384, maxHeaderBlockSize = Nothing}

updateSettings :: Settings -> SettingsList -> Settings

Updating settings.

    >>> updateSettings defaultSettings [(SettingsEnablePush,0),(SettingsMaxHeaderBlockSize,200)]
    Settings {headerTableSize = 4096, enablePush = False, maxConcurrentStreams = Nothing, initialWindowSize = 65535, maxFrameSize = 16384, maxHeaderBlockSize = Just 200}

# Window

type WindowSize = Int

The type for window size.

defaultInitialWindowSize :: WindowSize

The default initial window size.

    >>> defaultInitialWindowSize
    65535

maxWindowSize :: WindowSize

The maximum window size.

    >>> maxWindowSize
    2147483647

isWindowOverflow :: WindowSize -> Bool

Checking if a window size exceeds the maximum window size.

    >>> isWindowOverflow 10
    False
    >>> isWindowOverflow maxWindowSize
    False
    >>> isWindowOverflow (maxWindowSize + 1)
    True

# Error code

type ErrorCode = Word32

The type for raw error code.

data ErrorCodeId

The type for error code. See https://tools.ietf.org/html/rfc7540#section-7.

Constructors

NoError |
ProtocolError |
InternalError |
FlowControlError |
SettingsTimeout |
StreamClosed |
FrameSizeError |
RefusedStream |
Cancel |
CompressionError |
ConnectError |
EnhanceYourCalm |
InadequateSecurity |
HTTP11Required |
UnknownErrorCode ErrorCode |

Instances

Eq ErrorCodeId |
Ord ErrorCodeId |
Read ErrorCodeId |
Show ErrorCodeId |

fromErrorCodeId :: ErrorCodeId -> ErrorCode

Converting `ErrorCodeId` to `ErrorCode`.

    >>> fromErrorCodeId NoError
    0
    >>> fromErrorCodeId InadequateSecurity
    12

toErrorCodeId :: ErrorCode -> ErrorCodeId

Converting `ErrorCode` to `ErrorCodeId`.

    >>> toErrorCodeId 0
    NoError
    >>> toErrorCodeId 0xc
    InadequateSecurity
    >>> toErrorCodeId 0xe
    UnknownErrorCode 14

# Error

data HTTP2Error

The connection error or the stream error.

Constructors

ConnectionError !ErrorCodeId !ByteString |
StreamError !ErrorCodeId !StreamId |

Instances

Eq HTTP2Error |
Read HTTP2Error |
Show HTTP2Error |
Exception HTTP2Error |

errorCodeId :: HTTP2Error -> ErrorCodeId

Obtaining `ErrorCodeId` from `HTTP2Error`.

# Predefined values

connectionPreface :: ByteString

The preface of HTTP/2.

    >>> connectionPreface
    "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"

connectionPrefaceLength :: Int

Length of the preface.

    >>> connectionPrefaceLength
    24

frameHeaderLength :: Int

The length of HTTP/2 frame header.

    >>> frameHeaderLength
    9

maxPayloadLength :: Int

The maximum length of HTTP/2 payload.

    >>> maxPayloadLength
    16384

recommendedConcurrency :: Int

Default concurrency.

    >>> recommendedConcurrency
    100