class WebSocket::Driver::Hybi

Constants

BYTE
DEFAULT_ERROR_CODE
ERRORS
ERROR_CODES
FIN
GUID
LENGTH
MAX_RESERVED_ERROR
MESSAGE_OPCODES
MIN_RESERVED_ERROR
OPCODE
OPCODES
OPCODE_CODES
OPENING_OPCODES
PACK_FORMATS
RSV1
RSV2
RSV3

Public Instance Methods

add_extension(extension) click to toggle source
# File lib/websocket/driver/hybi.rb, line 89
def add_extension(extension)
  @extensions.add(extension)
  true
end
binary(message) click to toggle source
# File lib/websocket/driver/hybi.rb, line 132
def binary(message)
  frame(message, :binary)
end
close(reason = nil, code = nil) click to toggle source
# File lib/websocket/driver/hybi.rb, line 145
def close(reason = nil, code = nil)
  reason ||= ''
  code   ||= ERRORS[:normal_closure]

  if @ready_state <= 0
    @ready_state = 3
    emit(:close, CloseEvent.new(code, reason))
    true
  elsif @ready_state == 1
    frame(reason, :close, code)
    @ready_state = 2
    true
  else
    false
  end
end
frame(buffer, type = nil, code = nil) click to toggle source
# File lib/websocket/driver/hybi.rb, line 162
def frame(buffer, type = nil, code = nil)
  return queue([buffer, type, code]) if @ready_state <= 0
  return false unless @ready_state == 1

  message = Message.new
  frame   = Frame.new
  is_text = String === buffer

  message.rsv1   = message.rsv2 = message.rsv3 = false
  message.opcode = OPCODES[type || (is_text ? :text : :binary)]

  payload = is_text ? buffer.bytes.to_a : buffer
  payload = [code].pack(PACK_FORMATS[2]).bytes.to_a + payload if code
  message.data = payload.pack('C*')

  if MESSAGE_OPCODES.include?(message.opcode)
    message = @extensions.process_outgoing_message(message)
  end

  frame.final       = true
  frame.rsv1        = message.rsv1
  frame.rsv2        = message.rsv2
  frame.rsv3        = message.rsv3
  frame.opcode      = message.opcode
  frame.masked      = !!@masking
  frame.masking_key = SecureRandom.random_bytes(4) if frame.masked
  frame.length      = message.data.bytesize
  frame.payload     = message.data

  send_frame(frame)
  true

rescue ::WebSocket::Extensions::ExtensionError => error
  fail(:extension_error, error.message)
end
parse(chunk) click to toggle source
# File lib/websocket/driver/hybi.rb, line 94
def parse(chunk)
  @reader.put(chunk)
  buffer = true
  while buffer
    case @stage
      when 0 then
        buffer = @reader.read(1)
        parse_opcode(buffer.getbyte(0)) if buffer

      when 1 then
        buffer = @reader.read(1)
        parse_length(buffer.getbyte(0)) if buffer

      when 2 then
        buffer = @reader.read(@frame.length_bytes)
        parse_extended_length(buffer) if buffer

      when 3 then
        buffer = @reader.read(4)
        if buffer
          @stage = 4
          @frame.masking_key = buffer
        end

      when 4 then
        buffer = @reader.read(@frame.length)

        if buffer
          @stage = 0
          emit_frame(buffer)
        end

      else
        buffer = nil
    end
  end
end
ping(message = '', &callback) click to toggle source
# File lib/websocket/driver/hybi.rb, line 136
def ping(message = '', &callback)
  @ping_callbacks[message] = callback if callback
  frame(message, :ping)
end
pong(message = '') click to toggle source
# File lib/websocket/driver/hybi.rb, line 141
def pong(message = '')
  frame(message, :pong)
end
version() click to toggle source
# File lib/websocket/driver/hybi.rb, line 85
def version
  "hybi-#{@socket.env['HTTP_SEC_WEBSOCKET_VERSION']}"
end

Public Class Methods

generate_accept(key) click to toggle source
# File lib/websocket/driver/hybi.rb, line 10
def self.generate_accept(key)
  Base64.strict_encode64(Digest::SHA1.digest(key + GUID))
end
new(socket, options = {}) click to toggle source
# File lib/websocket/driver/hybi.rb, line 56
def initialize(socket, options = {})
  super

  @extensions      = ::WebSocket::Extensions.new
  @stage           = 0
  @masking         = options[:masking]
  @protocols       = options[:protocols] || []
  @protocols       = @protocols.strip.split(/ *, */) if String === @protocols
  @require_masking = options[:require_masking]
  @ping_callbacks  = {}

  @frame = @message = nil

  return unless @socket.respond_to?(:env)

  sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
  protos  = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']

  @headers['Upgrade']              = 'websocket'
  @headers['Connection']           = 'Upgrade'
  @headers['Sec-WebSocket-Accept'] = Hybi.generate_accept(sec_key)

  if protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
    protos = protos.split(/ *, */) if String === protos
    @protocol = protos.find { |p| @protocols.include?(p) }
    @headers['Sec-WebSocket-Protocol'] = @protocol if @protocol
  end
end