Search results

There are no results.

std.net.http.client.WebsocketRequest

type pub inline WebsocketRequest

A type for upgrading an HTTP connection to a WebSocket connection.

Instance methods

header

Show source code
Hide source code
fn pub move header(header: Header, value: String) -> Self {
  @request.headers.add(header, value)
  self
}
fn pub move header(header: Header, value: String) -> WebsocketRequest

Adds the header with the given value.

Refer to the documentation of std.net.http.HeaderMap.add for more details.

protocols

Show source code
Hide source code
fn pub move protocols(values: Array[String]) -> Self {
  for value in values { @protocols.insert(value) }

  self
}
fn pub move protocols(values: Array[String]) -> WebsocketRequest

Adds the given protocols to the protocols supported by the server.

Examples

import std.net.http.client (Client)
import std.uri (Uri)

type async Main {
  fn async main {
    let client = Client.new
    let uri = Uri.parse('https://echo.websocket.org').or_panic

    client.websocket(uri).protocols(['foo', 'bar']).send.or_panic
  }
}

query

Show source code
Hide source code
fn pub move query(key: String, value: String) -> Self {
  @request.query.add(key, value)
  self
}
fn pub move query(key: String, value: String) -> WebsocketRequest

Adds a query string parameter and value to self.

Refer to the documentation of std.uri.Values.add for more details.

send

Show source code
Hide source code
fn pub move send -> Result[
  (Websocket[WebsocketConnection], Response),
  WebsocketError,
] {
  let buf = ByteArray.new
  let key = ByteArray.new
  let enc = Encoder.new

  @request.client.random.bytes(into: buf, size: 16)
  enc.encode(buf, into: key)
  buf.clear

  let key = key.into_string

  enc.encode(Sha1.hash(key + WEBSOCKET_KEY).bytes, into: buf)

  @request.headers.set(Header.connection, 'upgrade')
  @request.headers.set(Header.upgrade, 'websocket')
  @request.headers.set(Header.sec_websocket_key, key)
  @request.headers.set(Header.sec_websocket_version, WEBSOCKET_VERSION)

  if @protocols.size > 0 {
    let proto = String.join(@protocols.iter, ', ')

    @request.headers.set(Header.sec_websocket_protocol, proto)
  }

  let rng = @request.client.random
  let (resp, con) = match @request.send_with_body('') {
    case Ok(v) -> v
    case Error(e) -> throw WebsocketError.Other(e)
  }

  match resp.status.to_int {
    case
      101
    if header_eq(resp, Header.upgrade, 'websocket')
      and header_eq(resp, Header.connection, 'upgrade')
      and header_eq(resp, Header.sec_websocket_accept, buf)
    -> {}
    case 101 -> throw WebsocketError.InvalidHandshake
    case _ -> throw WebsocketError.ServerError(resp.status)
  }

  # For websockets the connection is managed by the Websocket that we return,
  # not the Response.
  con.state = State.Websocket

  # Extensions are not supported at this time.
  if resp.headers.get(Header.sec_websocket_extensions).ok? {
    throw WebsocketError.InvalidExtension
  }

  let proto = match resp.headers.get(Header.sec_websocket_protocol) {
    case Ok(v) if @protocols.contains?(v) -> Option.Some(v.to_slice)
    case Ok(_) -> throw WebsocketError.InvalidProtocol
    case _ -> Option.None
  }

  let ws = Websocket.client(WebsocketConnection(con), rng, proto)

  return Result.Ok((ws, resp))
}
fn pub move send -> Result[(Websocket[WebsocketConnection], Response), WebsocketError]

Sends the request and returns a websocket and its raw response.

The returned Response is the response returned by the server. This is returned such that additional data (e.g. headers) can be used if necessary.

When the Websocket is dropped the underlying connection is closed.