Class: FTW::WebSocket

Inherits:
Object
  • Object
show all
Includes:
Cabin::Inspectable, CRLF
Defined in:
lib/ftw/namespace.rb,
lib/ftw/websocket.rb

Overview

WebSockets, RFC6455.

TODO(sissel): Find a comfortable way to make this websocket stuff both use HTTP::Connection for the HTTP handshake and also be usable from HTTP::Client TODO(sissel): Also consider SPDY and the kittens.

Defined Under Namespace

Modules: Constants Classes: Parser, Rack, Writer

Constant Summary collapse

TEXTFRAME =

The frame identifier for a ‘text’ frame

0x0001
WEBSOCKET_ACCEPT_UUID =

Search RFC6455 for this string and you will find its definitions. It is used in servers accepting websocket upgrades.

"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

Constants included from CRLF

CRLF::CRLF

Instance Method Summary collapse

Constructor Details

#initialize(request) ⇒ WebSocket

Creates a new websocket and fills in the given http request with any necessary settings.



36
37
38
39
40
41
42
# File 'lib/ftw/websocket.rb', line 36

def initialize(request)
  @key_nonce = generate_key_nonce
  @request = request
  prepare(@request)
  @parser = FTW::WebSocket::Parser.new
  @messages = []
end

Instance Method Details

#connection=(connection) ⇒ Object

Set the connection for this websocket. This is usually invoked by FTW::Agent after the websocket upgrade and handshake have been successful.

You probably don’t call this yourself.



48
49
50
# File 'lib/ftw/websocket.rb', line 48

def connection=(connection)
  @connection = connection
end

#each(&block) ⇒ Object

Iterate over each WebSocket message. This method will run forever unless you break from it.

The text payload of each message will be yielded to the block.



121
122
123
124
125
# File 'lib/ftw/websocket.rb', line 121

def each(&block)
  while true
    block.call(receive)
  end
end

#handshake_ok?(response) ⇒ Boolean

Is this Response acceptable for our WebSocket Upgrade request?

Returns:

  • (Boolean)


102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ftw/websocket.rb', line 102

def handshake_ok?(response)
  # See RFC6455 section 4.2.2
  return false unless response.status == 101 # "Switching Protocols"
  return false unless response.headers.get("upgrade").downcase == "websocket"
  return false unless response.headers.get("connection").downcase == "upgrade"

  # Now verify Sec-WebSocket-Accept. It should be the SHA-1 of the
  # Sec-WebSocket-Key (in base64) + WEBSOCKET_ACCEPT_UUID
  expected = @key_nonce + WEBSOCKET_ACCEPT_UUID
  expected_hash = Digest::SHA1.base64digest(expected)
  return false unless response.headers.get("Sec-WebSocket-Accept") == expected_hash

  return true
end

#publish(message) ⇒ Object

Publish a message text.

This will send a websocket text frame over the connection.



145
146
147
148
# File 'lib/ftw/websocket.rb', line 145

def publish(message)
  writer = FTW::WebSocket::Writer.singleton
  writer.write_text(@connection, message)
end

#receiveObject

Receive a single payload



128
129
130
131
# File 'lib/ftw/websocket.rb', line 128

def receive
  @messages += network_consume if @messages.empty?
  @messages.shift
end