http2-client-0.8.0.1: A native HTTP2 client library.

Safe HaskellNone
LanguageHaskell2010

Network.HTTP2.Client

Contents

Description

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

Basics

runHttp2Client Source #

Arguments

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

newHttp2Client Source #

Arguments

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

-> IO 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 -> 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 "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) -> IO () Source #

Sends HTTP trailers.

Trailers should be the last thing sent over a stream.

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 clients

data Http2Client Source #

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

Constructors

Http2Client 

Fields

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.

Constructors

StreamDefinition 

Fields

  • _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.

Constructors

Http2Stream 

Fields

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

Constructors

IncomingFlowControl 

Fields

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

Constructors

OutgoingFlowControl 

Fields

  • _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.

Exceptions

linkAsyncs :: Http2Client -> IO () Source #

Links all client's asyncs to current thread using: link someUnderlyingAsync .

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.

Misc.

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.

Constructors

Http2ClientAsyncs 

Fields

Convenience re-exports

type HostName = String #

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 #

Use the Num instance (i.e. use a literal) to create a PortNumber value with the correct network-byte-ordering. You should not use the PortNum constructor. It will be removed in the next release.

>>> 1 :: PortNumber
1
>>> read "1" :: PortNumber
1
Instances
Enum PortNumber 
Instance details

Defined in Network.Socket.Types

Eq PortNumber 
Instance details

Defined in Network.Socket.Types

Integral PortNumber 
Instance details

Defined in Network.Socket.Types

Num PortNumber 
Instance details

Defined in Network.Socket.Types

Ord PortNumber 
Instance details

Defined in Network.Socket.Types

Read PortNumber 
Instance details

Defined in Network.Socket.Types

Real PortNumber 
Instance details

Defined in Network.Socket.Types

Show PortNumber 
Instance details

Defined in Network.Socket.Types

Storable PortNumber 
Instance details

Defined in Network.Socket.Types