Class: EventMachine::WebSocket::Connection
- Inherits:
-
Connection
- Object
- Connection
- EventMachine::WebSocket::Connection
- Defined in:
- lib/em-websocket/connection.rb
Constant Summary collapse
- PATH =
/^GET (\/[^\s]*) HTTP\/1\.1$/
- HEADER =
/^([^:]+):\s*([^$]+)/
Instance Method Summary collapse
- #dispatch ⇒ Object
-
#initialize(options) ⇒ Connection
constructor
A new instance of Connection.
- #new_request ⇒ Object
- #onclose(&blk) ⇒ Object
- #onmessage(&blk) ⇒ Object
-
#onopen(&blk) ⇒ Object
define WebSocket callbacks.
- #process_message ⇒ Object
- #receive_data(data) ⇒ Object
-
#send(data) ⇒ Object
should only be invoked after handshake, otherwise it will inject data into the header exchange.
- #send_upgrade ⇒ Object
- #unbind ⇒ Object
- #websocket_connection? ⇒ Boolean
Constructor Details
#initialize(options) ⇒ Connection
Returns a new instance of Connection.
15 16 17 18 19 20 21 22 23 |
# File 'lib/em-websocket/connection.rb', line 15 def initialize() @options = @debug = [:debug] || false @state = :handshake @request = {} @data = '' debug [:initialize] end |
Instance Method Details
#dispatch ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/em-websocket/connection.rb', line 37 def dispatch while case @state when :handshake new_request when :upgrade send_upgrade when :connected else raise RuntimeError, "invalid state: #{@state}" end end end |
#new_request ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/em-websocket/connection.rb', line 50 def new_request if @data.match(/\r\n\r\n$/) debug [:inbound_headers, @data] lines = @data.split("\r\n") # extract request path @request['Path'] = lines.shift.match(PATH)[1].strip # extract remaining headers lines.each do |line| h = HEADER.match(line) @request[h[1].strip] = h[2].strip end # transform headers @request['Host'] = Addressable::URI.parse("ws://"+@request['Host']) if not websocket_connection? send_data "HTTP/1.1 400 Bad request\r\n\r\n" close_connection_after_writing return false else @data = '' @state = :upgrade return true end end false end |
#onclose(&blk) ⇒ Object
12 |
# File 'lib/em-websocket/connection.rb', line 12 def onclose(&blk); @onclode = blk; end |
#onmessage(&blk) ⇒ Object
13 |
# File 'lib/em-websocket/connection.rb', line 13 def (&blk); @onmessage = blk; end |
#onopen(&blk) ⇒ Object
define WebSocket callbacks
11 |
# File 'lib/em-websocket/connection.rb', line 11 def onopen(&blk); @onopen = blk; end |
#process_message ⇒ Object
109 110 111 112 113 114 115 |
# File 'lib/em-websocket/connection.rb', line 109 def debug [:message, @data] @onmessage.call(@data) if @onmessage @data = '' false end |
#receive_data(data) ⇒ Object
25 26 27 28 29 30 |
# File 'lib/em-websocket/connection.rb', line 25 def receive_data(data) debug [:receive_data, data] @data << data dispatch end |
#send(data) ⇒ Object
should only be invoked after handshake, otherwise it will inject data into the header exchange
frames need to start with 0x00-0x7f byte and end with an 0xFF byte. Per spec, we can also set the first byte to a value betweent 0x80 and 0xFF, followed by a leading length indicator
124 125 126 127 |
# File 'lib/em-websocket/connection.rb', line 124 def send(data) debug [:send, data] send_data("\x00#{data}\xff") end |
#send_upgrade ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/em-websocket/connection.rb', line 86 def send_upgrade location = "ws://#{@request['Host'].host}" location << ":#{@request['Host'].port}" if @request['Host'].port location << @request['Path'] upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" upgrade << "Upgrade: WebSocket\r\n" upgrade << "Connection: Upgrade\r\n" upgrade << "WebSocket-Origin: #{@request['Origin']}\r\n" upgrade << "WebSocket-Location: #{location}\r\n\r\n" # upgrade connection and notify client callback # about completed handshake debug [:upgrade_headers, upgrade] send_data upgrade @state = :connected @onopen.call if @onopen # stop dispatch, wait for messages false end |
#unbind ⇒ Object
32 33 34 35 |
# File 'lib/em-websocket/connection.rb', line 32 def unbind debug [:unbind, :connection] @onclose.call if @onclose end |
#websocket_connection? ⇒ Boolean
82 83 84 |
# File 'lib/em-websocket/connection.rb', line 82 def websocket_connection? @request['Connection'] == 'Upgrade' and @request['Upgrade'] == 'WebSocket' end |