class EventMachine::WebSocket::Connection

Constants

BINARY
ENCODING_SUPPORTED

Cache encodings since it's moderately expensive to look them up each time

UTF8

Attributes

max_frame_size[W]

Public Class Methods

new(options) click to toggle source
# File lib/em-websocket/connection.rb, line 41
def initialize(options)
  @options = options
  @debug = options[:debug] || false
  @secure = options[:secure] || false
  @secure_proxy = options[:secure_proxy] || false
  @tls_options = options[:tls_options] || {}
  @close_timeout = options[:close_timeout]

  @handler = nil

  debug [:initialize]
end

Public Instance Methods

close(code = nil, body = nil) click to toggle source

Use this method to close the websocket connection cleanly This sends a close frame and waits for acknowlegement before closing the connection

# File lib/em-websocket/connection.rb, line 57
def close(code = nil, body = nil)
  if code && !acceptable_close_code?(code)
    raise "Application code may only use codes from 1000, 3000-4999"
  end

  close_websocket_private(code, body)
end
Also aliased as: close_websocket
close_timeout() click to toggle source
# File lib/em-websocket/connection.rb, line 251
def close_timeout
  @close_timeout || WebSocket.close_timeout
end
close_websocket(code = nil, body = nil)

Deprecated, to be removed in version 0.6

Alias for: close
dispatch(data) click to toggle source
# File lib/em-websocket/connection.rb, line 101
def dispatch(data)
  if data.match(/\A<policy-file-request\s*\/>/)
    send_flash_cross_domain_file
  else
    @handshake ||= begin
      handshake = Handshake.new(@secure || @secure_proxy)

      handshake.callback { |upgrade_response, handler_klass|
        debug [:accepting_ws_version, handshake.protocol_version]
        debug [:upgrade_response, upgrade_response]
        self.send_data(upgrade_response)
        @handler = handler_klass.new(self, @debug)
        @handshake = nil
        trigger_on_open(handshake)
      }

      handshake.errback { |e|
        debug [:error, e]
        trigger_on_error(e)
        # Handshake errors require the connection to be aborted
        abort
      }

      handshake
    end

    @handshake.receive_data(data)
  end
end
max_frame_size() click to toggle source

Returns the maximum frame size which this connection is configured to accept. This can be set globally or on a per connection basis, and defaults to a value of 10MB if not set.

The behaviour when a too large frame is received varies by protocol, but in the newest protocols the connection will be closed with the correct close code (1009) immediately after receiving the frame header

# File lib/em-websocket/connection.rb, line 247
def max_frame_size
  defined?(@max_frame_size) ? @max_frame_size : WebSocket.max_frame_size
end
onbinary(&blk) click to toggle source
# File lib/em-websocket/connection.rb, line 13
def onbinary(&blk);   @onbinary = blk; end
onclose(&blk) click to toggle source
# File lib/em-websocket/connection.rb, line 10
def onclose(&blk);    @onclose = blk;   end
onerror(&blk) click to toggle source
# File lib/em-websocket/connection.rb, line 11
def onerror(&blk);    @onerror = blk;   end
onmessage(&blk) click to toggle source
# File lib/em-websocket/connection.rb, line 12
def onmessage(&blk);  @onmessage = blk; end
onopen(&blk) click to toggle source

define WebSocket callbacks

# File lib/em-websocket/connection.rb, line 9
def onopen(&blk);     @onopen = blk;    end
onping(&blk) click to toggle source
# File lib/em-websocket/connection.rb, line 14
def onping(&blk);     @onping = blk;    end
onpong(&blk) click to toggle source
# File lib/em-websocket/connection.rb, line 15
def onpong(&blk);     @onpong = blk;    end
ping(body = '') click to toggle source

Send a ping to the client. The client must respond with a pong.

In the case that the client is running a WebSocket draft < 01, false is returned since ping & pong are not supported

# File lib/em-websocket/connection.rb, line 195
def ping(body = '')
  if @handler
    @handler.pingable? ? @handler.send_frame(:ping, body) && true : false
  else
    raise WebSocketError, "Cannot ping before onopen callback"
  end
end
pingable?() click to toggle source

Test whether the connection is pingable (i.e. the WebSocket draft in use is >= 01)

# File lib/em-websocket/connection.rb, line 219
def pingable?
  if @handler
    @handler.pingable?
  else
    raise WebSocketError, "Cannot test whether pingable before onopen callback"
  end
end
pong(body = '') click to toggle source

Send an unsolicited pong message, as allowed by the protocol. The client is not expected to respond to this message.

em-websocket automatically takes care of sending pong replies to incoming ping messages, as the protocol demands.

# File lib/em-websocket/connection.rb, line 209
def pong(body = '')
  if @handler
    @handler.pingable? ? @handler.send_frame(:pong, body) && true : false
  else
    raise WebSocketError, "Cannot ping before onopen callback"
  end
end
post_init() click to toggle source
# File lib/em-websocket/connection.rb, line 68
def post_init
  start_tls(@tls_options) if @secure
end
receive_data(data) click to toggle source
# File lib/em-websocket/connection.rb, line 72
def receive_data(data)
  debug [:receive_data, data]

  if @handler
    @handler.receive_data(data)
  else
    dispatch(data)
  end
rescue => e
  debug [:error, e]

  # There is no code defined for application errors, so use 3000
  # (which is reserved for frameworks)
  close_websocket_private(3000, "Application error")

  # These are application errors - raise unless onerror defined
  trigger_on_error(e) || raise(e)
