http-io-streams-0.1.6.1: HTTP and WebSocket client based on io-streams
Copyright© 2020 Herbert Valerio Riedel
LicenseGPL-2.0-or-later
Safe HaskellSafe-Inferred
LanguageHaskell2010

Network.Http.Client.WebSocket

Description

Basic WebSocket RFC 6455 support.

Since: 0.1.4.0

Synopsis

WebSocket Frames

WebSocket Frame Header

data WSFrameHdr Source #

WebSocket Frame as per RFC 6455 section 5.2

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Since: 0.1.4.0

Constructors

WSFrameHdr 

Fields

  • ws'FIN :: !Bool

    MUST be set for control-frames (control-frames MUST NOT be fragmented).

  • ws'RSV1 :: !Bool
     
  • ws'RSV2 :: !Bool
     
  • ws'RSV3 :: !Bool
     
  • ws'opcode :: !WSOpcode
     
  • ws'length :: !Word64

    MUST be smaller than 2^63 for data-frames; MUST be smaller than 126 for control-frames.

  • ws'mask :: !(Maybe Word32)

    Whether the frame is masked and which masking key is used; Nothing denotes unmasked frames.

    A client MUST mask all frames that it sends to the server; A server MUST NOT mask any frames that it sends to the client.

Instances

Instances details
Show WSFrameHdr Source # 
Instance details

Defined in Network.Http.Client.WebSocket

Binary WSFrameHdr Source # 
Instance details

Defined in Network.Http.Client.WebSocket

wsFrameHdrSize :: WSFrameHdr -> Int Source #

Size of serialized WebSocket frame header (i.e. without payload data) in octets.

Since: 0.1.4.0

data WSOpcode Source #

WebSocket frame opcode.

See also wsIsDataFrame.

Since: 0.1.4.0

Constructors

WSOpcode'Continuation

data fragmented data-frame

WSOpcode'Text

data payload must utf-8 encoded

WSOpcode'Binary

data binary data payload

WSOpcode'Close

control connection close frame (optional payload with reason-code)

WSOpcode'Ping

control PING frame

WSOpcode'Pong

control PONG frame

WSOpcode'Reserved !WSOpcodeReserved

reserved frame kind not defined by RFC 6455

Instances

Instances details
Show WSOpcode Source # 
Instance details

Defined in Network.Http.Client.WebSocket

Eq WSOpcode Source # 
Instance details

Defined in Network.Http.Client.WebSocket

wsIsDataFrame :: WSOpcode -> Bool Source #

Whether WSOpcode denotes a data-frame.

There are two kinds of WebSocket frames, data-frames and control-frames. Consequently, this predicate is False for control-frames.

Since: 0.1.4.0

Mid-level I/O primitives

Sending WebSocket frames

writeWSFrame :: Connection -> WSOpcode -> Maybe Word32 -> ByteString -> IO () Source #

Convenience function for writing simple non-fragmented frames to an established WebSocket connection.

Control-frames MUST have a payload smaller than 126 bytes.

Since: 0.1.4.0

sendWSFragData :: Connection -> WSFrameHdr -> (OutputStream ByteString -> IO a) -> IO a Source #

Send WebSocket message as fragmented data-frames.

This function can be used if the size of the data payload to be sent is not known in advance.

This operation does not flush automatically after every chunk; write an empty chunk to the OutputStream to trigger flushing pending data onto the WebSocket connection.

The ws'length and ws'FIN fields are ignored and computed from the chunks to be sent.

Pre-conditions:

Since: 0.1.4.0

Receiving WebSocket frames

readWSFrame :: Int -> Connection -> IO (Maybe (WSFrameHdr, ByteString)) Source #

Convenience function for reading a single (possibly fragmented) frame from an established WebSocket connection.

The first argument is the maximum expected frame size to receive; if a larger frame is encountered an exception is raised.

This operation does not perform any defragmentation nor automatically deal with control-frames (those will be returned to the caller as-is).

Returns Nothing if the InputStream is terminated before reading the first octet.

Since: 0.1.4.0

receiveWSFrame :: Connection -> (WSFrameHdr -> InputStream ByteString -> IO a) -> IO (Maybe a) Source #

Receive a single WebSocket frame as InputStream.

This operation does not perform any defragmentation nor automatically deal with control-frames (those will be returned to the caller as-is).

See also readWSFrame for a simple non-streaming version.

Since: 0.1.4.0

WebSocket handshake

HTTP/1.1 WebSocket connection upgrade

wsUpgradeConnection Source #

Arguments

:: Connection

Connection in HTTP/1.1 protocol state (i.e. not yet upgraded)

-> ByteString

resource name (i.e. the argument to the GET verb)

-> RequestBuilder α

Additional Handshake request builder operations (i.e. to add additional HTTP headers to Handshake HTTP request)

-> SecWebSocketKey

The sec-websocket-key value to use

-> (Response -> InputStream ByteString -> IO b)

failure continuation if handshake fails with a non-101 response code

-> (Response -> Connection -> IO b)

success continuation; the Connection has been succesfully upgraded to WebSocket mode and only WebSocket operations shall be performed over this Connection.

-> IO b 

Perform an opening WebSocket handshake as per RFC 6455 section 4

This operation sets the host, upgrade, connection, sec-websocket-version, sec-websocket-key HTTP headers; if you need to customize the handshake request further use the BuildRequest-modifier argument to inject more headers into the request.

Since: 0.1.4.0

Low-level primitives for WebSocket handshake

wsKeyToAcceptB64 :: SecWebSocketKey -> ByteString Source #

Compute Sec-WebSocket-Accept header value from Sec-WebSocket-Key header value according to RFC 6455

>>> wsKeyToAcceptB64 <$> secWebSocketKeyFromB64 "dGhlIHNhbXBsZSBub25jZQ=="
Just "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="

Since: 0.1.4.0

secWebSocketKeyFromB64 :: ByteString -> Maybe SecWebSocketKey Source #

Construct SecWebSocketKey from its HTTP header base64 representation.

The input must be a valid Sec-WebSocket-Key value, i.e. a base64 encoded 16-octet value (i.e. 24 base64 characters) with optional surrounding whitespace (TAB or SPC) characters or this function will return Nothing.

Since: 0.1.4.0

secWebSocketKeyToB64 :: SecWebSocketKey -> ByteString Source #

Emit SecWebSocketKey as base64-encoded value suitable for use in the Sec-WebSocket-Accept HTTP header.

Since: 0.1.4.0

secWebSocketKeyFromWords :: Word64 -> Word64 -> SecWebSocketKey Source #

Construct SecWebSocketKey from two Word64 values.

Since: 0.1.4.0

Exception

data WsException Source #

Exception type thrown by WebSocket routines.

These exceptions mostly denote WebSocket protocol violations from either side, client and server.

Since: 0.1.4.0

Constructors

WsException String