Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module defines a set of low-level primitives for starting an HTTP2 session and interacting with a server.
For higher-level primitives, please refer to Network.HTTP2.Client.Helpers .
Synopsis
- runHttp2Client :: Http2FrameConnection -> Int -> Int -> SettingsList -> GoAwayHandler -> FallBackFrameHandler -> (Http2Client -> ClientIO a) -> ClientIO a
- newHttp2Client :: Http2FrameConnection -> Int -> Int -> SettingsList -> GoAwayHandler -> FallBackFrameHandler -> ClientIO Http2Client
- withHttp2Stream :: Http2Client -> StreamStarter a
- headers :: Http2Stream -> HeaderList -> FlagSetter -> ClientIO StreamThread
- trailers :: Http2Stream -> HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO ()
- sendData :: Http2Client -> Http2Stream -> FlagSetter -> ByteString -> ClientIO ()
- data Http2Client = Http2Client {
- _ping :: ByteString -> ClientIO (ClientIO (FrameHeader, FramePayload))
- _settings :: SettingsList -> ClientIO (ClientIO (FrameHeader, FramePayload))
- _goaway :: ErrorCodeId -> ByteString -> ClientIO ()
- _startStream :: forall a. StreamStarter a
- _incomingFlowControl :: IncomingFlowControl
- _outgoingFlowControl :: OutgoingFlowControl
- _payloadSplitter :: IO PayloadSplitter
- _asyncs :: !Http2ClientAsyncs
- _close :: ClientIO ()
- type PushPromiseHandler = StreamId -> Http2Stream -> HeaderList -> IncomingFlowControl -> OutgoingFlowControl -> ClientIO ()
- data StreamDefinition a = StreamDefinition {}
- type StreamStarter a = (Http2Stream -> StreamDefinition a) -> ClientIO (Either TooMuchConcurrency a)
- newtype TooMuchConcurrency = TooMuchConcurrency {}
- data StreamThread
- data Http2Stream = Http2Stream {
- _headers :: HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO StreamThread
- _prio :: Priority -> ClientIO ()
- _rst :: ErrorCodeId -> ClientIO ()
- _waitEvent :: ClientIO StreamEvent
- _sendDataChunk :: (FrameFlags -> FrameFlags) -> ByteString -> ClientIO ()
- _handlePushPromise :: StreamId -> HeaderList -> PushPromiseHandler -> ClientIO ()
- data IncomingFlowControl = IncomingFlowControl {
- _addCredit :: WindowSize -> IO ()
- _consumeCredit :: WindowSize -> IO Int
- _updateWindow :: ClientIO Bool
- data OutgoingFlowControl = OutgoingFlowControl {
- _receiveCredit :: WindowSize -> IO ()
- _withdrawCredit :: WindowSize -> ClientIO WindowSize
- linkAsyncs :: Http2Client -> ClientIO ()
- data RemoteSentGoAwayFrame = RemoteSentGoAwayFrame !StreamId !ErrorCodeId !ByteString
- type GoAwayHandler = RemoteSentGoAwayFrame -> ClientIO ()
- defaultGoAwayHandler :: GoAwayHandler
- type FallBackFrameHandler = (FrameHeader, FramePayload) -> ClientIO ()
- ignoreFallbackHandler :: FallBackFrameHandler
- type FlagSetter = FrameFlags -> FrameFlags
- data Http2ClientAsyncs = Http2ClientAsyncs {}
- _gtfo :: Http2Client -> ErrorCodeId -> ByteString -> ClientIO ()
- data StreamEvent
- module Network.HTTP2.Client.FrameConnection
- module Network.HTTP2.Client.Exceptions
- type HostName = String
- data PortNumber
- data ClientParams
Basics
:: Http2FrameConnection | A frame connection. |
-> Int | The buffersize for the Network.HPACK encoder. |
-> Int | The buffersize for the Network.HPACK decoder. |
-> SettingsList | Initial SETTINGS that are sent as first frame. |
-> GoAwayHandler | Actions to run when the remote sends a GoAwayFrame |
-> FallBackFrameHandler | Actions to run when a control frame is not yet handled in http2-client lib (e.g., PRIORITY frames). |
-> (Http2Client -> ClientIO a) | Actions to run on the client. |
-> ClientIO a |
Starts a new Http2Client around a frame connection.
This function is slightly safer than startHttp2Client
because it uses
withAsync
instead of
async
; plus this function calls linkAsyncs
to
make sure that a network error kills the controlling thread. However, this
with-pattern takes the control of the thread and can be annoying at times.
This function tries to finalize the client with a call to _close
, a second
call to _close
will trigger an IOException because the Handle representing
the TCP connection will be closed.
:: Http2FrameConnection | A frame connection. |
-> Int | The buffersize for the Network.HPACK encoder. |
-> Int | The buffersize for the Network.HPACK decoder. |
-> SettingsList | Initial SETTINGS that are sent as first frame. |
-> GoAwayHandler | Actions to run when the remote sends a GoAwayFrame |
-> FallBackFrameHandler | Actions to run when a control frame is not yet handled in http2-client lib (e.g., PRIORITY frames). |
-> ClientIO Http2Client |
Starts a new Http2Client around a frame connection.
You may want to linkAsyncs
for a proper and automated cleanup of the
underlying threads.
withHttp2Stream :: Http2Client -> StreamStarter a Source #
Starts a new stream (i.e., one HTTP request + server-pushes).
You will typically call the returned StreamStarter
immediately to define
what you want to do with the Http2Stream.
_ (withHttp2Stream myClient $ stream - StreamDefinition _ _)
Please refer to StreamStarter
and StreamDefinition
for more.
headers :: Http2Stream -> HeaderList -> FlagSetter -> ClientIO StreamThread Source #
Sends the HTTP2+HTTP headers of your chosing.
You must add HTTP2 pseudo-headers first, followed by your typical HTTP headers. This function makes no verification of this ordering/exhaustinevess.
HTTP2 pseudo-headers replace the HTTP verb + parsed url as follows: ":method" such as GET, ":scheme" such as "https", ":path" such as "blogpost/1234?foo=bar", ":authority" such as "haskell.org"
Note that we currently enforce the setEndHeader
but this design
choice may change in the future. Hence, we recommend you use
setEndHeader
as well.
trailers :: Http2Stream -> HeaderList -> (FrameFlags -> FrameFlags) -> ClientIO () Source #
Sends HTTP trailers.
Trailers should be the last thing sent over a stream.
sendData :: Http2Client -> Http2Stream -> FlagSetter -> ByteString -> ClientIO () Source #
Sends data, chunked according to the server's preferred chunk size.
This function does not respect HTTP2 flow-control and send chunks
sequentially. Hence, you should first ensure that you have enough
flow-control credit (with _withdrawCredit
) or risk a connection failure.
When you call _withdrawCredit keep in mind that HTTP2 has flow control at
the stream and at the connection level. If you use `http2-client` in a
multithreaded conext, you should avoid starving the connection-level
flow-control.
If you want to send bytestrings that fit in RAM, you can use
upload
as a function that implements
flow-control.
This function does not send frames back-to-back, that is, other frames may get interleaved between two chunks (for instance, to give priority to other streams, although no priority queue exists in `http2-client` so far).
Please refer to _sendDataChunk
and _withdrawCredit
as well.
Starting clients
data Http2Client Source #
Record holding functions one can call while in an HTTP2 client session.
Http2Client | |
|
type PushPromiseHandler = StreamId -> Http2Stream -> HeaderList -> IncomingFlowControl -> OutgoingFlowControl -> ClientIO () Source #
Handler upon receiving a PUSH_PROMISE from the server.
The functions for Http2Stream
are similar to those used in ''. But callers
shall not use _headers
to initialize the PUSH_PROMISE stream. Rather,
callers should waitHeaders
or _rst
to reject the PUSH_PROMISE.
The StreamId corresponds to the parent stream as PUSH_PROMISEs are tied to a
client-initiated stream. Longer term we may move passing this handler to the
_startStream
instead of newHttp2Client
(as it is for now).
Starting streams
data StreamDefinition a Source #
Defines a client stream.
Please red the doc for this record fields and then see StreamStarter
.
StreamDefinition | |
|
type StreamStarter a = (Http2Stream -> StreamDefinition a) -> ClientIO (Either TooMuchConcurrency a) Source #
Type alias for callback-based functions starting new streams.
The callback a user must provide takes an Http2Stream
and returns a
StreamDefinition
. This construction may seem wrong because a StreamDefinition
contains an initialization and a handler functions. The explanation for this
twistedness is as follows: in HTTP2 stream-ids must be monotonically
increasing, if we want to support multi-threaded clients we need to
serialize access to a critical region of the code when clients send
HEADERS+CONTINUATIONs frames.
Passing the Http2Stream
object as part of the callback avoids leaking the
implementation of the critical region, meanwhile, the StreamDefinition
delimits this critical region.
newtype TooMuchConcurrency Source #
Whether or not the client library believes the server will reject the new
stream. The Int content corresponds to the number of streams that should end
before accepting more streams. A reason this number can be more than zero is
that servers can change (and hence reduce) the advertised number of allowed
maxConcurrentStreams
at any time.
Instances
Show TooMuchConcurrency Source # | |
Defined in Network.HTTP2.Client showsPrec :: Int -> TooMuchConcurrency -> ShowS # show :: TooMuchConcurrency -> String # showList :: [TooMuchConcurrency] -> ShowS # |
data StreamThread Source #
Opaque proof that a client stream was initialized.
This type is only useful to force calling _headers
in _initStream
and
contains no information.
data Http2Stream Source #
Record holding functions one can call while in an HTTP2 client stream.
Http2Stream | |
|
Flow control
data IncomingFlowControl Source #
Offers credit-based flow-control.
Any mutable changes are atomic and hence work as intended in a multithreaded setup.
The design of the flow-control mechanism is subject to changes. One
important thing to keep in mind with current implementation is that both the
connection and streams are credited with _addCredit
as soon as DATA frames
arrive, hence no-need to account for the DATA frames (but you can account
for delay-bandwidth product for instance).
IncomingFlowControl | |
|
data OutgoingFlowControl Source #
Receives credit-based flow-control or block.
There is no way to observe the total amount of credit and receive/withdraw
are atomic hence this object is thread-safe. However we plan to propose an
STM-based API to allow withdrawing atomically from both the connection and a
per-stream OutgoingFlowControl
objects at a same time. Without such
atomicity one must ensure consumers do not exhaust the connection credit
before taking the per-stream credit (else they might prevent others sending
data without taking any).
Longer term we plan to hide outgoing-flow-control increment/decrement altogether because exception between withdrawing credit and sending DATA could mean lost credit (and hence hanging streams).
OutgoingFlowControl | |
|
Exceptions
linkAsyncs :: Http2Client -> ClientIO () Source #
Links all client's asyncs to current thread using:
link someUnderlyingAsync
.
data RemoteSentGoAwayFrame Source #
An exception thrown when the server sends a GoAwayFrame.
Instances
Show RemoteSentGoAwayFrame Source # | |
Defined in Network.HTTP2.Client.Dispatch showsPrec :: Int -> RemoteSentGoAwayFrame -> ShowS # show :: RemoteSentGoAwayFrame -> String # showList :: [RemoteSentGoAwayFrame] -> ShowS # | |
Exception RemoteSentGoAwayFrame Source # | |
type GoAwayHandler = RemoteSentGoAwayFrame -> ClientIO () Source #
A Handler for exceptional circumstances.
defaultGoAwayHandler :: GoAwayHandler Source #
Default GoAwayHandler throws a RemoteSentGoAwayFrame
in the current
thread.
A probably sharper handler if you want to abruptly stop any operation is to
get the ThreadId
of the main client thread and using
throwTo
.
There's an inherent race condition when receiving a GoAway frame because the server will likely close the connection which will lead to TCP errors as well.
Misc.
type FallBackFrameHandler = (FrameHeader, FramePayload) -> ClientIO () Source #
A fallback handler for frames.
ignoreFallbackHandler :: FallBackFrameHandler Source #
Default FallBackFrameHandler that ignores frames.
type FlagSetter = FrameFlags -> FrameFlags Source #
Type synonym for functions that modify flags.
Typical FlagSetter for library users are HTTP2.setEndHeader when sending headers HTTP2.setEndStream to signal that there the client is not willing to send more data.
We might use Endo in the future.
data Http2ClientAsyncs Source #
Set of Async threads running an Http2Client.
This asyncs are linked to the thread where the Http2Client is created.
If you modify this structure to add more Async, please also modify
linkAsyncs
accordingly.
Http2ClientAsyncs | |
|
_gtfo :: Http2Client -> ErrorCodeId -> ByteString -> ClientIO () Source #
Convenience re-exports
data StreamEvent Source #
StreamHeadersEvent !FrameHeader !HeaderList | |
StreamPushPromiseEvent !FrameHeader !StreamId !HeaderList | |
StreamDataEvent !FrameHeader ByteString | |
StreamErrorEvent !FrameHeader ErrorCode |
Instances
Show StreamEvent Source # | |
Defined in Network.HTTP2.Client.Dispatch showsPrec :: Int -> StreamEvent -> ShowS # show :: StreamEvent -> String # showList :: [StreamEvent] -> ShowS # |
Either a host name e.g., "haskell.org"
or a numeric host
address string consisting of a dotted decimal IPv4 address or an
IPv6 address e.g., "192.168.0.1"
.
data PortNumber #
Port number.
Use the Num
instance (i.e. use a literal) to create a
PortNumber
value.
>>>
1 :: PortNumber
1>>>
read "1" :: PortNumber
1>>>
show (12345 :: PortNumber)
"12345">>>
50000 < (51000 :: PortNumber)
True>>>
50000 < (52000 :: PortNumber)
True>>>
50000 + (10000 :: PortNumber)
60000
Instances
data ClientParams #
Instances
Show ClientParams | |
Defined in Network.TLS.Parameters showsPrec :: Int -> ClientParams -> ShowS # show :: ClientParams -> String # showList :: [ClientParams] -> ShowS # | |
TLSParams ClientParams | |
Defined in Network.TLS.Context getTLSCommonParams :: ClientParams -> CommonParams getTLSRole :: ClientParams -> Role doHandshake :: ClientParams -> Context -> IO () doHandshakeWith :: ClientParams -> Context -> Handshake -> IO () doRequestCertificate :: ClientParams -> Context -> IO Bool doPostHandshakeAuthWith :: ClientParams -> Context -> Handshake13 -> IO () |