{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE OverloadedStrings #-}
module Network.HTTP2.Client (
runHttp2Client
, newHttp2Client
, withHttp2Stream
, headers
, trailers
, sendData
, Http2Client(..)
, PushPromiseHandler
, StreamDefinition(..)
, StreamStarter
, TooMuchConcurrency(..)
, StreamThread
, Http2Stream(..)
, IncomingFlowControl(..)
, OutgoingFlowControl(..)
, linkAsyncs
, RemoteSentGoAwayFrame(..)
, GoAwayHandler
, defaultGoAwayHandler
, FallBackFrameHandler
, ignoreFallbackHandler
, FlagSetter
, Http2ClientAsyncs(..)
, _gtfo
, StreamEvent(..)
, module Network.HTTP2.Client.FrameConnection
, module Network.HTTP2.Client.Exceptions
, module Network.Socket
, module Network.TLS
) where
import Control.Concurrent.Async.Lifted (Async, async, race, withAsync, link)
import Control.Exception.Lifted (bracket, throwIO, SomeException, catch)
import Control.Concurrent.MVar.Lifted (newEmptyMVar, newMVar, putMVar, takeMVar, tryPutMVar)
import Control.Concurrent.Lifted (threadDelay)
import Control.Monad (forever, void, when, forM_)
import Control.Monad.IO.Class (liftIO)
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import Data.IORef.Lifted (newIORef, atomicModifyIORef', readIORef)
import Data.Maybe (fromMaybe)
import Network.HPACK as HPACK
import Network.HTTP2 as HTTP2
import Network.Socket (HostName, PortNumber)
import Network.TLS (ClientParams)
import Network.HTTP2.Client.Channels
import Network.HTTP2.Client.Dispatch
import Network.HTTP2.Client.Exceptions
import Network.HTTP2.Client.FrameConnection
data IncomingFlowControl = IncomingFlowControl {
IncomingFlowControl -> WindowSize -> IO ()
_addCredit :: WindowSize -> IO ()
, IncomingFlowControl -> WindowSize -> IO WindowSize
_consumeCredit :: WindowSize -> IO Int
, IncomingFlowControl -> ClientIO Bool
_updateWindow :: ClientIO Bool
}
data OutgoingFlowControl = OutgoingFlowControl {
OutgoingFlowControl -> WindowSize -> IO ()
_receiveCredit :: WindowSize -> IO ()
, OutgoingFlowControl -> WindowSize -> ClientIO WindowSize
_withdrawCredit :: WindowSize -> ClientIO WindowSize
}
data StreamDefinition a = StreamDefinition {
StreamDefinition a -> ClientIO StreamThread
_initStream :: ClientIO StreamThread
, StreamDefinition a
-> IncomingFlowControl -> OutgoingFlowControl -> ClientIO a
_handleStream :: IncomingFlowControl -> OutgoingFlowControl -> ClientIO a
}
type StreamStarter a =
(Http2Stream -> StreamDefinition a) -> ClientIO (Either TooMuchConcurrency a)
newtype TooMuchConcurrency = TooMuchConcurrency { TooMuchConcurrency -> WindowSize
_getStreamRoomNeeded :: Int }
deriving WindowSize -> TooMuchConcurrency -> ShowS
[TooMuchConcurrency] -> ShowS
TooMuchConcurrency -> String
(WindowSize -> TooMuchConcurrency -> ShowS)
-> (TooMuchConcurrency -> String)
-> ([TooMuchConcurrency] -> ShowS)
-> Show TooMuchConcurrency
forall a.
(WindowSize -> a -> ShowS)
-> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TooMuchConcurrency] -> ShowS
$cshowList :: [TooMuchConcurrency] -> ShowS
show :: TooMuchConcurrency -> String
$cshow :: TooMuchConcurrency -> String
showsPrec :: WindowSize -> TooMuchConcurrency -> ShowS
$cshowsPrec :: WindowSize -> TooMuchConcurrency -> ShowS
Show
data Http2Client = Http2Client {
Http2Client
-> ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
_ping :: ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
, Http2Client
-> SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_settings :: SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
, Http2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_goaway :: ErrorCodeId -> ByteString -> ClientIO ()
, Http2Client -> forall a. StreamStarter a
_startStream :: forall a. StreamStarter a
, Http2Client -> IncomingFlowControl
_incomingFlowControl :: IncomingFlowControl
, Http2Client -> OutgoingFlowControl
_outgoingFlowControl :: OutgoingFlowControl
, Http2Client -> IO PayloadSplitter
_payloadSplitter :: IO PayloadSplitter
, Http2Client -> Http2ClientAsyncs
_asyncs :: !Http2ClientAsyncs
, Http2Client -> ClientIO ()
_close :: ClientIO ()
}
data InitHttp2Client = InitHttp2Client {
InitHttp2Client
-> ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initPing :: ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
, InitHttp2Client
-> SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initSettings :: SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
, InitHttp2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_initGoaway :: ErrorCodeId -> ByteString -> ClientIO ()
, InitHttp2Client -> forall a. StreamStarter a
_initStartStream :: forall a. StreamStarter a
, InitHttp2Client -> IncomingFlowControl
_initIncomingFlowControl :: IncomingFlowControl
, InitHttp2Client -> OutgoingFlowControl
_initOutgoingFlowControl :: OutgoingFlowControl
, InitHttp2Client -> IO PayloadSplitter
_initPaylodSplitter :: IO PayloadSplitter
, InitHttp2Client -> ClientIO ()
_initClose :: ClientIO ()
, InitHttp2Client -> ClientIO Bool
_initStop :: ClientIO Bool
}
data Http2ClientAsyncs = Http2ClientAsyncs {
Http2ClientAsyncs
-> Async (Either ClientError (FrameHeader, FramePayload))
_waitSettingsAsync :: Async (Either ClientError (FrameHeader, FramePayload))
, Http2ClientAsyncs -> Async (Either ClientError ())
_incomingFramesAsync :: Async (Either ClientError ())
}
linkAsyncs :: Http2Client -> ClientIO ()
linkAsyncs :: Http2Client -> ClientIO ()
linkAsyncs Http2Client
client =
let Http2ClientAsyncs{Async (Either ClientError ())
Async (Either ClientError (FrameHeader, FramePayload))
_incomingFramesAsync :: Async (Either ClientError ())
_waitSettingsAsync :: Async (Either ClientError (FrameHeader, FramePayload))
_incomingFramesAsync :: Http2ClientAsyncs -> Async (Either ClientError ())
_waitSettingsAsync :: Http2ClientAsyncs
-> Async (Either ClientError (FrameHeader, FramePayload))
..} = Http2Client -> Http2ClientAsyncs
_asyncs Http2Client
client in do
Async (Either ClientError (FrameHeader, FramePayload))
-> ClientIO ()
forall (m :: * -> *) a. MonadBase IO m => Async a -> m ()
link Async (Either ClientError (FrameHeader, FramePayload))
_waitSettingsAsync
Async (Either ClientError ()) -> ClientIO ()
forall (m :: * -> *) a. MonadBase IO m => Async a -> m ()
link Async (Either ClientError ())
_incomingFramesAsync
_gtfo :: Http2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_gtfo :: Http2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_gtfo = Http2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_goaway
data StreamThread = CST
data Http2Stream = Http2Stream {
:: HPACK.HeaderList
-> (FrameFlags -> FrameFlags)
-> ClientIO StreamThread
, Http2Stream -> Priority -> ClientIO ()
_prio :: Priority -> ClientIO ()
, Http2Stream -> ErrorCodeId -> ClientIO ()
_rst :: ErrorCodeId -> ClientIO ()
, Http2Stream -> ClientIO StreamEvent
_waitEvent :: ClientIO StreamEvent
, Http2Stream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
_sendDataChunk :: (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
, Http2Stream
-> WindowSize -> HeaderList -> PushPromiseHandler -> ClientIO ()
_handlePushPromise :: StreamId -> HeaderList -> PushPromiseHandler -> ClientIO ()
}
trailers :: Http2Stream -> HPACK.HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO ()
trailers :: Http2Stream
-> HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO ()
trailers Http2Stream
stream HeaderList
hdrs FrameFlags -> FrameFlags
flagmod = ClientIO StreamThread -> ClientIO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ClientIO StreamThread -> ClientIO ())
-> ClientIO StreamThread -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ Http2Stream
-> HeaderList
-> (FrameFlags -> FrameFlags)
-> ClientIO StreamThread
_headers Http2Stream
stream HeaderList
hdrs FrameFlags -> FrameFlags
flagmod
type PushPromiseHandler =
StreamId -> Http2Stream -> HeaderList -> IncomingFlowControl -> OutgoingFlowControl -> ClientIO ()
withHttp2Stream :: Http2Client -> StreamStarter a
withHttp2Stream :: Http2Client -> StreamStarter a
withHttp2Stream = Http2Client -> StreamStarter a
Http2Client -> forall a. StreamStarter a
_startStream
type FlagSetter = FrameFlags -> FrameFlags
headers :: Http2Stream -> HeaderList -> FlagSetter -> ClientIO StreamThread
= Http2Stream
-> HeaderList
-> (FrameFlags -> FrameFlags)
-> ClientIO StreamThread
_headers
runHttp2Client
:: Http2FrameConnection
-> Int
-> Int
-> SettingsList
-> GoAwayHandler
-> FallBackFrameHandler
-> (Http2Client -> ClientIO a)
-> ClientIO a
runHttp2Client :: Http2FrameConnection
-> WindowSize
-> WindowSize
-> SettingsList
-> GoAwayHandler
-> FallBackFrameHandler
-> (Http2Client -> ClientIO a)
-> ClientIO a
runHttp2Client Http2FrameConnection
conn WindowSize
encoderBufSize WindowSize
decoderBufSize SettingsList
initSettings GoAwayHandler
goAwayHandler FallBackFrameHandler
fallbackHandler Http2Client -> ClientIO a
mainHandler = do
(ClientIO ()
incomingLoop, InitHttp2Client
initClient) <- Http2FrameConnection
-> WindowSize
-> WindowSize
-> GoAwayHandler
-> FallBackFrameHandler
-> ClientIO (ClientIO (), InitHttp2Client)
initHttp2Client Http2FrameConnection
conn WindowSize
encoderBufSize WindowSize
decoderBufSize GoAwayHandler
goAwayHandler FallBackFrameHandler
fallbackHandler
ClientIO ()
-> (Async (StM (ExceptT ClientError IO) ()) -> ClientIO a)
-> ClientIO a
forall (m :: * -> *) a b.
MonadBaseControl IO m =>
m a -> (Async (StM m a) -> m b) -> m b
withAsync ClientIO ()
incomingLoop ((Async (StM (ExceptT ClientError IO) ()) -> ClientIO a)
-> ClientIO a)
-> (Async (StM (ExceptT ClientError IO) ()) -> ClientIO a)
-> ClientIO a
forall a b. (a -> b) -> a -> b
$ \Async (StM (ExceptT ClientError IO) ())
aIncoming -> do
ClientIO (FrameHeader, FramePayload)
settsIO <- InitHttp2Client
-> SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initSettings InitHttp2Client
initClient SettingsList
initSettings
ClientIO (FrameHeader, FramePayload)
-> (Async
(StM (ExceptT ClientError IO) (FrameHeader, FramePayload))
-> ClientIO a)
-> ClientIO a
forall (m :: * -> *) a b.
MonadBaseControl IO m =>
m a -> (Async (StM m a) -> m b) -> m b
withAsync ClientIO (FrameHeader, FramePayload)
settsIO ((Async (StM (ExceptT ClientError IO) (FrameHeader, FramePayload))
-> ClientIO a)
-> ClientIO a)
-> (Async
(StM (ExceptT ClientError IO) (FrameHeader, FramePayload))
-> ClientIO a)
-> ClientIO a
forall a b. (a -> b) -> a -> b
$ \Async (StM (ExceptT ClientError IO) (FrameHeader, FramePayload))
aSettings -> do
let client :: Http2Client
client = Http2Client :: (ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload)))
-> (SettingsList
-> ClientIO (ClientIO (FrameHeader, FramePayload)))
-> (ErrorCodeId -> ByteString -> ClientIO ())
-> (forall a. StreamStarter a)
-> IncomingFlowControl
-> OutgoingFlowControl
-> IO PayloadSplitter
-> Http2ClientAsyncs
-> ClientIO ()
-> Http2Client
Http2Client {
_settings :: SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_settings = InitHttp2Client
-> SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initSettings InitHttp2Client
initClient
, _ping :: ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
_ping = InitHttp2Client
-> ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initPing InitHttp2Client
initClient
, _goaway :: ErrorCodeId -> ByteString -> ClientIO ()
_goaway = InitHttp2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_initGoaway InitHttp2Client
initClient
, _close :: ClientIO ()
_close =
InitHttp2Client -> ClientIO Bool
_initStop InitHttp2Client
initClient ClientIO Bool -> ClientIO () -> ClientIO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> InitHttp2Client -> ClientIO ()
_initClose InitHttp2Client
initClient
, _startStream :: forall a. StreamStarter a
_startStream = InitHttp2Client -> forall a. StreamStarter a
_initStartStream InitHttp2Client
initClient
, _incomingFlowControl :: IncomingFlowControl
_incomingFlowControl = InitHttp2Client -> IncomingFlowControl
_initIncomingFlowControl InitHttp2Client
initClient
, _outgoingFlowControl :: OutgoingFlowControl
_outgoingFlowControl = InitHttp2Client -> OutgoingFlowControl
_initOutgoingFlowControl InitHttp2Client
initClient
, _payloadSplitter :: IO PayloadSplitter
_payloadSplitter = InitHttp2Client -> IO PayloadSplitter
_initPaylodSplitter InitHttp2Client
initClient
, _asyncs :: Http2ClientAsyncs
_asyncs = Async (Either ClientError (FrameHeader, FramePayload))
-> Async (Either ClientError ()) -> Http2ClientAsyncs
Http2ClientAsyncs Async (Either ClientError (FrameHeader, FramePayload))
Async (StM (ExceptT ClientError IO) (FrameHeader, FramePayload))
aSettings Async (Either ClientError ())
Async (StM (ExceptT ClientError IO) ())
aIncoming
}
Http2Client -> ClientIO ()
linkAsyncs Http2Client
client
a
ret <- Http2Client -> ClientIO a
mainHandler Http2Client
client
Http2Client -> ClientIO ()
_close Http2Client
client
a -> ClientIO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
ret
newHttp2Client
:: Http2FrameConnection
-> Int
-> Int
-> SettingsList
-> GoAwayHandler
-> FallBackFrameHandler
-> ClientIO Http2Client
newHttp2Client :: Http2FrameConnection
-> WindowSize
-> WindowSize
-> SettingsList
-> GoAwayHandler
-> FallBackFrameHandler
-> ClientIO Http2Client
newHttp2Client Http2FrameConnection
conn WindowSize
encoderBufSize WindowSize
decoderBufSize SettingsList
initSettings GoAwayHandler
goAwayHandler FallBackFrameHandler
fallbackHandler = do
(ClientIO ()
incomingLoop, InitHttp2Client
initClient) <- Http2FrameConnection
-> WindowSize
-> WindowSize
-> GoAwayHandler
-> FallBackFrameHandler
-> ClientIO (ClientIO (), InitHttp2Client)
initHttp2Client Http2FrameConnection
conn WindowSize
encoderBufSize WindowSize
decoderBufSize GoAwayHandler
goAwayHandler FallBackFrameHandler
fallbackHandler
Async (Either ClientError ())
aIncoming <- ClientIO ()
-> ExceptT ClientError IO (Async (StM (ExceptT ClientError IO) ()))
forall (m :: * -> *) a.
MonadBaseControl IO m =>
m a -> m (Async (StM m a))
async ClientIO ()
incomingLoop
ClientIO (FrameHeader, FramePayload)
settsIO <- InitHttp2Client
-> SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initSettings InitHttp2Client
initClient SettingsList
initSettings
Async (Either ClientError (FrameHeader, FramePayload))
aSettings <- ClientIO (FrameHeader, FramePayload)
-> ExceptT
ClientError
IO
(Async (StM (ExceptT ClientError IO) (FrameHeader, FramePayload)))
forall (m :: * -> *) a.
MonadBaseControl IO m =>
m a -> m (Async (StM m a))
async ClientIO (FrameHeader, FramePayload)
settsIO
Http2Client -> ClientIO Http2Client
forall (m :: * -> *) a. Monad m => a -> m a
return (Http2Client -> ClientIO Http2Client)
-> Http2Client -> ClientIO Http2Client
forall a b. (a -> b) -> a -> b
$ Http2Client :: (ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload)))
-> (SettingsList
-> ClientIO (ClientIO (FrameHeader, FramePayload)))
-> (ErrorCodeId -> ByteString -> ClientIO ())
-> (forall a. StreamStarter a)
-> IncomingFlowControl
-> OutgoingFlowControl
-> IO PayloadSplitter
-> Http2ClientAsyncs
-> ClientIO ()
-> Http2Client
Http2Client {
_settings :: SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_settings = InitHttp2Client
-> SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initSettings InitHttp2Client
initClient
, _ping :: ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
_ping = InitHttp2Client
-> ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initPing InitHttp2Client
initClient
, _goaway :: ErrorCodeId -> ByteString -> ClientIO ()
_goaway = InitHttp2Client -> ErrorCodeId -> ByteString -> ClientIO ()
_initGoaway InitHttp2Client
initClient
, _close :: ClientIO ()
_close =
InitHttp2Client -> ClientIO Bool
_initStop InitHttp2Client
initClient ClientIO Bool -> ClientIO () -> ClientIO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> InitHttp2Client -> ClientIO ()
_initClose InitHttp2Client
initClient
, _startStream :: forall a. StreamStarter a
_startStream = InitHttp2Client -> forall a. StreamStarter a
_initStartStream InitHttp2Client
initClient
, _incomingFlowControl :: IncomingFlowControl
_incomingFlowControl = InitHttp2Client -> IncomingFlowControl
_initIncomingFlowControl InitHttp2Client
initClient
, _outgoingFlowControl :: OutgoingFlowControl
_outgoingFlowControl = InitHttp2Client -> OutgoingFlowControl
_initOutgoingFlowControl InitHttp2Client
initClient
, _payloadSplitter :: IO PayloadSplitter
_payloadSplitter = InitHttp2Client -> IO PayloadSplitter
_initPaylodSplitter InitHttp2Client
initClient
, _asyncs :: Http2ClientAsyncs
_asyncs = Async (Either ClientError (FrameHeader, FramePayload))
-> Async (Either ClientError ()) -> Http2ClientAsyncs
Http2ClientAsyncs Async (Either ClientError (FrameHeader, FramePayload))
aSettings Async (Either ClientError ())
aIncoming
}
initHttp2Client
:: Http2FrameConnection
-> Int
-> Int
-> GoAwayHandler
-> FallBackFrameHandler
-> ClientIO (ClientIO (), InitHttp2Client)
initHttp2Client :: Http2FrameConnection
-> WindowSize
-> WindowSize
-> GoAwayHandler
-> FallBackFrameHandler
-> ClientIO (ClientIO (), InitHttp2Client)
initHttp2Client Http2FrameConnection
conn WindowSize
encoderBufSize WindowSize
decoderBufSize GoAwayHandler
goAwayHandler FallBackFrameHandler
fallbackHandler = do
let controlStream :: Http2FrameClientStream
controlStream = Http2FrameConnection -> WindowSize -> Http2FrameClientStream
makeFrameClientStream Http2FrameConnection
conn WindowSize
0
let ackPing :: ByteString -> ClientIO ()
ackPing = Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
sendPingFrame Http2FrameClientStream
controlStream FrameFlags -> FrameFlags
HTTP2.setAck
let ackSettings :: ClientIO ()
ackSettings = Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> SettingsList -> ClientIO ()
sendSettingsFrame Http2FrameClientStream
controlStream FrameFlags -> FrameFlags
HTTP2.setAck []
Dispatch
dispatch <- ExceptT ClientError IO Dispatch
forall (m :: * -> *). MonadBase IO m => m Dispatch
newDispatchIO
DispatchControl
dispatchControl <- WindowSize
-> (ByteString -> ClientIO ())
-> ClientIO ()
-> GoAwayHandler
-> FallBackFrameHandler
-> ExceptT ClientError IO DispatchControl
forall (m :: * -> *).
MonadBase IO m =>
WindowSize
-> (ByteString -> ClientIO ())
-> ClientIO ()
-> GoAwayHandler
-> FallBackFrameHandler
-> m DispatchControl
newDispatchControlIO WindowSize
encoderBufSize
ByteString -> ClientIO ()
ackPing
ClientIO ()
ackSettings
GoAwayHandler
goAwayHandler
FallBackFrameHandler
fallbackHandler
let baseIncomingWindowSize :: IO WindowSize
baseIncomingWindowSize = Settings -> WindowSize
initialWindowSize (Settings -> WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_clientSettings (ConnectionSettings -> WindowSize)
-> IO ConnectionSettings -> IO WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
dispatchControl
baseOutgoingWindowSize :: IO WindowSize
baseOutgoingWindowSize = Settings -> WindowSize
initialWindowSize (Settings -> WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_serverSettings (ConnectionSettings -> WindowSize)
-> IO ConnectionSettings -> IO WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
dispatchControl
IncomingFlowControl
_initIncomingFlowControl <- IO IncomingFlowControl
-> ExceptT ClientError IO IncomingFlowControl
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO IncomingFlowControl
-> ExceptT ClientError IO IncomingFlowControl)
-> IO IncomingFlowControl
-> ExceptT ClientError IO IncomingFlowControl
forall a b. (a -> b) -> a -> b
$ DispatchControl
-> IO WindowSize
-> (WindowSize -> ClientIO ())
-> IO IncomingFlowControl
newIncomingFlowControl DispatchControl
dispatchControl IO WindowSize
baseIncomingWindowSize (Http2FrameClientStream -> WindowSize -> ClientIO ()
sendWindowUpdateFrame Http2FrameClientStream
controlStream)
Chan (FrameHeader, FramePayload)
windowUpdatesChan <- ExceptT ClientError IO (Chan (FrameHeader, FramePayload))
forall (m :: * -> *) a. MonadBase IO m => m (Chan a)
newChan
OutgoingFlowControl
_initOutgoingFlowControl <- IO OutgoingFlowControl
-> ExceptT ClientError IO OutgoingFlowControl
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO OutgoingFlowControl
-> ExceptT ClientError IO OutgoingFlowControl)
-> IO OutgoingFlowControl
-> ExceptT ClientError IO OutgoingFlowControl
forall a b. (a -> b) -> a -> b
$ DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IO WindowSize
-> IO OutgoingFlowControl
newOutgoingFlowControl DispatchControl
dispatchControl Chan (FrameHeader, FramePayload)
windowUpdatesChan IO WindowSize
baseOutgoingWindowSize
DispatchHPACK
dispatchHPACK <- WindowSize -> ExceptT ClientError IO DispatchHPACK
forall (m :: * -> *).
MonadBase IO m =>
WindowSize -> m DispatchHPACK
newDispatchHPACKIO WindowSize
decoderBufSize
(ClientIO ()
incomingLoop,ClientIO Bool
endIncomingLoop) <- Http2FrameConnection
-> Dispatch
-> DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IncomingFlowControl
-> DispatchHPACK
-> ClientIO (ClientIO (), ClientIO Bool)
dispatchLoop Http2FrameConnection
conn Dispatch
dispatch DispatchControl
dispatchControl Chan (FrameHeader, FramePayload)
windowUpdatesChan IncomingFlowControl
_initIncomingFlowControl DispatchHPACK
dispatchHPACK
IORef WindowSize
conccurentStreams <- WindowSize -> ExceptT ClientError IO (IORef WindowSize)
forall (m :: * -> *) a. MonadBase IO m => a -> m (IORef a)
newIORef WindowSize
0
MVar WindowSize
clientStreamIdMutex <- WindowSize -> ExceptT ClientError IO (MVar WindowSize)
forall (m :: * -> *) a. MonadBase IO m => a -> m (MVar a)
newMVar WindowSize
0
let withClientStreamId :: (WindowSize -> m c) -> m c
withClientStreamId WindowSize -> m c
h = m WindowSize -> (WindowSize -> m ()) -> (WindowSize -> m c) -> m c
forall (m :: * -> *) a b c.
MonadBaseControl IO m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracket (MVar WindowSize -> m WindowSize
forall (m :: * -> *) a. MonadBase IO m => MVar a -> m a
takeMVar MVar WindowSize
clientStreamIdMutex)
(MVar WindowSize -> WindowSize -> m ()
forall (m :: * -> *) a. MonadBase IO m => MVar a -> a -> m ()
putMVar MVar WindowSize
clientStreamIdMutex (WindowSize -> m ())
-> (WindowSize -> WindowSize) -> WindowSize -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WindowSize -> WindowSize
forall a. Enum a => a -> a
succ)
(\WindowSize
k -> WindowSize -> m c
h (WindowSize
2 WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
* WindowSize
k WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
1))
let _initStartStream :: (Http2Stream -> StreamDefinition b)
-> ExceptT ClientError IO (Either TooMuchConcurrency b)
_initStartStream Http2Stream -> StreamDefinition b
getWork = do
WindowSize
maxConcurrency <- WindowSize -> Maybe WindowSize -> WindowSize
forall a. a -> Maybe a -> a
fromMaybe WindowSize
100 (Maybe WindowSize -> WindowSize)
-> (ConnectionSettings -> Maybe WindowSize)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Settings -> Maybe WindowSize
maxConcurrentStreams (Settings -> Maybe WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> Maybe WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_serverSettings (ConnectionSettings -> WindowSize)
-> ExceptT ClientError IO ConnectionSettings -> ClientIO WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> ExceptT ClientError IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
dispatchControl
WindowSize
roomNeeded <- IORef WindowSize
-> (WindowSize -> (WindowSize, WindowSize)) -> ClientIO WindowSize
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef WindowSize
conccurentStreams
(\WindowSize
n -> if WindowSize
n WindowSize -> WindowSize -> Bool
forall a. Ord a => a -> a -> Bool
< WindowSize
maxConcurrency then (WindowSize
n WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
1, WindowSize
0) else (WindowSize
n, WindowSize
1 WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
n WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
- WindowSize
maxConcurrency))
if WindowSize
roomNeeded WindowSize -> WindowSize -> Bool
forall a. Ord a => a -> a -> Bool
> WindowSize
0
then
Either TooMuchConcurrency b
-> ExceptT ClientError IO (Either TooMuchConcurrency b)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either TooMuchConcurrency b
-> ExceptT ClientError IO (Either TooMuchConcurrency b))
-> Either TooMuchConcurrency b
-> ExceptT ClientError IO (Either TooMuchConcurrency b)
forall a b. (a -> b) -> a -> b
$ TooMuchConcurrency -> Either TooMuchConcurrency b
forall a b. a -> Either a b
Left (TooMuchConcurrency -> Either TooMuchConcurrency b)
-> TooMuchConcurrency -> Either TooMuchConcurrency b
forall a b. (a -> b) -> a -> b
$ WindowSize -> TooMuchConcurrency
TooMuchConcurrency WindowSize
roomNeeded
else b -> Either TooMuchConcurrency b
forall a b. b -> Either a b
Right (b -> Either TooMuchConcurrency b)
-> ExceptT ClientError IO b
-> ExceptT ClientError IO (Either TooMuchConcurrency b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
Chan (FrameHeader, FramePayload)
windowUpdatesChan <- ExceptT ClientError IO (Chan (FrameHeader, FramePayload))
forall (m :: * -> *) a. MonadBase IO m => m (Chan a)
newChan
ExceptT ClientError IO b
cont <- (WindowSize -> ExceptT ClientError IO (ExceptT ClientError IO b))
-> ExceptT ClientError IO (ExceptT ClientError IO b)
forall (m :: * -> *) c.
MonadBaseControl IO m =>
(WindowSize -> m c) -> m c
withClientStreamId ((WindowSize -> ExceptT ClientError IO (ExceptT ClientError IO b))
-> ExceptT ClientError IO (ExceptT ClientError IO b))
-> (WindowSize
-> ExceptT ClientError IO (ExceptT ClientError IO b))
-> ExceptT ClientError IO (ExceptT ClientError IO b)
forall a b. (a -> b) -> a -> b
$ \WindowSize
sid -> do
DispatchStream
dispatchStream <- WindowSize -> ExceptT ClientError IO DispatchStream
forall (m :: * -> *).
MonadBase IO m =>
WindowSize -> m DispatchStream
newDispatchStreamIO WindowSize
sid
Http2FrameConnection
-> Dispatch
-> DispatchControl
-> DispatchStream
-> Chan (FrameHeader, FramePayload)
-> (Http2Stream -> StreamDefinition b)
-> StreamFSMState
-> ExceptT ClientError IO (ExceptT ClientError IO b)
forall a.
Http2FrameConnection
-> Dispatch
-> DispatchControl
-> DispatchStream
-> Chan (FrameHeader, FramePayload)
-> (Http2Stream -> StreamDefinition a)
-> StreamFSMState
-> ClientIO (ClientIO a)
initializeStream Http2FrameConnection
conn
Dispatch
dispatch
DispatchControl
dispatchControl
DispatchStream
dispatchStream
Chan (FrameHeader, FramePayload)
windowUpdatesChan
Http2Stream -> StreamDefinition b
getWork
StreamFSMState
Idle
b
v <- ExceptT ClientError IO b
cont
IORef WindowSize -> (WindowSize -> (WindowSize, ())) -> ClientIO ()
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef WindowSize
conccurentStreams (\WindowSize
n -> (WindowSize
n WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
- WindowSize
1, ()))
b -> ExceptT ClientError IO b
forall (f :: * -> *) a. Applicative f => a -> f a
pure b
v
let _initPing :: ByteString
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
_initPing ByteString
dat = do
PingHandler
handler <- IO PingHandler -> ExceptT ClientError IO PingHandler
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO PingHandler -> ExceptT ClientError IO PingHandler)
-> IO PingHandler -> ExceptT ClientError IO PingHandler
forall a b. (a -> b) -> a -> b
$ DispatchControl -> ByteString -> IO PingHandler
registerPingHandler DispatchControl
dispatchControl ByteString
dat
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
sendPingFrame Http2FrameClientStream
controlStream FrameFlags -> FrameFlags
forall a. a -> a
id ByteString
dat
t m (FrameHeader, FramePayload)
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
forall (m :: * -> *) a. Monad m => a -> m a
return (t m (FrameHeader, FramePayload)
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload)))
-> t m (FrameHeader, FramePayload)
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
forall a b. (a -> b) -> a -> b
$ m (FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload))
-> m (FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload)
forall a b. (a -> b) -> a -> b
$ PingHandler -> m (FrameHeader, FramePayload)
forall (m :: * -> *).
MonadBase IO m =>
PingHandler -> m (FrameHeader, FramePayload)
waitPingReply PingHandler
handler
let _initSettings :: SettingsList
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
_initSettings SettingsList
settslist = do
SetSettingsHandler
handler <- IO SetSettingsHandler -> ExceptT ClientError IO SetSettingsHandler
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO SetSettingsHandler
-> ExceptT ClientError IO SetSettingsHandler)
-> IO SetSettingsHandler
-> ExceptT ClientError IO SetSettingsHandler
forall a b. (a -> b) -> a -> b
$ DispatchControl -> IO SetSettingsHandler
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m SetSettingsHandler
registerSetSettingsHandler DispatchControl
dispatchControl
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> SettingsList -> ClientIO ()
sendSettingsFrame Http2FrameClientStream
controlStream FrameFlags -> FrameFlags
forall a. a -> a
id SettingsList
settslist
t m (FrameHeader, FramePayload)
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
forall (m :: * -> *) a. Monad m => a -> m a
return (t m (FrameHeader, FramePayload)
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload)))
-> t m (FrameHeader, FramePayload)
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
forall a b. (a -> b) -> a -> b
$ do
(FrameHeader, FramePayload)
ret <- m (FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload))
-> m (FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload)
forall a b. (a -> b) -> a -> b
$ SetSettingsHandler -> m (FrameHeader, FramePayload)
forall (m :: * -> *).
MonadBase IO m =>
SetSettingsHandler -> m (FrameHeader, FramePayload)
waitSetSettingsReply SetSettingsHandler
handler
DispatchControl
-> (ConnectionSettings -> (ConnectionSettings, ())) -> t m ()
forall (m :: * -> *) a.
MonadBase IO m =>
DispatchControl
-> (ConnectionSettings -> (ConnectionSettings, a)) -> m a
modifySettings DispatchControl
dispatchControl
(\(ConnectionSettings Settings
cli Settings
srv) ->
(Settings -> Settings -> ConnectionSettings
ConnectionSettings (Settings -> SettingsList -> Settings
HTTP2.updateSettings Settings
cli SettingsList
settslist) Settings
srv, ()))
(FrameHeader, FramePayload) -> t m (FrameHeader, FramePayload)
forall (m :: * -> *) a. Monad m => a -> m a
return (FrameHeader, FramePayload)
ret
let _initGoaway :: ErrorCodeId -> ByteString -> ClientIO ()
_initGoaway ErrorCodeId
err ByteString
errStr = do
WindowSize
sId <- IO WindowSize -> ClientIO WindowSize
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO WindowSize -> ClientIO WindowSize)
-> IO WindowSize -> ClientIO WindowSize
forall a b. (a -> b) -> a -> b
$ Dispatch -> IO WindowSize
forall (m :: * -> *). MonadBase IO m => Dispatch -> m WindowSize
readMaxReceivedStreamIdIO Dispatch
dispatch
Http2FrameClientStream
-> WindowSize -> ErrorCodeId -> ByteString -> ClientIO ()
sendGTFOFrame Http2FrameClientStream
controlStream WindowSize
sId ErrorCodeId
err ByteString
errStr
let _initPaylodSplitter :: IO PayloadSplitter
_initPaylodSplitter = ConnectionSettings -> PayloadSplitter
settingsPayloadSplitter (ConnectionSettings -> PayloadSplitter)
-> IO ConnectionSettings -> IO PayloadSplitter
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
dispatchControl
let _initStop :: ClientIO Bool
_initStop = ClientIO Bool
endIncomingLoop
let _initClose :: ClientIO ()
_initClose = Http2FrameConnection -> ClientIO ()
closeConnection Http2FrameConnection
conn
(ClientIO (), InitHttp2Client)
-> ClientIO (ClientIO (), InitHttp2Client)
forall (m :: * -> *) a. Monad m => a -> m a
return (ClientIO ()
incomingLoop, InitHttp2Client :: (ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload)))
-> (SettingsList
-> ClientIO (ClientIO (FrameHeader, FramePayload)))
-> (ErrorCodeId -> ByteString -> ClientIO ())
-> (forall a. StreamStarter a)
-> IncomingFlowControl
-> OutgoingFlowControl
-> IO PayloadSplitter
-> ClientIO ()
-> ClientIO Bool
-> InitHttp2Client
InitHttp2Client{IO PayloadSplitter
ClientIO Bool
ClientIO ()
OutgoingFlowControl
IncomingFlowControl
SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
ErrorCodeId -> ByteString -> ClientIO ()
forall a. StreamStarter a
forall (t :: (* -> *) -> * -> *) (m :: * -> *).
(MonadTrans t, MonadBase IO m) =>
ByteString
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
forall (t :: (* -> *) -> * -> *) (m :: * -> *).
(MonadTrans t, MonadBase IO m, MonadBase IO (t m)) =>
SettingsList
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
_initClose :: ClientIO ()
_initStop :: ClientIO Bool
_initPaylodSplitter :: IO PayloadSplitter
_initGoaway :: ErrorCodeId -> ByteString -> ClientIO ()
_initSettings :: forall (t :: (* -> *) -> * -> *) (m :: * -> *).
(MonadTrans t, MonadBase IO m, MonadBase IO (t m)) =>
SettingsList
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
_initPing :: forall (t :: (* -> *) -> * -> *) (m :: * -> *).
(MonadTrans t, MonadBase IO m) =>
ByteString
-> ExceptT ClientError IO (t m (FrameHeader, FramePayload))
_initStartStream :: forall a. StreamStarter a
_initOutgoingFlowControl :: OutgoingFlowControl
_initIncomingFlowControl :: IncomingFlowControl
_initStop :: ClientIO Bool
_initClose :: ClientIO ()
_initPaylodSplitter :: IO PayloadSplitter
_initOutgoingFlowControl :: OutgoingFlowControl
_initIncomingFlowControl :: IncomingFlowControl
_initStartStream :: forall a. StreamStarter a
_initGoaway :: ErrorCodeId -> ByteString -> ClientIO ()
_initSettings :: SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
_initPing :: ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
..})
initializeStream
:: Http2FrameConnection
-> Dispatch
-> DispatchControl
-> DispatchStream
-> Chan (FrameHeader, FramePayload)
-> (Http2Stream -> StreamDefinition a)
-> StreamFSMState
-> ClientIO (ClientIO a)
initializeStream :: Http2FrameConnection
-> Dispatch
-> DispatchControl
-> DispatchStream
-> Chan (FrameHeader, FramePayload)
-> (Http2Stream -> StreamDefinition a)
-> StreamFSMState
-> ClientIO (ClientIO a)
initializeStream Http2FrameConnection
conn Dispatch
dispatch DispatchControl
control DispatchStream
stream Chan (FrameHeader, FramePayload)
windowUpdatesChan Http2Stream -> StreamDefinition a
getWork StreamFSMState
initialState = do
let sid :: WindowSize
sid = DispatchStream -> WindowSize
_dispatchStreamId DispatchStream
stream
let frameStream :: Http2FrameClientStream
frameStream = Http2FrameConnection -> WindowSize -> Http2FrameClientStream
makeFrameClientStream Http2FrameConnection
conn WindowSize
sid
let events :: Chan StreamEvent
events = DispatchStream -> Chan StreamEvent
_dispatchStreamReadEvents DispatchStream
stream
let _headers :: HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO StreamThread
_headers HeaderList
headersList FrameFlags -> FrameFlags
flags = do
PayloadSplitter
splitter <- ConnectionSettings -> PayloadSplitter
settingsPayloadSplitter (ConnectionSettings -> PayloadSplitter)
-> ExceptT ClientError IO ConnectionSettings
-> ExceptT ClientError IO PayloadSplitter
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> ExceptT ClientError IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
control
StreamThread
cst <- Http2FrameClientStream
-> HpackEncoderContext
-> HeaderList
-> PayloadSplitter
-> (FrameFlags -> FrameFlags)
-> ClientIO StreamThread
sendHeaders Http2FrameClientStream
frameStream (DispatchControl -> HpackEncoderContext
_dispatchControlHpackEncoder DispatchControl
control) HeaderList
headersList PayloadSplitter
splitter FrameFlags -> FrameFlags
flags
Bool -> ClientIO () -> ClientIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FrameFlags -> Bool
testEndStream (FrameFlags -> Bool) -> FrameFlags -> Bool
forall a b. (a -> b) -> a -> b
$ FrameFlags -> FrameFlags
flags FrameFlags
0) (ClientIO () -> ClientIO ()) -> ClientIO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
Dispatch -> WindowSize -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m ()
closeLocalStream Dispatch
dispatch WindowSize
sid
StreamThread -> ClientIO StreamThread
forall (m :: * -> *) a. Monad m => a -> m a
return StreamThread
cst
let _waitEvent :: ClientIO StreamEvent
_waitEvent = Chan StreamEvent -> ClientIO StreamEvent
forall (m :: * -> *) a. MonadBase IO m => Chan a -> m a
readChan Chan StreamEvent
events
let _sendDataChunk :: (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
_sendDataChunk FrameFlags -> FrameFlags
flags ByteString
dat = do
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
sendDataFrame Http2FrameClientStream
frameStream FrameFlags -> FrameFlags
flags ByteString
dat
Bool -> ClientIO () -> ClientIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FrameFlags -> Bool
testEndStream (FrameFlags -> Bool) -> FrameFlags -> Bool
forall a b. (a -> b) -> a -> b
$ FrameFlags -> FrameFlags
flags FrameFlags
0) (ClientIO () -> ClientIO ()) -> ClientIO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
Dispatch -> WindowSize -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m ()
closeLocalStream Dispatch
dispatch WindowSize
sid
let _rst :: ErrorCodeId -> ClientIO ()
_rst = \ErrorCodeId
err -> do
Http2FrameClientStream -> ErrorCodeId -> ClientIO ()
sendResetFrame Http2FrameClientStream
frameStream ErrorCodeId
err
Dispatch -> WindowSize -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m ()
closeReleaseStream Dispatch
dispatch WindowSize
sid
let _prio :: Priority -> ClientIO ()
_prio = Http2FrameClientStream -> Priority -> ClientIO ()
sendPriorityFrame Http2FrameClientStream
frameStream
let _handlePushPromise :: WindowSize
-> p
-> (WindowSize
-> Http2Stream
-> p
-> IncomingFlowControl
-> OutgoingFlowControl
-> ClientIO b)
-> ClientIO b
_handlePushPromise WindowSize
ppSid p
ppHeaders WindowSize
-> Http2Stream
-> p
-> IncomingFlowControl
-> OutgoingFlowControl
-> ClientIO b
ppHandler = do
let mkStreamActions :: Http2Stream -> StreamDefinition b
mkStreamActions Http2Stream
s = ClientIO StreamThread
-> (IncomingFlowControl -> OutgoingFlowControl -> ClientIO b)
-> StreamDefinition b
forall a.
ClientIO StreamThread
-> (IncomingFlowControl -> OutgoingFlowControl -> ClientIO a)
-> StreamDefinition a
StreamDefinition (StreamThread -> ClientIO StreamThread
forall (m :: * -> *) a. Monad m => a -> m a
return StreamThread
CST) (WindowSize
-> Http2Stream
-> p
-> IncomingFlowControl
-> OutgoingFlowControl
-> ClientIO b
ppHandler WindowSize
sid Http2Stream
s p
ppHeaders)
DispatchStream
newStream <- WindowSize -> ExceptT ClientError IO DispatchStream
forall (m :: * -> *).
MonadBase IO m =>
WindowSize -> m DispatchStream
newDispatchStreamIO WindowSize
ppSid
Chan (FrameHeader, FramePayload)
ppWindowsUpdatesChan <- ExceptT ClientError IO (Chan (FrameHeader, FramePayload))
forall (m :: * -> *) a. MonadBase IO m => m (Chan a)
newChan
ClientIO b
ppCont <- Http2FrameConnection
-> Dispatch
-> DispatchControl
-> DispatchStream
-> Chan (FrameHeader, FramePayload)
-> (Http2Stream -> StreamDefinition b)
-> StreamFSMState
-> ClientIO (ClientIO b)
forall a.
Http2FrameConnection
-> Dispatch
-> DispatchControl
-> DispatchStream
-> Chan (FrameHeader, FramePayload)
-> (Http2Stream -> StreamDefinition a)
-> StreamFSMState
-> ClientIO (ClientIO a)
initializeStream Http2FrameConnection
conn
Dispatch
dispatch
DispatchControl
control
DispatchStream
newStream
Chan (FrameHeader, FramePayload)
ppWindowsUpdatesChan
Http2Stream -> StreamDefinition b
mkStreamActions
StreamFSMState
ReservedRemote
ClientIO b
ppCont
let streamActions :: StreamDefinition a
streamActions = Http2Stream -> StreamDefinition a
getWork (Http2Stream -> StreamDefinition a)
-> Http2Stream -> StreamDefinition a
forall a b. (a -> b) -> a -> b
$ Http2Stream :: (HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO StreamThread)
-> (Priority -> ClientIO ())
-> (ErrorCodeId -> ClientIO ())
-> ClientIO StreamEvent
-> ((FrameFlags -> FrameFlags) -> ByteString -> ClientIO ())
-> (WindowSize -> HeaderList -> PushPromiseHandler -> ClientIO ())
-> Http2Stream
Http2Stream{ClientIO StreamEvent
WindowSize -> HeaderList -> PushPromiseHandler -> ClientIO ()
HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO StreamThread
ErrorCodeId -> ClientIO ()
Priority -> ClientIO ()
(FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
forall p b.
WindowSize
-> p
-> (WindowSize
-> Http2Stream
-> p
-> IncomingFlowControl
-> OutgoingFlowControl
-> ClientIO b)
-> ClientIO b
_handlePushPromise :: forall p b.
WindowSize
-> p
-> (WindowSize
-> Http2Stream
-> p
-> IncomingFlowControl
-> OutgoingFlowControl
-> ClientIO b)
-> ClientIO b
_prio :: Priority -> ClientIO ()
_rst :: ErrorCodeId -> ClientIO ()
_sendDataChunk :: (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
_waitEvent :: ClientIO StreamEvent
_headers :: HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO StreamThread
_handlePushPromise :: WindowSize -> HeaderList -> PushPromiseHandler -> ClientIO ()
_sendDataChunk :: (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
_waitEvent :: ClientIO StreamEvent
_rst :: ErrorCodeId -> ClientIO ()
_prio :: Priority -> ClientIO ()
_headers :: HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO StreamThread
..}
Dispatch -> WindowSize -> StreamState -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> StreamState -> m ()
registerStream Dispatch
dispatch WindowSize
sid (Chan (FrameHeader, FramePayload)
-> Chan StreamEvent -> StreamFSMState -> StreamState
StreamState Chan (FrameHeader, FramePayload)
windowUpdatesChan Chan StreamEvent
events StreamFSMState
initialState)
StreamThread
_ <- StreamDefinition a -> ClientIO StreamThread
forall a. StreamDefinition a -> ClientIO StreamThread
_initStream StreamDefinition a
streamActions
ClientIO a -> ClientIO (ClientIO a)
forall (m :: * -> *) a. Monad m => a -> m a
return (ClientIO a -> ClientIO (ClientIO a))
-> ClientIO a -> ClientIO (ClientIO a)
forall a b. (a -> b) -> a -> b
$ do
let baseIncomingWindowSize :: IO WindowSize
baseIncomingWindowSize = Settings -> WindowSize
initialWindowSize (Settings -> WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_clientSettings (ConnectionSettings -> WindowSize)
-> IO ConnectionSettings -> IO WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
control
IncomingFlowControl
isfc <- IO IncomingFlowControl
-> ExceptT ClientError IO IncomingFlowControl
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO IncomingFlowControl
-> ExceptT ClientError IO IncomingFlowControl)
-> IO IncomingFlowControl
-> ExceptT ClientError IO IncomingFlowControl
forall a b. (a -> b) -> a -> b
$ DispatchControl
-> IO WindowSize
-> (WindowSize -> ClientIO ())
-> IO IncomingFlowControl
newIncomingFlowControl DispatchControl
control IO WindowSize
baseIncomingWindowSize (Http2FrameClientStream -> WindowSize -> ClientIO ()
sendWindowUpdateFrame Http2FrameClientStream
frameStream)
let baseOutgoingWindowSize :: IO WindowSize
baseOutgoingWindowSize = Settings -> WindowSize
initialWindowSize (Settings -> WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_serverSettings (ConnectionSettings -> WindowSize)
-> IO ConnectionSettings -> IO WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
control
OutgoingFlowControl
osfc <- IO OutgoingFlowControl
-> ExceptT ClientError IO OutgoingFlowControl
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO OutgoingFlowControl
-> ExceptT ClientError IO OutgoingFlowControl)
-> IO OutgoingFlowControl
-> ExceptT ClientError IO OutgoingFlowControl
forall a b. (a -> b) -> a -> b
$ DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IO WindowSize
-> IO OutgoingFlowControl
newOutgoingFlowControl DispatchControl
control Chan (FrameHeader, FramePayload)
windowUpdatesChan IO WindowSize
baseOutgoingWindowSize
StreamDefinition a
-> IncomingFlowControl -> OutgoingFlowControl -> ClientIO a
forall a.
StreamDefinition a
-> IncomingFlowControl -> OutgoingFlowControl -> ClientIO a
_handleStream StreamDefinition a
streamActions IncomingFlowControl
isfc OutgoingFlowControl
osfc
dispatchLoop
:: Http2FrameConnection
-> Dispatch
-> DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IncomingFlowControl
-> DispatchHPACK
-> ClientIO (ClientIO (), ClientIO Bool)
dispatchLoop :: Http2FrameConnection
-> Dispatch
-> DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IncomingFlowControl
-> DispatchHPACK
-> ClientIO (ClientIO (), ClientIO Bool)
dispatchLoop Http2FrameConnection
conn Dispatch
d DispatchControl
dc Chan (FrameHeader, FramePayload)
windowUpdatesChan IncomingFlowControl
inFlowControl DispatchHPACK
dh = do
let getNextFrame :: ClientIO (FrameHeader, Either HTTP2Error FramePayload)
getNextFrame = Http2FrameConnection
-> ClientIO (FrameHeader, Either HTTP2Error FramePayload)
next Http2FrameConnection
conn
let go :: ClientIO a
go = ClientIO a -> ClientIO a
forall a. ClientIO a -> ClientIO a
delayException (ClientIO a -> ClientIO a)
-> (ClientIO () -> ClientIO a) -> ClientIO () -> ClientIO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ClientIO () -> ClientIO a
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (ClientIO () -> ClientIO a) -> ClientIO () -> ClientIO a
forall a b. (a -> b) -> a -> b
$ do
(FrameHeader, Either HTTP2Error FramePayload)
frame <- ClientIO (FrameHeader, Either HTTP2Error FramePayload)
getNextFrame
(FrameHeader, Either HTTP2Error FramePayload)
-> Dispatch -> ClientIO ()
dispatchFramesStep (FrameHeader, Either HTTP2Error FramePayload)
frame Dispatch
d
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either HTTP2Error FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
forall e.
Exception e =>
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either e FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
whenFrame (WindowSize -> FrameHeader -> FramePayload -> Bool
hasStreamId WindowSize
0) (FrameHeader, Either HTTP2Error FramePayload)
frame (FallBackFrameHandler -> ClientIO ())
-> FallBackFrameHandler -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ \(FrameHeader, FramePayload)
got ->
Chan (FrameHeader, FramePayload)
-> (FrameHeader, FramePayload) -> DispatchControl -> ClientIO ()
dispatchControlFramesStep Chan (FrameHeader, FramePayload)
windowUpdatesChan (FrameHeader, FramePayload)
got DispatchControl
dc
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either HTTP2Error FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
forall e.
Exception e =>
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either e FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
whenFrame ([FrameTypeId] -> FrameHeader -> FramePayload -> Bool
hasTypeId [FrameTypeId
FrameData]) (FrameHeader, Either HTTP2Error FramePayload)
frame (FallBackFrameHandler -> ClientIO ())
-> FallBackFrameHandler -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ \(FrameHeader, FramePayload)
got ->
Dispatch -> IncomingFlowControl -> FallBackFrameHandler
creditDataFramesStep Dispatch
d IncomingFlowControl
inFlowControl (FrameHeader, FramePayload)
got
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either HTTP2Error FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
forall e.
Exception e =>
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either e FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
whenFrame ([FrameTypeId] -> FrameHeader -> FramePayload -> Bool
hasTypeId [FrameTypeId
FrameWindowUpdate]) (FrameHeader, Either HTTP2Error FramePayload)
frame (FallBackFrameHandler -> ClientIO ())
-> FallBackFrameHandler -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ \(FrameHeader, FramePayload)
got -> do
Dispatch -> FallBackFrameHandler
updateWindowsStep Dispatch
d (FrameHeader, FramePayload)
got
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either HTTP2Error FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
forall e.
Exception e =>
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either e FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
whenFrame ([FrameTypeId] -> FrameHeader -> FramePayload -> Bool
hasTypeId [FrameTypeId
FramePushPromise, FrameTypeId
FrameHeaders]) (FrameHeader, Either HTTP2Error FramePayload)
frame (FallBackFrameHandler -> ClientIO ())
-> FallBackFrameHandler -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ \(FrameHeader, FramePayload)
got -> do
let hpackLoop :: HPACKStepResult -> ClientIO ()
hpackLoop (FinishedWithHeaders FrameHeader
curFh WindowSize
sId IO HeaderList
mkNewHdrs) = IO () -> ClientIO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ClientIO ()) -> IO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
HeaderList
newHdrs <- IO HeaderList
mkNewHdrs
Maybe (Chan StreamEvent)
chan <- (StreamState -> Chan StreamEvent)
-> Maybe StreamState -> Maybe (Chan StreamEvent)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StreamState -> Chan StreamEvent
_streamStateEvents (Maybe StreamState -> Maybe (Chan StreamEvent))
-> IO (Maybe StreamState) -> IO (Maybe (Chan StreamEvent))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dispatch -> WindowSize -> IO (Maybe StreamState)
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m (Maybe StreamState)
lookupStreamState Dispatch
d WindowSize
sId
let msg :: StreamEvent
msg = FrameHeader -> HeaderList -> StreamEvent
StreamHeadersEvent FrameHeader
curFh HeaderList
newHdrs
IO ()
-> (Chan StreamEvent -> IO ()) -> Maybe (Chan StreamEvent) -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((Chan StreamEvent -> StreamEvent -> IO ())
-> StreamEvent -> Chan StreamEvent -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Chan StreamEvent -> StreamEvent -> IO ()
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan StreamEvent
msg) Maybe (Chan StreamEvent)
chan
hpackLoop (FinishedWithPushPromise FrameHeader
curFh WindowSize
parentSid WindowSize
newSid IO HeaderList
mkNewHdrs) = IO () -> ClientIO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ClientIO ()) -> IO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
HeaderList
newHdrs <- IO HeaderList
mkNewHdrs
Maybe (Chan StreamEvent)
chan <- (StreamState -> Chan StreamEvent)
-> Maybe StreamState -> Maybe (Chan StreamEvent)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StreamState -> Chan StreamEvent
_streamStateEvents (Maybe StreamState -> Maybe (Chan StreamEvent))
-> IO (Maybe StreamState) -> IO (Maybe (Chan StreamEvent))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dispatch -> WindowSize -> IO (Maybe StreamState)
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m (Maybe StreamState)
lookupStreamState Dispatch
d WindowSize
parentSid
let msg :: StreamEvent
msg = FrameHeader -> WindowSize -> HeaderList -> StreamEvent
StreamPushPromiseEvent FrameHeader
curFh WindowSize
newSid HeaderList
newHdrs
IO ()
-> (Chan StreamEvent -> IO ()) -> Maybe (Chan StreamEvent) -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((Chan StreamEvent -> StreamEvent -> IO ())
-> StreamEvent -> Chan StreamEvent -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Chan StreamEvent -> StreamEvent -> IO ()
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan StreamEvent
msg) Maybe (Chan StreamEvent)
chan
hpackLoop (WaitContinuation (FrameHeader, Either HTTP2Error FramePayload)
-> ClientIO HPACKStepResult
act) =
ClientIO (FrameHeader, Either HTTP2Error FramePayload)
getNextFrame ClientIO (FrameHeader, Either HTTP2Error FramePayload)
-> ((FrameHeader, Either HTTP2Error FramePayload)
-> ClientIO HPACKStepResult)
-> ClientIO HPACKStepResult
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (FrameHeader, Either HTTP2Error FramePayload)
-> ClientIO HPACKStepResult
act ClientIO HPACKStepResult
-> (HPACKStepResult -> ClientIO ()) -> ClientIO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HPACKStepResult -> ClientIO ()
hpackLoop
hpackLoop (FailedHeaders FrameHeader
curFh WindowSize
sId ErrorCode
err) = IO () -> ClientIO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ClientIO ()) -> IO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
Maybe (Chan StreamEvent)
chan <- (StreamState -> Chan StreamEvent)
-> Maybe StreamState -> Maybe (Chan StreamEvent)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StreamState -> Chan StreamEvent
_streamStateEvents (Maybe StreamState -> Maybe (Chan StreamEvent))
-> IO (Maybe StreamState) -> IO (Maybe (Chan StreamEvent))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dispatch -> WindowSize -> IO (Maybe StreamState)
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m (Maybe StreamState)
lookupStreamState Dispatch
d WindowSize
sId
let msg :: StreamEvent
msg = FrameHeader -> ErrorCode -> StreamEvent
StreamErrorEvent FrameHeader
curFh ErrorCode
err
IO ()
-> (Chan StreamEvent -> IO ()) -> Maybe (Chan StreamEvent) -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((Chan StreamEvent -> StreamEvent -> IO ())
-> StreamEvent -> Chan StreamEvent -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Chan StreamEvent -> StreamEvent -> IO ()
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan StreamEvent
msg) Maybe (Chan StreamEvent)
chan
HPACKStepResult -> ClientIO ()
hpackLoop ((FrameHeader, FramePayload) -> DispatchHPACK -> HPACKStepResult
dispatchHPACKFramesStep (FrameHeader, FramePayload)
got DispatchHPACK
dh)
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either HTTP2Error FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
forall e.
Exception e =>
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either e FramePayload)
-> FallBackFrameHandler
-> ClientIO ()
whenFrame ([FrameTypeId] -> FrameHeader -> FramePayload -> Bool
hasTypeId [FrameTypeId
FrameRSTStream]) (FrameHeader, Either HTTP2Error FramePayload)
frame (FallBackFrameHandler -> ClientIO ())
-> FallBackFrameHandler -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ \(FrameHeader, FramePayload)
got -> do
Dispatch -> FallBackFrameHandler
handleRSTStep Dispatch
d (FrameHeader, FramePayload)
got
(FrameHeader, Either HTTP2Error FramePayload)
-> Dispatch -> ClientIO ()
finalizeFramesStep (FrameHeader, Either HTTP2Error FramePayload)
frame Dispatch
d
MVar ()
end <- ExceptT ClientError IO (MVar ())
forall (m :: * -> *) a. MonadBase IO m => m (MVar a)
newEmptyMVar
let run :: ClientIO ()
run = ExceptT ClientError IO (Either Any ()) -> ClientIO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ExceptT ClientError IO (Either Any ()) -> ClientIO ())
-> ExceptT ClientError IO (Either Any ()) -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ ExceptT ClientError IO Any
-> ClientIO () -> ExceptT ClientError IO (Either Any ())
forall (m :: * -> *) a b.
MonadBaseControl IO m =>
m a -> m b -> m (Either a b)
race ExceptT ClientError IO Any
forall a. ClientIO a
go (MVar () -> ClientIO ()
forall (m :: * -> *) a. MonadBase IO m => MVar a -> m a
takeMVar MVar ()
end)
let stop :: ClientIO Bool
stop = MVar () -> () -> ClientIO Bool
forall (m :: * -> *) a. MonadBase IO m => MVar a -> a -> m Bool
tryPutMVar MVar ()
end ()
(ClientIO (), ClientIO Bool)
-> ClientIO (ClientIO (), ClientIO Bool)
forall (m :: * -> *) a. Monad m => a -> m a
return (ClientIO ()
run, ClientIO Bool
stop)
handleRSTStep
:: Dispatch
-> (FrameHeader, FramePayload)
-> ClientIO ()
handleRSTStep :: Dispatch -> FallBackFrameHandler
handleRSTStep Dispatch
d (FrameHeader
fh, FramePayload
payload) = do
let sid :: WindowSize
sid = FrameHeader -> WindowSize
streamId FrameHeader
fh
case FramePayload
payload of
(RSTStreamFrame ErrorCodeId
err) -> IO () -> ClientIO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ClientIO ()) -> IO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
Maybe (Chan StreamEvent)
chan <- (StreamState -> Chan StreamEvent)
-> Maybe StreamState -> Maybe (Chan StreamEvent)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StreamState -> Chan StreamEvent
_streamStateEvents (Maybe StreamState -> Maybe (Chan StreamEvent))
-> IO (Maybe StreamState) -> IO (Maybe (Chan StreamEvent))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dispatch -> WindowSize -> IO (Maybe StreamState)
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m (Maybe StreamState)
lookupStreamState Dispatch
d WindowSize
sid
let msg :: StreamEvent
msg = FrameHeader -> ErrorCode -> StreamEvent
StreamErrorEvent FrameHeader
fh (ErrorCodeId -> ErrorCode
HTTP2.fromErrorCodeId ErrorCodeId
err)
IO ()
-> (Chan StreamEvent -> IO ()) -> Maybe (Chan StreamEvent) -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((Chan StreamEvent -> StreamEvent -> IO ())
-> StreamEvent -> Chan StreamEvent -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Chan StreamEvent -> StreamEvent -> IO ()
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan StreamEvent
msg) Maybe (Chan StreamEvent)
chan
Dispatch -> WindowSize -> IO ()
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m ()
closeReleaseStream Dispatch
d WindowSize
sid
FramePayload
_ ->
String -> ClientIO ()
forall a. HasCallStack => String -> a
error (String -> ClientIO ()) -> String -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ String
"expecting RSTFrame but got " String -> ShowS
forall a. [a] -> [a] -> [a]
++ FramePayload -> String
forall a. Show a => a -> String
show FramePayload
payload
dispatchFramesStep
:: (FrameHeader, Either HTTP2Error FramePayload)
-> Dispatch
-> ClientIO ()
dispatchFramesStep :: (FrameHeader, Either HTTP2Error FramePayload)
-> Dispatch -> ClientIO ()
dispatchFramesStep (FrameHeader
fh,Either HTTP2Error FramePayload
_) Dispatch
d = do
let sid :: WindowSize
sid = FrameHeader -> WindowSize
streamId FrameHeader
fh
IORef WindowSize -> (WindowSize -> (WindowSize, ())) -> ClientIO ()
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' (Dispatch -> IORef WindowSize
_dispatchMaxStreamId Dispatch
d) (\WindowSize
n -> (WindowSize -> WindowSize -> WindowSize
forall a. Ord a => a -> a -> a
max WindowSize
n WindowSize
sid, ()))
finalizeFramesStep
:: (FrameHeader, Either HTTP2Error FramePayload)
-> Dispatch
-> ClientIO ()
finalizeFramesStep :: (FrameHeader, Either HTTP2Error FramePayload)
-> Dispatch -> ClientIO ()
finalizeFramesStep (FrameHeader
fh,Either HTTP2Error FramePayload
_) Dispatch
d = do
let sid :: WindowSize
sid = FrameHeader -> WindowSize
streamId FrameHeader
fh
Bool -> ClientIO () -> ClientIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FrameFlags -> Bool
testEndStream (FrameFlags -> Bool) -> FrameFlags -> Bool
forall a b. (a -> b) -> a -> b
$ FrameHeader -> FrameFlags
flags FrameHeader
fh) (ClientIO () -> ClientIO ()) -> ClientIO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ do
Dispatch -> WindowSize -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m ()
closeRemoteStream Dispatch
d WindowSize
sid
dispatchControlFramesStep
:: Chan (FrameHeader, FramePayload)
-> (FrameHeader, FramePayload)
-> DispatchControl
-> ClientIO ()
dispatchControlFramesStep :: Chan (FrameHeader, FramePayload)
-> (FrameHeader, FramePayload) -> DispatchControl -> ClientIO ()
dispatchControlFramesStep Chan (FrameHeader, FramePayload)
windowUpdatesChan controlFrame :: (FrameHeader, FramePayload)
controlFrame@(FrameHeader
fh, FramePayload
payload) control :: DispatchControl
control@(DispatchControl{IORef [(ByteString, PingHandler)]
IORef [SetSettingsHandler]
IORef ConnectionSettings
ClientIO ()
HpackEncoderContext
FallBackFrameHandler
ByteString -> ClientIO ()
GoAwayHandler
_dispatchControlSetSettingsHandlers :: DispatchControl -> IORef [SetSettingsHandler]
_dispatchControlPingHandlers :: DispatchControl -> IORef [(ByteString, PingHandler)]
_dispatchControlOnFallback :: DispatchControl -> FallBackFrameHandler
_dispatchControlOnGoAway :: DispatchControl -> GoAwayHandler
_dispatchControlAckSettings :: DispatchControl -> ClientIO ()
_dispatchControlAckPing :: DispatchControl -> ByteString -> ClientIO ()
_dispatchControlConnectionSettings :: DispatchControl -> IORef ConnectionSettings
_dispatchControlSetSettingsHandlers :: IORef [SetSettingsHandler]
_dispatchControlPingHandlers :: IORef [(ByteString, PingHandler)]
_dispatchControlOnFallback :: FallBackFrameHandler
_dispatchControlOnGoAway :: GoAwayHandler
_dispatchControlAckSettings :: ClientIO ()
_dispatchControlAckPing :: ByteString -> ClientIO ()
_dispatchControlHpackEncoder :: HpackEncoderContext
_dispatchControlConnectionSettings :: IORef ConnectionSettings
_dispatchControlHpackEncoder :: DispatchControl -> HpackEncoderContext
..}) = do
case FramePayload
payload of
(SettingsFrame SettingsList
settsList)
| Bool -> Bool
not (Bool -> Bool) -> (FrameHeader -> Bool) -> FrameHeader -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameFlags -> Bool
testAck (FrameFlags -> Bool)
-> (FrameHeader -> FrameFlags) -> FrameHeader -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameHeader -> FrameFlags
flags (FrameHeader -> Bool) -> FrameHeader -> Bool
forall a b. (a -> b) -> a -> b
$ FrameHeader
fh -> do
IORef ConnectionSettings
-> (ConnectionSettings -> (ConnectionSettings, ())) -> ClientIO ()
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef ConnectionSettings
_dispatchControlConnectionSettings
(\(ConnectionSettings Settings
cli Settings
srv) ->
(Settings -> Settings -> ConnectionSettings
ConnectionSettings Settings
cli (Settings -> SettingsList -> Settings
HTTP2.updateSettings Settings
srv SettingsList
settsList), ()))
IO () -> ClientIO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ClientIO ()) -> IO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ IO () -> (WindowSize -> IO ()) -> Maybe WindowSize -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
(HpackEncoderContext -> WindowSize -> IO ()
_applySettings HpackEncoderContext
_dispatchControlHpackEncoder)
(SettingsKeyId -> SettingsList -> Maybe WindowSize
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup SettingsKeyId
SettingsHeaderTableSize SettingsList
settsList)
ClientIO ()
_dispatchControlAckSettings
| Bool
otherwise -> do
Maybe SetSettingsHandler
handler <- DispatchControl
-> ExceptT ClientError IO (Maybe SetSettingsHandler)
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m (Maybe SetSettingsHandler)
lookupAndReleaseSetSettingsHandler DispatchControl
control
ClientIO ()
-> (SetSettingsHandler -> ClientIO ())
-> Maybe SetSettingsHandler
-> ClientIO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((FrameHeader, FramePayload) -> SetSettingsHandler -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
(FrameHeader, FramePayload) -> SetSettingsHandler -> m ()
notifySetSettingsHandler (FrameHeader, FramePayload)
controlFrame) Maybe SetSettingsHandler
handler
(PingFrame ByteString
pingMsg)
| Bool -> Bool
not (Bool -> Bool) -> (FrameHeader -> Bool) -> FrameHeader -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameFlags -> Bool
testAck (FrameFlags -> Bool)
-> (FrameHeader -> FrameFlags) -> FrameHeader -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameHeader -> FrameFlags
flags (FrameHeader -> Bool) -> FrameHeader -> Bool
forall a b. (a -> b) -> a -> b
$ FrameHeader
fh ->
ByteString -> ClientIO ()
_dispatchControlAckPing ByteString
pingMsg
| Bool
otherwise -> do
Maybe PingHandler
handler <- DispatchControl
-> ByteString -> ExceptT ClientError IO (Maybe PingHandler)
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> ByteString -> m (Maybe PingHandler)
lookupAndReleasePingHandler DispatchControl
control ByteString
pingMsg
ClientIO ()
-> (PingHandler -> ClientIO ()) -> Maybe PingHandler -> ClientIO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((FrameHeader, FramePayload) -> PingHandler -> ClientIO ()
forall (m :: * -> *).
MonadBase IO m =>
(FrameHeader, FramePayload) -> PingHandler -> m ()
notifyPingHandler (FrameHeader, FramePayload)
controlFrame) Maybe PingHandler
handler
(WindowUpdateFrame WindowSize
_ ) ->
Chan (FrameHeader, FramePayload) -> FallBackFrameHandler
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan Chan (FrameHeader, FramePayload)
windowUpdatesChan (FrameHeader, FramePayload)
controlFrame
(GoAwayFrame WindowSize
lastSid ErrorCodeId
errCode ByteString
reason) ->
GoAwayHandler
_dispatchControlOnGoAway GoAwayHandler -> GoAwayHandler
forall a b. (a -> b) -> a -> b
$ WindowSize -> ErrorCodeId -> ByteString -> RemoteSentGoAwayFrame
RemoteSentGoAwayFrame WindowSize
lastSid ErrorCodeId
errCode ByteString
reason
FramePayload
_ ->
FallBackFrameHandler
_dispatchControlOnFallback (FrameHeader, FramePayload)
controlFrame
creditDataFramesStep
:: Dispatch
-> IncomingFlowControl
-> (FrameHeader, FramePayload)
-> ClientIO ()
creditDataFramesStep :: Dispatch -> IncomingFlowControl -> FallBackFrameHandler
creditDataFramesStep Dispatch
d IncomingFlowControl
flowControl (FrameHeader
fh,FramePayload
payload) = do
WindowSize
_ <- IO WindowSize -> ClientIO WindowSize
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO WindowSize -> ClientIO WindowSize)
-> IO WindowSize -> ClientIO WindowSize
forall a b. (a -> b) -> a -> b
$ IncomingFlowControl -> WindowSize -> IO WindowSize
_consumeCredit IncomingFlowControl
flowControl (FrameHeader -> WindowSize
HTTP2.payloadLength FrameHeader
fh)
IO () -> ClientIO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ClientIO ()) -> IO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ IncomingFlowControl -> WindowSize -> IO ()
_addCredit IncomingFlowControl
flowControl (FrameHeader -> WindowSize
HTTP2.payloadLength FrameHeader
fh)
let sid :: WindowSize
sid = FrameHeader -> WindowSize
streamId FrameHeader
fh
case FramePayload
payload of
(DataFrame ByteString
dat) -> do
Maybe (Chan StreamEvent)
chan <- (StreamState -> Chan StreamEvent)
-> Maybe StreamState -> Maybe (Chan StreamEvent)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StreamState -> Chan StreamEvent
_streamStateEvents (Maybe StreamState -> Maybe (Chan StreamEvent))
-> ExceptT ClientError IO (Maybe StreamState)
-> ExceptT ClientError IO (Maybe (Chan StreamEvent))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dispatch
-> WindowSize -> ExceptT ClientError IO (Maybe StreamState)
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m (Maybe StreamState)
lookupStreamState Dispatch
d WindowSize
sid
ClientIO ()
-> (Chan StreamEvent -> ClientIO ())
-> Maybe (Chan StreamEvent)
-> ClientIO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((Chan StreamEvent -> StreamEvent -> ClientIO ())
-> StreamEvent -> Chan StreamEvent -> ClientIO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Chan StreamEvent -> StreamEvent -> ClientIO ()
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan (StreamEvent -> Chan StreamEvent -> ClientIO ())
-> StreamEvent -> Chan StreamEvent -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ FrameHeader -> ByteString -> StreamEvent
StreamDataEvent FrameHeader
fh ByteString
dat) Maybe (Chan StreamEvent)
chan
FramePayload
_ ->
String -> ClientIO ()
forall a. HasCallStack => String -> a
error (String -> ClientIO ()) -> String -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ String
"expecting DataFrame but got " String -> ShowS
forall a. [a] -> [a] -> [a]
++ FramePayload -> String
forall a. Show a => a -> String
show FramePayload
payload
updateWindowsStep
:: Dispatch
-> (FrameHeader, FramePayload)
-> ClientIO ()
updateWindowsStep :: Dispatch -> FallBackFrameHandler
updateWindowsStep Dispatch
d got :: (FrameHeader, FramePayload)
got@(FrameHeader
fh,FramePayload
_) = do
let sid :: WindowSize
sid = FrameHeader -> WindowSize
HTTP2.streamId FrameHeader
fh
Maybe (Chan (FrameHeader, FramePayload))
chan <- (StreamState -> Chan (FrameHeader, FramePayload))
-> Maybe StreamState -> Maybe (Chan (FrameHeader, FramePayload))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap StreamState -> Chan (FrameHeader, FramePayload)
_streamStateWindowUpdatesChan (Maybe StreamState -> Maybe (Chan (FrameHeader, FramePayload)))
-> ExceptT ClientError IO (Maybe StreamState)
-> ExceptT
ClientError IO (Maybe (Chan (FrameHeader, FramePayload)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Dispatch
-> WindowSize -> ExceptT ClientError IO (Maybe StreamState)
forall (m :: * -> *).
MonadBase IO m =>
Dispatch -> WindowSize -> m (Maybe StreamState)
lookupStreamState Dispatch
d WindowSize
sid
ClientIO ()
-> (Chan (FrameHeader, FramePayload) -> ClientIO ())
-> Maybe (Chan (FrameHeader, FramePayload))
-> ClientIO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) ((Chan (FrameHeader, FramePayload) -> FallBackFrameHandler)
-> (FrameHeader, FramePayload)
-> Chan (FrameHeader, FramePayload)
-> ClientIO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Chan (FrameHeader, FramePayload) -> FallBackFrameHandler
forall (m :: * -> *) a. MonadBase IO m => Chan a -> a -> m ()
writeChan (FrameHeader, FramePayload)
got) Maybe (Chan (FrameHeader, FramePayload))
chan
data HPACKLoopDecision =
!StreamId
| OpenPushPromise !StreamId !StreamId
data HPACKStepResult =
WaitContinuation !((FrameHeader, Either HTTP2Error FramePayload) -> ClientIO HPACKStepResult)
| !FrameHeader !StreamId ErrorCode
| !FrameHeader !StreamId (IO HeaderList)
| FinishedWithPushPromise !FrameHeader !StreamId !StreamId (IO HeaderList)
dispatchHPACKFramesStep
:: (FrameHeader, FramePayload)
-> DispatchHPACK
-> HPACKStepResult
dispatchHPACKFramesStep :: (FrameHeader, FramePayload) -> DispatchHPACK -> HPACKStepResult
dispatchHPACKFramesStep (FrameHeader
fh,FramePayload
fp) (DispatchHPACK{DynamicTable
_dispatchHPACKDynamicTable :: DispatchHPACK -> DynamicTable
_dispatchHPACKDynamicTable :: DynamicTable
..}) =
let (HPACKLoopDecision
decision, Either ErrorCodeId ByteString
pattern) = case FramePayload
fp of
PushPromiseFrame WindowSize
ppSid ByteString
hbf -> do
(WindowSize -> WindowSize -> HPACKLoopDecision
OpenPushPromise WindowSize
sid WindowSize
ppSid, ByteString -> Either ErrorCodeId ByteString
forall a b. b -> Either a b
Right ByteString
hbf)
HeadersFrame Maybe Priority
_ ByteString
hbf ->
(WindowSize -> HPACKLoopDecision
ForwardHeader WindowSize
sid, ByteString -> Either ErrorCodeId ByteString
forall a b. b -> Either a b
Right ByteString
hbf)
RSTStreamFrame ErrorCodeId
err ->
(WindowSize -> HPACKLoopDecision
ForwardHeader WindowSize
sid, ErrorCodeId -> Either ErrorCodeId ByteString
forall a b. a -> Either a b
Left ErrorCodeId
err)
FramePayload
_ ->
String -> (HPACKLoopDecision, Either ErrorCodeId ByteString)
forall a. HasCallStack => String -> a
error String
"wrong TypeId"
in FrameHeader
-> HPACKLoopDecision
-> Either ErrorCodeId ByteString
-> HPACKStepResult
go FrameHeader
fh HPACKLoopDecision
decision Either ErrorCodeId ByteString
pattern
where
sid :: StreamId
sid :: WindowSize
sid = FrameHeader -> WindowSize
HTTP2.streamId FrameHeader
fh
go :: FrameHeader -> HPACKLoopDecision -> Either ErrorCodeId ByteString -> HPACKStepResult
go :: FrameHeader
-> HPACKLoopDecision
-> Either ErrorCodeId ByteString
-> HPACKStepResult
go FrameHeader
curFh HPACKLoopDecision
decision (Right ByteString
buffer) =
if Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ FrameFlags -> Bool
HTTP2.testEndHeader (FrameHeader -> FrameFlags
HTTP2.flags FrameHeader
curFh)
then ((FrameHeader, Either HTTP2Error FramePayload)
-> ClientIO HPACKStepResult)
-> HPACKStepResult
WaitContinuation (((FrameHeader, Either HTTP2Error FramePayload)
-> ClientIO HPACKStepResult)
-> HPACKStepResult)
-> ((FrameHeader, Either HTTP2Error FramePayload)
-> ClientIO HPACKStepResult)
-> HPACKStepResult
forall a b. (a -> b) -> a -> b
$ \(FrameHeader, Either HTTP2Error FramePayload)
frame -> do
let interrupted :: FrameHeader -> FramePayload -> Bool
interrupted FrameHeader
fh2 FramePayload
fp2 =
Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [FrameTypeId] -> FrameHeader -> FramePayload -> Bool
hasTypeId [ FrameTypeId
FrameRSTStream , FrameTypeId
FrameContinuation ] FrameHeader
fh2 FramePayload
fp2
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either HTTP2Error FramePayload)
-> ((FrameHeader, FramePayload) -> ClientIO HPACKStepResult)
-> ((FrameHeader, FramePayload) -> ClientIO HPACKStepResult)
-> ClientIO HPACKStepResult
forall e a.
Exception e =>
(FrameHeader -> FramePayload -> Bool)
-> (FrameHeader, Either e FramePayload)
-> ((FrameHeader, FramePayload) -> ClientIO a)
-> ((FrameHeader, FramePayload) -> ClientIO a)
-> ClientIO a
whenFrameElse FrameHeader -> FramePayload -> Bool
interrupted (FrameHeader, Either HTTP2Error FramePayload)
frame (\(FrameHeader, FramePayload)
_ ->
String -> ClientIO HPACKStepResult
forall a. HasCallStack => String -> a
error String
"invalid frame type while waiting for CONTINUATION")
(\(FrameHeader
lastFh, FramePayload
lastFp) ->
case FramePayload
lastFp of
ContinuationFrame ByteString
chbf ->
HPACKStepResult -> ClientIO HPACKStepResult
forall (m :: * -> *) a. Monad m => a -> m a
return (HPACKStepResult -> ClientIO HPACKStepResult)
-> HPACKStepResult -> ClientIO HPACKStepResult
forall a b. (a -> b) -> a -> b
$ FrameHeader
-> HPACKLoopDecision
-> Either ErrorCodeId ByteString
-> HPACKStepResult
go FrameHeader
lastFh HPACKLoopDecision
decision (ByteString -> Either ErrorCodeId ByteString
forall a b. b -> Either a b
Right (ByteString -> ByteString -> ByteString
ByteString.append ByteString
buffer ByteString
chbf))
RSTStreamFrame ErrorCodeId
err ->
HPACKStepResult -> ClientIO HPACKStepResult
forall (m :: * -> *) a. Monad m => a -> m a
return (HPACKStepResult -> ClientIO HPACKStepResult)
-> HPACKStepResult -> ClientIO HPACKStepResult
forall a b. (a -> b) -> a -> b
$ FrameHeader
-> HPACKLoopDecision
-> Either ErrorCodeId ByteString
-> HPACKStepResult
go FrameHeader
lastFh HPACKLoopDecision
decision (ErrorCodeId -> Either ErrorCodeId ByteString
forall a b. a -> Either a b
Left ErrorCodeId
err)
FramePayload
_ ->
String -> ClientIO HPACKStepResult
forall a. HasCallStack => String -> a
error String
"continued frame has invalid type")
else case HPACKLoopDecision
decision of
ForwardHeader WindowSize
sId ->
FrameHeader -> WindowSize -> IO HeaderList -> HPACKStepResult
FinishedWithHeaders FrameHeader
curFh WindowSize
sId (DynamicTable -> ByteString -> IO HeaderList
decodeHeader DynamicTable
_dispatchHPACKDynamicTable ByteString
buffer)
OpenPushPromise WindowSize
parentSid WindowSize
newSid ->
FrameHeader
-> WindowSize -> WindowSize -> IO HeaderList -> HPACKStepResult
FinishedWithPushPromise FrameHeader
curFh WindowSize
parentSid WindowSize
newSid (DynamicTable -> ByteString -> IO HeaderList
decodeHeader DynamicTable
_dispatchHPACKDynamicTable ByteString
buffer)
go FrameHeader
curFh HPACKLoopDecision
_ (Left ErrorCodeId
err) =
FrameHeader -> WindowSize -> ErrorCode -> HPACKStepResult
FailedHeaders FrameHeader
curFh WindowSize
sid (ErrorCodeId -> ErrorCode
HTTP2.fromErrorCodeId ErrorCodeId
err)
newIncomingFlowControl
:: DispatchControl
-> IO Int
-> (WindowSize -> ClientIO ())
-> IO IncomingFlowControl
newIncomingFlowControl :: DispatchControl
-> IO WindowSize
-> (WindowSize -> ClientIO ())
-> IO IncomingFlowControl
newIncomingFlowControl DispatchControl
control IO WindowSize
getBase WindowSize -> ClientIO ()
doSendUpdate = do
IORef WindowSize
creditAdded <- WindowSize -> IO (IORef WindowSize)
forall (m :: * -> *) a. MonadBase IO m => a -> m (IORef a)
newIORef WindowSize
0
IORef WindowSize
creditConsumed <- WindowSize -> IO (IORef WindowSize)
forall (m :: * -> *) a. MonadBase IO m => a -> m (IORef a)
newIORef WindowSize
0
let _addCredit :: WindowSize -> m ()
_addCredit WindowSize
n = IORef WindowSize -> (WindowSize -> (WindowSize, ())) -> m ()
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef WindowSize
creditAdded (\WindowSize
c -> (WindowSize
c WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
n, ()))
let _consumeCredit :: WindowSize -> IO WindowSize
_consumeCredit WindowSize
n = do
WindowSize
conso <- IORef WindowSize
-> (WindowSize -> (WindowSize, WindowSize)) -> IO WindowSize
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef WindowSize
creditConsumed (\WindowSize
c -> (WindowSize
c WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
n, WindowSize
c WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
n))
WindowSize
base <- IO WindowSize
getBase
WindowSize
extra <- IORef WindowSize -> IO WindowSize
forall (m :: * -> *) a. MonadBase IO m => IORef a -> m a
readIORef IORef WindowSize
creditAdded
WindowSize -> IO WindowSize
forall (m :: * -> *) a. Monad m => a -> m a
return (WindowSize -> IO WindowSize) -> WindowSize -> IO WindowSize
forall a b. (a -> b) -> a -> b
$ WindowSize
base WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
extra WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
- WindowSize
conso
let _updateWindow :: ClientIO Bool
_updateWindow = do
WindowSize
base <- Settings -> WindowSize
initialWindowSize (Settings -> WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_clientSettings (ConnectionSettings -> WindowSize)
-> ExceptT ClientError IO ConnectionSettings -> ClientIO WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> ExceptT ClientError IO ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
control
WindowSize
added <- IORef WindowSize -> ClientIO WindowSize
forall (m :: * -> *) a. MonadBase IO m => IORef a -> m a
readIORef IORef WindowSize
creditAdded
WindowSize
consumed <- IORef WindowSize -> ClientIO WindowSize
forall (m :: * -> *) a. MonadBase IO m => IORef a -> m a
readIORef IORef WindowSize
creditConsumed
let transferred :: WindowSize
transferred = WindowSize -> WindowSize -> WindowSize
forall a. Ord a => a -> a -> a
min WindowSize
added (WindowSize
HTTP2.maxWindowSize WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
- WindowSize
base WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
consumed)
let shouldUpdate :: Bool
shouldUpdate = WindowSize
transferred WindowSize -> WindowSize -> Bool
forall a. Ord a => a -> a -> Bool
> WindowSize
0
WindowSize -> ClientIO ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
_addCredit (WindowSize -> WindowSize
forall a. Num a => a -> a
negate WindowSize
transferred)
WindowSize
_ <- IO WindowSize -> ClientIO WindowSize
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO WindowSize -> ClientIO WindowSize)
-> IO WindowSize -> ClientIO WindowSize
forall a b. (a -> b) -> a -> b
$ WindowSize -> IO WindowSize
_consumeCredit (WindowSize -> WindowSize
forall a. Num a => a -> a
negate WindowSize
transferred)
Bool -> ClientIO () -> ClientIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
shouldUpdate (WindowSize -> ClientIO ()
doSendUpdate WindowSize
transferred)
Bool -> ClientIO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
shouldUpdate
IncomingFlowControl -> IO IncomingFlowControl
forall (m :: * -> *) a. Monad m => a -> m a
return (IncomingFlowControl -> IO IncomingFlowControl)
-> IncomingFlowControl -> IO IncomingFlowControl
forall a b. (a -> b) -> a -> b
$ (WindowSize -> IO ())
-> (WindowSize -> IO WindowSize)
-> ClientIO Bool
-> IncomingFlowControl
IncomingFlowControl WindowSize -> IO ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
_addCredit WindowSize -> IO WindowSize
_consumeCredit ClientIO Bool
_updateWindow
newOutgoingFlowControl ::
DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IO Int
-> IO OutgoingFlowControl
newOutgoingFlowControl :: DispatchControl
-> Chan (FrameHeader, FramePayload)
-> IO WindowSize
-> IO OutgoingFlowControl
newOutgoingFlowControl DispatchControl
control Chan (FrameHeader, FramePayload)
frames IO WindowSize
getBase = do
IORef WindowSize
credit <- WindowSize -> IO (IORef WindowSize)
forall (m :: * -> *) a. MonadBase IO m => a -> m (IORef a)
newIORef WindowSize
0
let receive :: WindowSize -> m ()
receive WindowSize
n = IORef WindowSize -> (WindowSize -> (WindowSize, ())) -> m ()
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef WindowSize
credit (\WindowSize
c -> (WindowSize
c WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
n, ()))
let withdraw :: WindowSize -> t IO WindowSize
withdraw WindowSize
0 = WindowSize -> t IO WindowSize
forall (m :: * -> *) a. Monad m => a -> m a
return WindowSize
0
withdraw WindowSize
n = do
WindowSize
base <- IO WindowSize -> t IO WindowSize
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift IO WindowSize
getBase
WindowSize
got <- IORef WindowSize
-> (WindowSize -> (WindowSize, WindowSize)) -> t IO WindowSize
forall (m :: * -> *) a b.
MonadBase IO m =>
IORef a -> (a -> (a, b)) -> m b
atomicModifyIORef' IORef WindowSize
credit (\WindowSize
c ->
if WindowSize
base WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
c WindowSize -> WindowSize -> Bool
forall a. Ord a => a -> a -> Bool
>= WindowSize
n
then (WindowSize
c WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
- WindowSize
n, WindowSize
n)
else (WindowSize
0 WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
- WindowSize
base, WindowSize
base WindowSize -> WindowSize -> WindowSize
forall a. Num a => a -> a -> a
+ WindowSize
c))
if WindowSize
got WindowSize -> WindowSize -> Bool
forall a. Ord a => a -> a -> Bool
> WindowSize
0
then WindowSize -> t IO WindowSize
forall (m :: * -> *) a. Monad m => a -> m a
return WindowSize
got
else do
Either () WindowSize
amount <- t IO () -> t IO WindowSize -> t IO (Either () WindowSize)
forall (m :: * -> *) a b.
MonadBaseControl IO m =>
m a -> m b -> m (Either a b)
race (WindowSize -> t IO ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
waitSettingsChange WindowSize
base) (Chan (FrameHeader, FramePayload) -> t IO WindowSize
forall (m :: * -> *) a.
MonadBase IO m =>
Chan (a, FramePayload) -> m WindowSize
waitSomeCredit Chan (FrameHeader, FramePayload)
frames)
WindowSize -> t IO ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
receive ((() -> WindowSize)
-> (WindowSize -> WindowSize) -> Either () WindowSize -> WindowSize
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (WindowSize -> () -> WindowSize
forall a b. a -> b -> a
const WindowSize
0) WindowSize -> WindowSize
forall a. a -> a
id Either () WindowSize
amount)
WindowSize -> t IO WindowSize
withdraw WindowSize
n
OutgoingFlowControl -> IO OutgoingFlowControl
forall (m :: * -> *) a. Monad m => a -> m a
return (OutgoingFlowControl -> IO OutgoingFlowControl)
-> OutgoingFlowControl -> IO OutgoingFlowControl
forall a b. (a -> b) -> a -> b
$ (WindowSize -> IO ())
-> (WindowSize -> ClientIO WindowSize) -> OutgoingFlowControl
OutgoingFlowControl WindowSize -> IO ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
receive WindowSize -> ClientIO WindowSize
forall (t :: (* -> *) -> * -> *).
(MonadTrans t, MonadBaseControl IO (t IO)) =>
WindowSize -> t IO WindowSize
withdraw
where
waitSettingsChange :: WindowSize -> m ()
waitSettingsChange WindowSize
prev = do
WindowSize
new <- Settings -> WindowSize
initialWindowSize (Settings -> WindowSize)
-> (ConnectionSettings -> Settings)
-> ConnectionSettings
-> WindowSize
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConnectionSettings -> Settings
_serverSettings (ConnectionSettings -> WindowSize)
-> m ConnectionSettings -> m WindowSize
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DispatchControl -> m ConnectionSettings
forall (m :: * -> *).
MonadBase IO m =>
DispatchControl -> m ConnectionSettings
readSettings DispatchControl
control
if WindowSize
new WindowSize -> WindowSize -> Bool
forall a. Eq a => a -> a -> Bool
== WindowSize
prev then WindowSize -> m ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
threadDelay WindowSize
1000000 m () -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> WindowSize -> m ()
waitSettingsChange WindowSize
prev else () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
waitSomeCredit :: Chan (a, FramePayload) -> m WindowSize
waitSomeCredit Chan (a, FramePayload)
frames = do
(a, FramePayload)
got <- Chan (a, FramePayload) -> m (a, FramePayload)
forall (m :: * -> *) a. MonadBase IO m => Chan a -> m a
readChan Chan (a, FramePayload)
frames
case (a, FramePayload)
got of
(a
_, WindowUpdateFrame WindowSize
amt) ->
WindowSize -> m WindowSize
forall (m :: * -> *) a. Monad m => a -> m a
return WindowSize
amt
(a, FramePayload)
_ ->
String -> m WindowSize
forall a. HasCallStack => String -> a
error String
"got forwarded an unknown frame"
sendHeaders
:: Http2FrameClientStream
-> HpackEncoderContext
-> HeaderList
-> PayloadSplitter
-> (FrameFlags -> FrameFlags)
-> ClientIO StreamThread
Http2FrameClientStream
s HpackEncoderContext
enc HeaderList
hdrs PayloadSplitter
blockSplitter FrameFlags -> FrameFlags
flagmod = do
Http2FrameClientStream
-> ClientIO [(FrameFlags -> FrameFlags, FramePayload)]
-> ClientIO ()
_sendFrames Http2FrameClientStream
s (IO [(FrameFlags -> FrameFlags, FramePayload)]
-> ClientIO [(FrameFlags -> FrameFlags, FramePayload)]
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift IO [(FrameFlags -> FrameFlags, FramePayload)]
mkFrames)
StreamThread -> ClientIO StreamThread
forall (m :: * -> *) a. Monad m => a -> m a
return StreamThread
CST
where
mkFrames :: IO [(FrameFlags -> FrameFlags, FramePayload)]
mkFrames = do
[ByteString]
headerBlockFragments <- PayloadSplitter
blockSplitter PayloadSplitter -> IO ByteString -> IO [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HpackEncoderContext -> HeaderList -> IO ByteString
_encodeHeaders HpackEncoderContext
enc HeaderList
hdrs
let framers :: [ByteString -> FramePayload]
framers = (Maybe Priority -> ByteString -> FramePayload
HeadersFrame Maybe Priority
forall a. Maybe a
Nothing) (ByteString -> FramePayload)
-> [ByteString -> FramePayload] -> [ByteString -> FramePayload]
forall a. a -> [a] -> [a]
: (ByteString -> FramePayload) -> [ByteString -> FramePayload]
forall a. a -> [a]
repeat ByteString -> FramePayload
ContinuationFrame
let frames :: [FramePayload]
frames = ((ByteString -> FramePayload) -> ByteString -> FramePayload)
-> [ByteString -> FramePayload] -> [ByteString] -> [FramePayload]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (ByteString -> FramePayload) -> ByteString -> FramePayload
forall a b. (a -> b) -> a -> b
($) [ByteString -> FramePayload]
framers [ByteString]
headerBlockFragments
let modifiersReversed :: [FrameFlags -> FrameFlags]
modifiersReversed = (FrameFlags -> FrameFlags
HTTP2.setEndHeader (FrameFlags -> FrameFlags)
-> (FrameFlags -> FrameFlags) -> FrameFlags -> FrameFlags
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FrameFlags -> FrameFlags
flagmod) (FrameFlags -> FrameFlags)
-> [FrameFlags -> FrameFlags] -> [FrameFlags -> FrameFlags]
forall a. a -> [a] -> [a]
: (FrameFlags -> FrameFlags) -> [FrameFlags -> FrameFlags]
forall a. a -> [a]
repeat FrameFlags -> FrameFlags
forall a. a -> a
id
let arrangedFrames :: [(FrameFlags -> FrameFlags, FramePayload)]
arrangedFrames = [(FrameFlags -> FrameFlags, FramePayload)]
-> [(FrameFlags -> FrameFlags, FramePayload)]
forall a. [a] -> [a]
reverse ([(FrameFlags -> FrameFlags, FramePayload)]
-> [(FrameFlags -> FrameFlags, FramePayload)])
-> [(FrameFlags -> FrameFlags, FramePayload)]
-> [(FrameFlags -> FrameFlags, FramePayload)]
forall a b. (a -> b) -> a -> b
$ [FrameFlags -> FrameFlags]
-> [FramePayload] -> [(FrameFlags -> FrameFlags, FramePayload)]
forall a b. [a] -> [b] -> [(a, b)]
zip [FrameFlags -> FrameFlags]
modifiersReversed ([FramePayload] -> [FramePayload]
forall a. [a] -> [a]
reverse [FramePayload]
frames)
[(FrameFlags -> FrameFlags, FramePayload)]
-> IO [(FrameFlags -> FrameFlags, FramePayload)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(FrameFlags -> FrameFlags, FramePayload)]
arrangedFrames
type PayloadSplitter = ByteString -> [ByteString]
settingsPayloadSplitter :: ConnectionSettings -> PayloadSplitter
settingsPayloadSplitter :: ConnectionSettings -> PayloadSplitter
settingsPayloadSplitter (ConnectionSettings Settings
_ Settings
srv) =
WindowSize -> PayloadSplitter
fixedSizeChunks (Settings -> WindowSize
maxFrameSize Settings
srv)
fixedSizeChunks :: Int -> ByteString -> [ByteString]
fixedSizeChunks :: WindowSize -> PayloadSplitter
fixedSizeChunks WindowSize
0 ByteString
_ = String -> [ByteString]
forall a. HasCallStack => String -> a
error String
"cannot chunk by zero-length blocks"
fixedSizeChunks WindowSize
_ ByteString
"" = []
fixedSizeChunks WindowSize
len ByteString
bstr =
let
(ByteString
chunk, ByteString
rest) = WindowSize -> ByteString -> (ByteString, ByteString)
ByteString.splitAt WindowSize
len ByteString
bstr
in
ByteString
chunk ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: WindowSize -> PayloadSplitter
fixedSizeChunks WindowSize
len ByteString
rest
sendData :: Http2Client -> Http2Stream -> FlagSetter -> ByteString -> ClientIO ()
sendData :: Http2Client
-> Http2Stream
-> (FrameFlags -> FrameFlags)
-> ByteString
-> ClientIO ()
sendData Http2Client
conn Http2Stream
stream FrameFlags -> FrameFlags
flagmod ByteString
dat = do
PayloadSplitter
splitter <- IO PayloadSplitter -> ExceptT ClientError IO PayloadSplitter
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO PayloadSplitter -> ExceptT ClientError IO PayloadSplitter)
-> IO PayloadSplitter -> ExceptT ClientError IO PayloadSplitter
forall a b. (a -> b) -> a -> b
$ Http2Client -> IO PayloadSplitter
_payloadSplitter Http2Client
conn
let chunks :: [ByteString]
chunks = PayloadSplitter
splitter ByteString
dat
let pairs :: [(FrameFlags -> FrameFlags, ByteString)]
pairs = [(FrameFlags -> FrameFlags, ByteString)]
-> [(FrameFlags -> FrameFlags, ByteString)]
forall a. [a] -> [a]
reverse ([(FrameFlags -> FrameFlags, ByteString)]
-> [(FrameFlags -> FrameFlags, ByteString)])
-> [(FrameFlags -> FrameFlags, ByteString)]
-> [(FrameFlags -> FrameFlags, ByteString)]
forall a b. (a -> b) -> a -> b
$ [FrameFlags -> FrameFlags]
-> [ByteString] -> [(FrameFlags -> FrameFlags, ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip (FrameFlags -> FrameFlags
flagmod (FrameFlags -> FrameFlags)
-> [FrameFlags -> FrameFlags] -> [FrameFlags -> FrameFlags]
forall a. a -> [a] -> [a]
: (FrameFlags -> FrameFlags) -> [FrameFlags -> FrameFlags]
forall a. a -> [a]
repeat FrameFlags -> FrameFlags
forall a. a -> a
id) ([ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse [ByteString]
chunks)
Bool -> ClientIO () -> ClientIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([ByteString] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ByteString]
chunks) (ClientIO () -> ClientIO ()) -> ClientIO () -> ClientIO ()
forall a b. (a -> b) -> a -> b
$ Http2Stream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
_sendDataChunk Http2Stream
stream FrameFlags -> FrameFlags
flagmod ByteString
""
[(FrameFlags -> FrameFlags, ByteString)]
-> ((FrameFlags -> FrameFlags, ByteString) -> ClientIO ())
-> ClientIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(FrameFlags -> FrameFlags, ByteString)]
pairs (((FrameFlags -> FrameFlags, ByteString) -> ClientIO ())
-> ClientIO ())
-> ((FrameFlags -> FrameFlags, ByteString) -> ClientIO ())
-> ClientIO ()
forall a b. (a -> b) -> a -> b
$ \(FrameFlags -> FrameFlags
flags, ByteString
chunk) -> Http2Stream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
_sendDataChunk Http2Stream
stream FrameFlags -> FrameFlags
flags ByteString
chunk
sendDataFrame
:: Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
sendDataFrame :: Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
sendDataFrame Http2FrameClientStream
s FrameFlags -> FrameFlags
flagmod ByteString
dat = do
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
flagmod (ByteString -> FramePayload
DataFrame ByteString
dat)
sendResetFrame :: Http2FrameClientStream -> ErrorCodeId -> ClientIO ()
sendResetFrame :: Http2FrameClientStream -> ErrorCodeId -> ClientIO ()
sendResetFrame Http2FrameClientStream
s ErrorCodeId
err = do
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
forall a. a -> a
id (ErrorCodeId -> FramePayload
RSTStreamFrame ErrorCodeId
err)
sendGTFOFrame
:: Http2FrameClientStream
-> StreamId -> ErrorCodeId -> ByteString -> ClientIO ()
sendGTFOFrame :: Http2FrameClientStream
-> WindowSize -> ErrorCodeId -> ByteString -> ClientIO ()
sendGTFOFrame Http2FrameClientStream
s WindowSize
lastStreamId ErrorCodeId
err ByteString
errStr = do
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
forall a. a -> a
id (WindowSize -> ErrorCodeId -> ByteString -> FramePayload
GoAwayFrame WindowSize
lastStreamId ErrorCodeId
err ByteString
errStr)
rfcError :: String -> a
rfcError :: String -> a
rfcError String
msg = String -> a
forall a. HasCallStack => String -> a
error (String
msg String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"draft-ietf-httpbis-http2-17")
sendPingFrame
:: Http2FrameClientStream
-> (FrameFlags -> FrameFlags)
-> ByteString
-> ClientIO ()
sendPingFrame :: Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
sendPingFrame Http2FrameClientStream
s FrameFlags -> FrameFlags
flags ByteString
dat
| Http2FrameClientStream -> WindowSize
_getStreamId Http2FrameClientStream
s WindowSize -> WindowSize -> Bool
forall a. Eq a => a -> a -> Bool
/= WindowSize
0 =
String -> ClientIO ()
forall a. String -> a
rfcError String
"PING frames are not associated with any individual stream."
| ByteString -> WindowSize
ByteString.length ByteString
dat WindowSize -> WindowSize -> Bool
forall a. Eq a => a -> a -> Bool
/= WindowSize
8 =
String -> ClientIO ()
forall a. String -> a
rfcError String
"PING frames MUST contain 8 octets"
| Bool
otherwise = Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
flags (ByteString -> FramePayload
PingFrame ByteString
dat)
sendWindowUpdateFrame
:: Http2FrameClientStream -> WindowSize -> ClientIO ()
sendWindowUpdateFrame :: Http2FrameClientStream -> WindowSize -> ClientIO ()
sendWindowUpdateFrame Http2FrameClientStream
s WindowSize
amount = do
let payload :: FramePayload
payload = WindowSize -> FramePayload
WindowUpdateFrame WindowSize
amount
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
forall a. a -> a
id FramePayload
payload
() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sendSettingsFrame
:: Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> SettingsList -> ClientIO ()
sendSettingsFrame :: Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> SettingsList -> ClientIO ()
sendSettingsFrame Http2FrameClientStream
s FrameFlags -> FrameFlags
flags SettingsList
setts
| Http2FrameClientStream -> WindowSize
_getStreamId Http2FrameClientStream
s WindowSize -> WindowSize -> Bool
forall a. Eq a => a -> a -> Bool
/= WindowSize
0 =
String -> ClientIO ()
forall a. String -> a
rfcError String
"The stream identifier for a SETTINGS frame MUST be zero (0x0)."
| Bool
otherwise = do
let payload :: FramePayload
payload = SettingsList -> FramePayload
SettingsFrame SettingsList
setts
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
flags FramePayload
payload
() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
sendPriorityFrame :: Http2FrameClientStream -> Priority -> ClientIO ()
sendPriorityFrame :: Http2FrameClientStream -> Priority -> ClientIO ()
sendPriorityFrame Http2FrameClientStream
s Priority
p = do
let payload :: FramePayload
payload = Priority -> FramePayload
PriorityFrame Priority
p
Http2FrameClientStream
-> (FrameFlags -> FrameFlags) -> FramePayload -> ClientIO ()
sendOne Http2FrameClientStream
s FrameFlags -> FrameFlags
forall a. a -> a
id FramePayload
payload
() -> ClientIO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
delayException :: ClientIO a -> ClientIO a
delayException :: ClientIO a -> ClientIO a
delayException ClientIO a
act = ClientIO a
act ClientIO a -> (SomeException -> ClientIO a) -> ClientIO a
forall (m :: * -> *) e a.
(MonadBaseControl IO m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` SomeException -> ClientIO a
forall a. SomeException -> ClientIO a
slowdown
where
slowdown :: SomeException -> ClientIO a
slowdown :: SomeException -> ClientIO a
slowdown SomeException
e = WindowSize -> ClientIO ()
forall (m :: * -> *). MonadBase IO m => WindowSize -> m ()
threadDelay WindowSize
50000 ClientIO () -> ClientIO a -> ClientIO a
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> SomeException -> ClientIO a
forall (m :: * -> *) e a. (MonadBase IO m, Exception e) => e -> m a
throwIO SomeException
e