http2-client- A native HTTP2 client library.

Safe HaskellNone




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 .



runHttp2Client Source #


:: 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 -> IO a)

Actions to run on the client.

-> IO a 

Starts a new Http2Client around a frame connection.

This is mostly useful if you want to muck around the Http2FrameConnection (e.g., for tracing frames) as well as for unit testing purposes. If you want to create a new connection you should likely use newHttp2Client instead.

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 -> IO 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 ""

Note that we currently enforce the setEndHeader but this design choice may change in the future. Hence, we recommend you use setEndHeader as well.

sendData :: Http2Client -> Http2Stream -> FlagSetter -> ByteString -> IO () 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 streams

data Http2Client Source #

Record holding functions one can call while in an HTTP2 client session.




type PushPromiseHandler = StreamId -> Http2Stream -> HeaderList -> IncomingFlowControl -> OutgoingFlowControl -> IO () 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.




  • _initStream :: IO StreamThread

    Function to initialize a new client stream. This function runs in a exclusive-access section of the code and may prevent other threads to initialize new streams. Hence, you should ensure this IO does not wait for long periods of time.

  • _handleStream :: IncomingFlowControl -> OutgoingFlowControl -> IO a

    Function to operate with the stream. IncomingFlowControl currently is credited on your behalf as soon as a DATA frame arrives (and before you handle it with _waitData). However we do not send WINDOW_UPDATE with _updateWindow. This design may change in the future to give more leeway to library users.

type StreamStarter a = (Http2Stream -> StreamDefinition a) -> IO (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.

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.




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).




  • _addCredit :: WindowSize -> IO ()

    Add credit (using a hidden mutable reference underneath). This function only does accounting, the IO only does mutable changes. See _updateWindow.

  • _consumeCredit :: WindowSize -> IO Int

    Consumes some credit and returns the credit left.

  • _updateWindow :: IO Bool

    Sends a WINDOW_UPDATE frame crediting it with the whole amount credited since the last _updateWindow call. The boolean tells whether an update was actually sent or not. A reason for not sending an update is if there is no credit in the flow-control system.

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).




  • _receiveCredit :: WindowSize -> IO ()

    Add credit (using a hidden mutable reference underneath).

  • _withdrawCredit :: WindowSize -> IO WindowSize

    Wait until we can take credit from stash. The returned value correspond to the amount that could be withdrawn, which is min(current, wanted). A caller should withdraw credit to send DATA chunks and put back any unused credit with _receiveCredit.


linkAsyncs :: Http2Client -> IO () Source #

Links all client's asyncs to current thread.

type GoAwayHandler = RemoteSentGoAwayFrame -> IO () 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.


type FallBackFrameHandler = (FrameHeader, FramePayload) -> IO () 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.




Convenience re-exports