end
send(data)
Alias for: send_text
send_binary(data) click to toggle source

Send a WebSocket binary frame.

# File lib/em-websocket/connection.rb, line 182
def send_binary(data)
  if @handler
    @handler.send_frame(:binary, data)
  else
    raise WebSocketError, "Cannot send binary before onopen callback"
  end
end
send_flash_cross_domain_file() click to toggle source
# File lib/em-websocket/connection.rb, line 131
def send_flash_cross_domain_file
  file =  '<?xml version="1.0"?><cross-domain-policy><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>'
  debug [:cross_domain, file]
  send_data file

  # handle the cross-domain request transparently
  # no need to notify the user about this connection
  @onclose = nil
  close_connection_after_writing
end
send_text(data) click to toggle source

Send a WebSocket text frame.

A WebSocketError may be raised if the connection is in an opening or a closing state, or if the passed in data is not valid UTF-8

# File lib/em-websocket/connection.rb, line 152
def send_text(data)
  # If we're using Ruby 1.9, be pedantic about encodings
  if ENCODING_SUPPORTED
    # Also accept ascii only data in other encodings for convenience
    unless (data.encoding == UTF8 && data.valid_encoding?) || data.ascii_only?
      raise WebSocketError, "Data sent to WebSocket must be valid UTF-8 but was #{data.encoding} (valid: #{data.valid_encoding?})"
    end
    # This labels the encoding as binary so that it can be combined with
    # the BINARY framing
    data.force_encoding(BINARY)
  else
    # TODO: Check that data is valid UTF-8
  end

  if @handler
    @handler.send_text_frame(data)
  else
    raise WebSocketError, "Cannot send data before onopen callback"
  end

  # Revert data back to the original encoding (which we assume is UTF-8)
  # Doing this to avoid duping the string - there may be a better way
  data.force_encoding(UTF8) if ENCODING_SUPPORTED
  return nil
end
Also aliased as: send
state() click to toggle source
# File lib/em-websocket/connection.rb, line 235
def state
  @handler ? @handler.state : :handshake
end
supports_close_codes?() click to toggle source
# File lib/em-websocket/connection.rb, line 227
def supports_close_codes?
  if @handler
    @handler.supports_close_codes?
  else
    raise WebSocketError, "Cannot test before onopen callback"
  end
end
trigger_on_binary(msg) click to toggle source
# File lib/em-websocket/connection.rb, line 20
def trigger_on_binary(msg)
  @onbinary.call(msg) if defined? @onbinary
end
trigger_on_close(event = {}) click to toggle source
# File lib/em-websocket/connection.rb, line 26
def trigger_on_close(event = {})
  @onclose.call(event) if defined? @onclose
end
trigger_on_error(reason) click to toggle source
# File lib/em-websocket/connection.rb, line 35
def trigger_on_error(reason)
  return false unless defined? @onerror
  @onerror.call(reason)
  true
end
trigger_on_message(msg) click to toggle source
# File lib/em-websocket/connection.rb, line 17
def trigger_on_message(msg)
  @onmessage.call(msg) if defined? @onmessage
end
trigger_on_open(handshake) click to toggle source
# File lib/em-websocket/connection.rb, line 23
def trigger_on_open(handshake)
  @onopen.call(handshake) if defined? @onopen
end
trigger_on_ping(data) click to toggle source
# File lib/em-websocket/connection.rb, line 29
def trigger_on_ping(data)
  @onping.call(data) if defined? @onping
end
trigger_on_pong(data) click to toggle source
# File lib/em-websocket/connection.rb, line 32
def trigger_on_pong(data)
  @onpong.call(data) if defined? @onpong
end
unbind() click to toggle source
# File lib/em-websocket/connection.rb, line 91
def unbind
  debug [:unbind, :connection]

  @handler.unbind if @handler
rescue => e
  debug [:error, e]
  # These are application errors - raise unless onerror defined
  trigger_on_error(e) || raise(e)
end

Private Instance Methods

abort() click to toggle source

As definited in draft 06 7.2.2, some failures require that the server abort the websocket connection rather than close cleanly

# File lib/em-websocket/connection.rb, line 259
def abort
  close_connection
end
acceptable_close_code?(code) click to toggle source

Allow applications to close with 1000, 1003, 1008, 1011, 3xxx or 4xxx.

em-websocket uses a few other codes internally which should not be used by applications

Browsers generally allow connections to be closed with code 1000, 3xxx, and 4xxx. em-websocket allows closing with a few other codes which seem reasonable (for discussion see github.com/igrigorik/em-websocket/issues/98)

Usage from the rfc:

1000 indicates a normal closure

1003 indicates that an endpoint is terminating the connection because it has received a type of data it cannot accept

1008 indicates that an endpoint is terminating the connection because it has received a message that violates its policy

1011 indicates that a server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request

Status codes in the range 3000-3999 are reserved for use by libraries, frameworks, and applications

Status codes in the range 4000-4999 are reserved for private use and thus can't be registered

# File lib/em-websocket/connection.rb, line 303
def acceptable_close_code?(code)
  case code
  when 1000, 1003, 1008, 1011, (3000..4999)
    true
  else
    false
  end
end
close_websocket_private(code, body) click to toggle source
# File lib/em-websocket/connection.rb, line 263
def close_websocket_private(code, body)
  if @handler
    debug [:closing, code]
    @handler.close_websocket(code, body)
  else
    # The handshake hasn't completed - should be safe to terminate
    abort
  end
end