module Network.HTTP2.Types (
SettingsKey
, SettingsKeyId(..)
, SettingsValue
, fromSettingsKeyId
, toSettingsKeyId
, Settings(..)
, SettingsList
, defaultSettings
, updateSettings
, ErrorCode
, ErrorCodeId(..)
, fromErrorCodeId
, toErrorCodeId
, FrameType
, FrameTypeId(..)
, fromFrameTypeId
, toFrameTypeId
, Frame(..)
, FrameHeader(..)
, FramePayload(..)
, framePayloadToFrameType
, StreamIdentifier(..)
, StreamDependency
, PromisedStreamId
, LastStreamId
, fromStreamIdentifier
, toStreamIdentifier
, streamIdentifierForSeetings
, testExclusive
, setExclusive
, FrameFlags
, defaultFlags
, testEndStream
, testAck
, testEndHeader
, testPadded
, testPriority
, setEndStream
, setAck
, setEndHeader
, setPadded
, setPriority
, PayloadLength
, maxPayloadLength
, WindowSizeIncrement
, HeaderBlockFragment
, Priority(..)
, Padding
) where
import Data.Array (Ix)
import Data.Bits (setBit, testBit, clearBit)
import Data.ByteString (ByteString)
import Data.Word (Word8, Word16, Word32)
type ErrorCode = Word32
data ErrorCodeId = NoError
| ProtocolError
| InternalError
| FlowControlError
| SettingsTimeout
| StreamClosed
| FrameSizeError
| RefusedStream
| Cancel
| CompressionError
| ConnectError
| EnhanceYourCalm
| InadequateSecurity
| HTTP11Required
| UnknownErrorCode ErrorCode
| UnknownError String
deriving (Show, Read, Eq, Ord)
fromErrorCodeId :: ErrorCodeId -> ErrorCode
fromErrorCodeId NoError = 0x0
fromErrorCodeId ProtocolError = 0x1
fromErrorCodeId InternalError = 0x2
fromErrorCodeId FlowControlError = 0x3
fromErrorCodeId SettingsTimeout = 0x4
fromErrorCodeId StreamClosed = 0x5
fromErrorCodeId FrameSizeError = 0x6
fromErrorCodeId RefusedStream = 0x7
fromErrorCodeId Cancel = 0x8
fromErrorCodeId CompressionError = 0x9
fromErrorCodeId ConnectError = 0xa
fromErrorCodeId EnhanceYourCalm = 0xb
fromErrorCodeId InadequateSecurity = 0xc
fromErrorCodeId HTTP11Required = 0xd
fromErrorCodeId (UnknownErrorCode w) = w
fromErrorCodeId _ = 255
toErrorCodeId :: ErrorCode -> ErrorCodeId
toErrorCodeId 0x0 = NoError
toErrorCodeId 0x1 = ProtocolError
toErrorCodeId 0x2 = InternalError
toErrorCodeId 0x3 = FlowControlError
toErrorCodeId 0x4 = SettingsTimeout
toErrorCodeId 0x5 = StreamClosed
toErrorCodeId 0x6 = FrameSizeError
toErrorCodeId 0x7 = RefusedStream
toErrorCodeId 0x8 = Cancel
toErrorCodeId 0x9 = CompressionError
toErrorCodeId 0xa = ConnectError
toErrorCodeId 0xb = EnhanceYourCalm
toErrorCodeId 0xc = InadequateSecurity
toErrorCodeId 0xd = HTTP11Required
toErrorCodeId w = UnknownErrorCode w
data SettingsKeyId = SettingsHeaderTableSize
| SettingsEnablePush
| SettingsMaxConcurrentStreams
| SettingsInitialWindowSize
| SettingsMaxFrameSize
| SettingsMaxHeaderBlockSize
deriving (Show, Read, Eq, Ord, Enum, Bounded)
type SettingsKey = Word16
type SettingsValue = Int
fromSettingsKeyId :: SettingsKeyId -> Word16
fromSettingsKeyId x = fromIntegral (fromEnum x) + 1
minSettingsKeyId :: Word16
minSettingsKeyId = fromIntegral $ fromEnum (minBound :: SettingsKeyId)
maxSettingsKeyId :: Word16
maxSettingsKeyId = fromIntegral $ fromEnum (maxBound :: SettingsKeyId)
toSettingsKeyId :: Word16 -> Maybe SettingsKeyId
toSettingsKeyId x
| minSettingsKeyId <= n && n <= maxSettingsKeyId = Just . toEnum . fromIntegral $ n
| otherwise = Nothing
where
n = x 1
data Settings = Settings {
headerTableSize :: Int
, establishPush :: Bool
, maxConcurrentStreams :: Int
, initialWindowSize :: Int
, maxFrameSize :: Int
, maxHeaderBlockSize :: Maybe Int
} deriving (Show)
type SettingsList = [(SettingsKeyId,SettingsValue)]
defaultSettings :: Settings
defaultSettings = Settings {
headerTableSize = 4096
, establishPush = True
, maxConcurrentStreams = 100
, initialWindowSize = 65535
, maxFrameSize = 16384
, maxHeaderBlockSize = Nothing
}
updateSettings :: Settings -> SettingsList -> Settings
updateSettings settings kvs = foldr update settings kvs
where
update (SettingsHeaderTableSize,x) def = def { headerTableSize = x }
update (SettingsEnablePush,x) def = def { establishPush = x > 0 }
update (SettingsMaxConcurrentStreams,x) def = def { maxConcurrentStreams = x }
update (SettingsInitialWindowSize,x) def = def { initialWindowSize = x }
update (SettingsMaxFrameSize,x) def = def { maxFrameSize = x }
update (SettingsMaxHeaderBlockSize,x) def = def { maxHeaderBlockSize = Just x }
data Priority = Priority {
exclusive :: Bool
, streamDependency :: StreamIdentifier
, weight :: Int
} deriving (Show, Read, Eq)
type FrameType = Word8
data FrameTypeId = FrameData
| FrameHeaders
| FramePriority
| FrameRSTStream
| FrameSettings
| FramePushPromise
| FramePing
| FrameGoAway
| FrameWindowUpdate
| FrameContinuation
deriving (Show, Eq, Ord, Enum, Bounded, Ix)
fromFrameTypeId :: FrameTypeId -> FrameType
fromFrameTypeId = fromIntegral . fromEnum
minFrameType :: FrameType
minFrameType = fromIntegral $ fromEnum (minBound :: FrameTypeId)
maxFrameType :: FrameType
maxFrameType = fromIntegral $ fromEnum (maxBound :: FrameTypeId)
toFrameTypeId :: FrameType -> Maybe FrameTypeId
toFrameTypeId x
| minFrameType <= x && x <= maxFrameType = Just . toEnum . fromIntegral $ x
| otherwise = Nothing
type PayloadLength = Int
maxPayloadLength :: PayloadLength
maxPayloadLength = 2^(14::Int)
type FrameFlags = Word8
defaultFlags :: FrameFlags
defaultFlags = 0
testEndStream :: FrameFlags -> Bool
testEndStream x = x `testBit` 0
testAck :: FrameFlags -> Bool
testAck x = x `testBit` 0
testEndHeader :: FrameFlags -> Bool
testEndHeader x = x `testBit` 2
testPadded :: FrameFlags -> Bool
testPadded x = x `testBit` 3
testPriority :: FrameFlags -> Bool
testPriority x = x `testBit` 5
setEndStream :: FrameFlags -> FrameFlags
setEndStream x = x `setBit` 0
setAck :: FrameFlags -> FrameFlags
setAck x = x `setBit` 0
setEndHeader :: FrameFlags -> FrameFlags
setEndHeader x = x `setBit` 2
setPadded :: FrameFlags -> FrameFlags
setPadded x = x `setBit` 3
setPriority :: FrameFlags -> FrameFlags
setPriority x = x `setBit` 5
newtype StreamIdentifier = StreamIdentifier Int deriving (Show, Read, Eq)
type StreamDependency = StreamIdentifier
type LastStreamId = StreamIdentifier
type PromisedStreamId = StreamIdentifier
toStreamIdentifier :: Int -> StreamIdentifier
toStreamIdentifier n = StreamIdentifier (n `clearBit` 31)
fromStreamIdentifier :: StreamIdentifier -> Int
fromStreamIdentifier (StreamIdentifier n) = n
testExclusive :: Int -> Bool
testExclusive n = n `testBit` 31
setExclusive :: Int -> Int
setExclusive n = n `setBit` 31
streamIdentifierForSeetings :: StreamIdentifier
streamIdentifierForSeetings = StreamIdentifier 0
type WindowSizeIncrement = Word32
type HeaderBlockFragment = ByteString
type Padding = ByteString
data Frame = Frame
{ frameHeader :: FrameHeader
, framePayload :: FramePayload
} deriving (Show, Read, Eq)
data FrameHeader = FrameHeader
{ payloadLength :: PayloadLength
, flags :: FrameFlags
, streamId :: StreamIdentifier
} deriving (Show, Read, Eq)
data FramePayload =
DataFrame ByteString
| HeadersFrame (Maybe Priority) HeaderBlockFragment
| PriorityFrame Priority
| RSTStreamFrame ErrorCodeId
| SettingsFrame SettingsList
| PushPromiseFrame PromisedStreamId HeaderBlockFragment
| PingFrame ByteString
| GoAwayFrame LastStreamId ErrorCodeId ByteString
| WindowUpdateFrame WindowSizeIncrement
| ContinuationFrame HeaderBlockFragment
| UnknownFrame FrameType ByteString
deriving (Show, Read, Eq)
framePayloadToFrameType :: FramePayload -> FrameType
framePayloadToFrameType (DataFrame _) = fromFrameTypeId FrameData
framePayloadToFrameType (HeadersFrame _ _) = fromFrameTypeId FrameHeaders
framePayloadToFrameType (PriorityFrame _) = fromFrameTypeId FramePriority
framePayloadToFrameType (RSTStreamFrame _) = fromFrameTypeId FrameRSTStream
framePayloadToFrameType (SettingsFrame _) = fromFrameTypeId FrameSettings
framePayloadToFrameType (PushPromiseFrame _ _) = fromFrameTypeId FramePushPromise
framePayloadToFrameType (PingFrame _) = fromFrameTypeId FramePing
framePayloadToFrameType (GoAwayFrame _ _ _) = fromFrameTypeId FrameGoAway
framePayloadToFrameType (WindowUpdateFrame _) = fromFrameTypeId FrameWindowUpdate
framePayloadToFrameType (ContinuationFrame _) = fromFrameTypeId FrameContinuation
framePayloadToFrameType (UnknownFrame w8 _) = w8