Class: Rocket::WebSocket

Inherits:
Object
  • Object
show all
Defined in:
lib/rocket/websocket.rb

Defined Under Namespace

Classes: Error

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arg, params = {}) ⇒ WebSocket

Returns a new instance of WebSocket.

Raises:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
# File 'lib/rocket/websocket.rb', line 22

def initialize(arg, params = {})
  uri = arg.is_a?(String) ? URI.parse(arg) : arg

  if uri.scheme == "ws"
    default_port = 80
  elsif uri.scheme = "wss"
    default_port = 443
  else
    raise(WebSocket::Error, "unsupported scheme: #{uri.scheme}")
  end

  @path = (uri.path.empty? ? "/" : uri.path) + (uri.query ? "?" + uri.query : "")
  host = uri.host + (uri.port == default_port ? "" : ":#{uri.port}")
  origin = params[:origin] || "http://#{uri.host}"
  key1 = generate_key()
  key2 = generate_key()
  key3 = generate_key3()

  socket = TCPSocket.new(uri.host, uri.port || default_port)

  if uri.scheme == "ws"
    @socket = socket
  else
    @socket = ssl_handshake(socket)
  end

  write(
    "GET #{@path} HTTP/1.1\r\n" +
    "Upgrade: WebSocket\r\n" +
    "Connection: Upgrade\r\n" +
    "Host: #{host}\r\n" +
    "Origin: #{origin}\r\n" +
    "Sec-WebSocket-Key1: #{key1}\r\n" +
    "Sec-WebSocket-Key2: #{key2}\r\n" +
    "\r\n" +
    "#{key3}")
  flush()

  line = gets().chomp()
  raise(WebSocket::Error, "bad response: #{line}") if !(line =~ /\AHTTP\/1.1 101 /n)
  read_header()
  if @header["Sec-WebSocket-Origin"] != origin
    raise(WebSocket::Error,
      "origin doesn't match: '#{@header["WebSocket-Origin"]}' != '#{origin}'")
  end
  reply_digest = read(16)
  expected_digest = security_digest(key1, key2, key3)
  if reply_digest != expected_digest
    raise(WebSocket::Error,
      "security digest doesn't match: %p != %p" % [reply_digest, expected_digest])
  end
  @handshaked = true
  @closing_started = false
end

Class Attribute Details

.debugObject

Returns the value of attribute debug.



16
17
18
# File 'lib/rocket/websocket.rb', line 16

def debug
  @debug
end

Instance Attribute Details

#headerObject (readonly)

Returns the value of attribute header.



19
20
21
# File 'lib/rocket/websocket.rb', line 19

def header
  @header
end

#pathObject (readonly)

Returns the value of attribute path.



20
21
22
# File 'lib/rocket/websocket.rb', line 20

def path
  @path
end

Instance Method Details

#closeObject

Does closing handshake.



119
120
121
122
123
124
# File 'lib/rocket/websocket.rb', line 119

def close()
  return if @closing_started
  write("\xff\x00")
  @socket.close() if !@server
  @closing_started = true
end

#close_socketObject



126
127
128
# File 'lib/rocket/websocket.rb', line 126

def close_socket()
  @socket.close()
end

#hostObject



110
111
112
# File 'lib/rocket/websocket.rb', line 110

def host
  return @header["Host"]
end

#originObject



114
115
116
# File 'lib/rocket/websocket.rb', line 114

def origin
  return @header["Origin"]
end

#receiveObject



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/rocket/websocket.rb', line 86

def receive()
  if !@handshaked
    raise(WebSocket::Error, "call WebSocket\#handshake first")
  end
  packet = gets("\xff")
  return nil if !packet
  if packet =~ /\A\x00(.*)\xff\z/nm
    return force_encoding($1, "UTF-8")
  elsif packet == "\xff" && read(1) == "\x00" # closing
    if @server
      @socket.close()
    else
      close()
    end
    return nil
  else
    raise(WebSocket::Error, "input must be either '\\x00...\\xff' or '\\xff\\x00'")
  end
end

#send(data) ⇒ Object



77
78
79
80
81
82
83
84
# File 'lib/rocket/websocket.rb', line 77

def send(data)
  if !@handshaked
    raise(WebSocket::Error, "call WebSocket\#handshake first")
  end
  data = force_encoding(data.dup(), "ASCII-8BIT")
  write("\x00#{data}\xff")
  flush()
end

#tcp_socketObject



106
107
108
# File 'lib/rocket/websocket.rb', line 106

def tcp_socket
  return @socket
end