websocket 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +5 -0
- data/README.md +117 -0
- data/Rakefile +23 -0
- data/autobahn-client.json +11 -0
- data/autobahn-server.json +10 -0
- data/examples/base.rb +162 -0
- data/examples/client.rb +70 -0
- data/examples/server.rb +56 -0
- data/examples/tests/autobahn_client.rb +52 -0
- data/examples/tests/echo_client.rb +42 -0
- data/examples/tests/echo_server.rb +45 -0
- data/lib/websocket.rb +16 -0
- data/lib/websocket/frame.rb +11 -0
- data/lib/websocket/frame/base.rb +45 -0
- data/lib/websocket/frame/data.rb +52 -0
- data/lib/websocket/frame/handler.rb +15 -0
- data/lib/websocket/frame/handler/base.rb +41 -0
- data/lib/websocket/frame/handler/handler03.rb +162 -0
- data/lib/websocket/frame/handler/handler04.rb +19 -0
- data/lib/websocket/frame/handler/handler05.rb +17 -0
- data/lib/websocket/frame/handler/handler07.rb +34 -0
- data/lib/websocket/frame/handler/handler75.rb +79 -0
- data/lib/websocket/frame/incoming.rb +43 -0
- data/lib/websocket/frame/incoming/client.rb +9 -0
- data/lib/websocket/frame/incoming/server.rb +9 -0
- data/lib/websocket/frame/outgoing.rb +28 -0
- data/lib/websocket/frame/outgoing/client.rb +9 -0
- data/lib/websocket/frame/outgoing/server.rb +9 -0
- data/lib/websocket/handshake.rb +10 -0
- data/lib/websocket/handshake/base.rb +67 -0
- data/lib/websocket/handshake/client.rb +80 -0
- data/lib/websocket/handshake/handler.rb +20 -0
- data/lib/websocket/handshake/handler/base.rb +25 -0
- data/lib/websocket/handshake/handler/client.rb +19 -0
- data/lib/websocket/handshake/handler/client01.rb +19 -0
- data/lib/websocket/handshake/handler/client04.rb +47 -0
- data/lib/websocket/handshake/handler/client75.rb +25 -0
- data/lib/websocket/handshake/handler/client76.rb +85 -0
- data/lib/websocket/handshake/handler/server.rb +30 -0
- data/lib/websocket/handshake/handler/server04.rb +38 -0
- data/lib/websocket/handshake/handler/server75.rb +26 -0
- data/lib/websocket/handshake/handler/server76.rb +71 -0
- data/lib/websocket/handshake/server.rb +56 -0
- data/lib/websocket/version.rb +3 -0
- data/spec/frame/incoming_03_spec.rb +117 -0
- data/spec/frame/incoming_04_spec.rb +117 -0
- data/spec/frame/incoming_05_spec.rb +133 -0
- data/spec/frame/incoming_07_spec.rb +133 -0
- data/spec/frame/incoming_75_spec.rb +59 -0
- data/spec/frame/incoming_common_spec.rb +22 -0
- data/spec/frame/outgoing_03_spec.rb +77 -0
- data/spec/frame/outgoing_04_spec.rb +77 -0
- data/spec/frame/outgoing_05_spec.rb +77 -0
- data/spec/frame/outgoing_07_spec.rb +77 -0
- data/spec/frame/outgoing_75_spec.rb +41 -0
- data/spec/frame/outgoing_common_spec.rb +15 -0
- data/spec/handshake/client_04_spec.rb +20 -0
- data/spec/handshake/client_75_spec.rb +11 -0
- data/spec/handshake/client_76_spec.rb +20 -0
- data/spec/handshake/server_04_spec.rb +18 -0
- data/spec/handshake/server_75_spec.rb +11 -0
- data/spec/handshake/server_76_spec.rb +46 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/all_client_drafts.rb +77 -0
- data/spec/support/all_server_drafts.rb +86 -0
- data/spec/support/handshake_requests.rb +72 -0
- data/spec/support/incoming_frames.rb +30 -0
- data/spec/support/outgoing_frames.rb +14 -0
- data/websocket.gemspec +21 -0
- metadata +163 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../client"
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
EM.epoll
|
5
|
+
EM.run do
|
6
|
+
|
7
|
+
host = 'ws://localhost:9001'
|
8
|
+
agent = "WebSocket-Ruby (Ruby #{RUBY_VERSION})"
|
9
|
+
cases = 0
|
10
|
+
skip = []
|
11
|
+
|
12
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/getCaseCount")
|
13
|
+
|
14
|
+
ws.onmessage do |msg, type|
|
15
|
+
puts "$ Total cases to run: #{msg}"
|
16
|
+
cases = msg.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
ws.onclose do
|
20
|
+
|
21
|
+
run_case = lambda do |n|
|
22
|
+
|
23
|
+
if n > cases
|
24
|
+
puts "$ Requesting report"
|
25
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/updateReports?agent=#{CGI.escape agent}")
|
26
|
+
ws.onclose do
|
27
|
+
EM.stop
|
28
|
+
end
|
29
|
+
|
30
|
+
elsif skip.include?(n)
|
31
|
+
EM.next_tick { run_case.call(n+1) }
|
32
|
+
|
33
|
+
else
|
34
|
+
puts "$ Test number #{n}"
|
35
|
+
ws = WebSocket::EventMachine::Client.connect(:uri => "#{host}/runCase?case=#{n}&agent=#{CGI.escape agent}")
|
36
|
+
|
37
|
+
ws.onmessage do |msg, type|
|
38
|
+
puts "Received #{msg}(#{type})"
|
39
|
+
ws.send(msg, :type => type)
|
40
|
+
end
|
41
|
+
|
42
|
+
ws.onclose do |msg|
|
43
|
+
puts("Closing: #{msg}") if msg
|
44
|
+
run_case.call(n + 1)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
run_case.call(1)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../client"
|
2
|
+
|
3
|
+
EM.epoll
|
4
|
+
EM.run do
|
5
|
+
|
6
|
+
trap("TERM") { stop }
|
7
|
+
trap("INT") { stop }
|
8
|
+
|
9
|
+
ws = WebSocket::EventMachine::Client.connect(:host => "localhost", :port => 9001);
|
10
|
+
|
11
|
+
ws.onopen do
|
12
|
+
puts "Connected"
|
13
|
+
ws.send "Hello"
|
14
|
+
end
|
15
|
+
|
16
|
+
ws.onmessage do |msg, type|
|
17
|
+
puts "Received message: #{msg}"
|
18
|
+
ws.send msg, :type => type
|
19
|
+
end
|
20
|
+
|
21
|
+
ws.onclose do
|
22
|
+
puts "Disconnected"
|
23
|
+
end
|
24
|
+
|
25
|
+
ws.onerror do |e|
|
26
|
+
puts "Error: #{e}"
|
27
|
+
end
|
28
|
+
|
29
|
+
ws.onping do |msg|
|
30
|
+
puts "Receied ping: #{msg}"
|
31
|
+
end
|
32
|
+
|
33
|
+
ws.onpong do |msg|
|
34
|
+
puts "Received pong: #{msg}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
puts "Terminating connection"
|
39
|
+
EventMachine.stop
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../server"
|
2
|
+
|
3
|
+
EM.epoll
|
4
|
+
EM.run do
|
5
|
+
|
6
|
+
trap("TERM") { stop }
|
7
|
+
trap("INT") { stop }
|
8
|
+
|
9
|
+
WebSocket::EventMachine::Server.start(:host => "0.0.0.0", :port => 9001) do |ws|
|
10
|
+
|
11
|
+
ws.onopen do
|
12
|
+
puts "Client connected"
|
13
|
+
end
|
14
|
+
|
15
|
+
ws.onmessage do |msg, type|
|
16
|
+
puts "Received message: #{msg}"
|
17
|
+
ws.send msg, :type => type
|
18
|
+
end
|
19
|
+
|
20
|
+
ws.onclose do
|
21
|
+
puts "Client disconnected"
|
22
|
+
end
|
23
|
+
|
24
|
+
ws.onerror do |e|
|
25
|
+
puts "Error: #{e}"
|
26
|
+
end
|
27
|
+
|
28
|
+
ws.onping do |msg|
|
29
|
+
puts "Receied ping: #{msg}"
|
30
|
+
end
|
31
|
+
|
32
|
+
ws.onpong do |msg|
|
33
|
+
puts "Received pong: #{msg}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "Server started at port 9001"
|
39
|
+
|
40
|
+
def stop
|
41
|
+
puts "Terminating WebSocket Server"
|
42
|
+
EventMachine.stop
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/websocket.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# WebSocket protocol implementation in Ruby
|
2
|
+
# This module does not provide a WebSocket server or client, but is made for using
|
3
|
+
# in http servers or clients to provide WebSocket support.
|
4
|
+
# @author Bernard "Imanel" Potocki
|
5
|
+
# @see http://github.com/imanel/websocket-ruby main repository
|
6
|
+
module WebSocket
|
7
|
+
class Error < RuntimeError; end
|
8
|
+
|
9
|
+
DEFAULT_VERSION = 13
|
10
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
11
|
+
|
12
|
+
autoload :Frame, "#{ROOT}/websocket/frame"
|
13
|
+
autoload :Handler, "#{ROOT}/websocket/handler"
|
14
|
+
autoload :Handshake, "#{ROOT}/websocket/handshake"
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module WebSocket
|
2
|
+
module Frame
|
3
|
+
|
4
|
+
autoload :Base, "#{::WebSocket::ROOT}/websocket/frame/base"
|
5
|
+
autoload :Data, "#{::WebSocket::ROOT}/websocket/frame/data"
|
6
|
+
autoload :Handler, "#{::WebSocket::ROOT}/websocket/frame/handler"
|
7
|
+
autoload :Incoming, "#{::WebSocket::ROOT}/websocket/frame/incoming"
|
8
|
+
autoload :Outgoing, "#{::WebSocket::ROOT}/websocket/frame/outgoing"
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module WebSocket
|
2
|
+
module Frame
|
3
|
+
class Base
|
4
|
+
|
5
|
+
attr_reader :data, :type, :version, :error
|
6
|
+
|
7
|
+
# Initialize frame
|
8
|
+
# @param args [Hash] Arguments for frame
|
9
|
+
# @option args [Integer] :version Version of draft. Currently supported version are 75, 76 and 00-13.
|
10
|
+
# @option args [String] :type Type of frame - available types are "text", "binary", "ping", "pong" and "close"(support depends on draft version)
|
11
|
+
# @option args [String] :data default data for frame
|
12
|
+
def initialize(args = {})
|
13
|
+
@type = args[:type]
|
14
|
+
@data = Data.new(args[:data].to_s)
|
15
|
+
@version = args[:version] || DEFAULT_VERSION
|
16
|
+
set_handler
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check if some errors occured
|
20
|
+
# @return [Boolean] True if error is set
|
21
|
+
def error?
|
22
|
+
!!@error
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def set_handler
|
28
|
+
case @version
|
29
|
+
when 75..76 then extend Handler::Handler75
|
30
|
+
when 0..2 then extend Handler::Handler75
|
31
|
+
when 3 then extend Handler::Handler03
|
32
|
+
when 4 then extend Handler::Handler04
|
33
|
+
when 5..6 then extend Handler::Handler05
|
34
|
+
when 7..13 then extend Handler::Handler07
|
35
|
+
else set_error(:unknown_protocol_version) and return
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_error(message)
|
40
|
+
@error = message
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module WebSocket
|
2
|
+
module Frame
|
3
|
+
class Data < String
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
super *args.each { |arg| arg.force_encoding('ASCII-8BIT') if respond_to?(:force_encoding) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(*args)
|
10
|
+
super *args.each { |arg| arg.force_encoding('ASCII-8BIT') if respond_to?(:force_encoding) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_mask
|
14
|
+
raise "Too short" if bytesize < 4 # TODO - change
|
15
|
+
@masking_key = Data.new(self[0..3])
|
16
|
+
end
|
17
|
+
|
18
|
+
def unset_mask
|
19
|
+
@masking_key = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def getbytes(start_index, count)
|
23
|
+
data = ''
|
24
|
+
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
|
25
|
+
count.times do |i|
|
26
|
+
data << getbyte(start_index + i)
|
27
|
+
end
|
28
|
+
data
|
29
|
+
end
|
30
|
+
|
31
|
+
# Required for support of Ruby 1.8
|
32
|
+
unless new.respond_to?(:getbyte)
|
33
|
+
def getbyte(index)
|
34
|
+
self[index]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def getbyte_with_masking(index)
|
39
|
+
if @masking_key
|
40
|
+
masked_char = getbyte_without_masking(index)
|
41
|
+
masked_char ? masked_char ^ @masking_key.getbyte(index % 4) : nil
|
42
|
+
else
|
43
|
+
getbyte_without_masking(index)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :getbyte_without_masking, :getbyte
|
48
|
+
alias_method :getbyte, :getbyte_with_masking
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module WebSocket
|
2
|
+
module Frame
|
3
|
+
module Handler
|
4
|
+
|
5
|
+
autoload :Base, "#{::WebSocket::ROOT}/websocket/frame/handler/base"
|
6
|
+
|
7
|
+
autoload :Handler03, "#{::WebSocket::ROOT}/websocket/frame/handler/handler03"
|
8
|
+
autoload :Handler04, "#{::WebSocket::ROOT}/websocket/frame/handler/handler04"
|
9
|
+
autoload :Handler05, "#{::WebSocket::ROOT}/websocket/frame/handler/handler05"
|
10
|
+
autoload :Handler07, "#{::WebSocket::ROOT}/websocket/frame/handler/handler07"
|
11
|
+
autoload :Handler75, "#{::WebSocket::ROOT}/websocket/frame/handler/handler75"
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module WebSocket
|
2
|
+
module Frame
|
3
|
+
module Handler
|
4
|
+
module Base
|
5
|
+
|
6
|
+
MAX_FRAME_SIZE = 20 * 1024 * 1024 # 20MB
|
7
|
+
|
8
|
+
# Is selected type supported for selected handler?
|
9
|
+
def support_type?
|
10
|
+
supported_frames.include?(@type)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Implement in submodules
|
14
|
+
def supported_frames
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Convert data to raw frame ready to send to client
|
21
|
+
def encode_frame
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
# Convert raw data to decoded frame
|
26
|
+
def decode_frame
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
|
30
|
+
def control_frame?(frame_type)
|
31
|
+
![:text, :binary, :continuation].include?(frame_type)
|
32
|
+
end
|
33
|
+
|
34
|
+
def data_frame?(frame_type)
|
35
|
+
[:text, :binary].include?(frame_type)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
module WebSocket
|
4
|
+
module Frame
|
5
|
+
module Handler
|
6
|
+
module Handler03
|
7
|
+
|
8
|
+
include Base
|
9
|
+
|
10
|
+
def supported_frames
|
11
|
+
[:text, :binary, :close, :ping, :pong]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def encode_frame
|
17
|
+
frame = ''
|
18
|
+
|
19
|
+
opcode = type_to_opcode(@type)
|
20
|
+
byte1 = opcode | (fin ? 0b10000000 : 0b00000000) # since more, rsv1-3 are 0 and 0x80 for Draft 4
|
21
|
+
frame << byte1
|
22
|
+
|
23
|
+
length = @data.size
|
24
|
+
if length <= 125
|
25
|
+
byte2 = length # since rsv4 is 0
|
26
|
+
frame << byte2
|
27
|
+
elsif length < 65536 # write 2 byte length
|
28
|
+
frame << 126
|
29
|
+
frame << [length].pack('n')
|
30
|
+
else # write 8 byte length
|
31
|
+
frame << 127
|
32
|
+
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
33
|
+
end
|
34
|
+
|
35
|
+
frame << @data
|
36
|
+
frame
|
37
|
+
rescue WebSocket::Error => e
|
38
|
+
set_error(e.message.to_sym) and return
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_frame
|
42
|
+
while @data.size > 1
|
43
|
+
pointer = 0
|
44
|
+
|
45
|
+
more = ((@data.getbyte(pointer) & 0b10000000) == 0b10000000) ^ fin
|
46
|
+
|
47
|
+
raise(WebSocket::Error, :reserved_bit_used) if @data.getbyte(pointer) & 0b01110000 != 0b00000000
|
48
|
+
|
49
|
+
opcode = @data.getbyte(pointer) & 0b00001111
|
50
|
+
frame_type = opcode_to_type(opcode)
|
51
|
+
pointer += 1
|
52
|
+
|
53
|
+
raise(WebSocket::Error, :fragmented_control_frame) if more && control_frame?(frame_type)
|
54
|
+
raise(WebSocket::Error, :data_frame_instead_continuation) if data_frame?(frame_type) && !@application_data_buffer.nil?
|
55
|
+
|
56
|
+
mask = masking? && (@data.getbyte(pointer) & 0b10000000) == 0b10000000
|
57
|
+
length = @data.getbyte(pointer) & 0b01111111
|
58
|
+
|
59
|
+
raise(WebSocket::Error, :control_frame_payload_too_long) if length > 125 && control_frame?(frame_type)
|
60
|
+
|
61
|
+
pointer += 1
|
62
|
+
|
63
|
+
payload_length = case length
|
64
|
+
when 127 # Length defined by 8 bytes
|
65
|
+
# Check buffer size
|
66
|
+
return if @data.getbyte(pointer+8-1) == nil # Buffer incomplete
|
67
|
+
|
68
|
+
# Only using the last 4 bytes for now, till I work out how to
|
69
|
+
# unpack 8 bytes. I'm sure 4GB frames will do for now :)
|
70
|
+
l = @data.getbytes(pointer+4, 4).unpack('N').first
|
71
|
+
pointer += 8
|
72
|
+
l
|
73
|
+
when 126 # Length defined by 2 bytes
|
74
|
+
# Check buffer size
|
75
|
+
return if @data.getbyte(pointer+2-1) == nil # Buffer incomplete
|
76
|
+
|
77
|
+
l = @data.getbytes(pointer, 2).unpack('n').first
|
78
|
+
pointer += 2
|
79
|
+
l
|
80
|
+
else
|
81
|
+
length
|
82
|
+
end
|
83
|
+
|
84
|
+
# Compute the expected frame length
|
85
|
+
frame_length = pointer + payload_length
|
86
|
+
frame_length += 4 if mask
|
87
|
+
|
88
|
+
raise(WebSocket::Error, :frame_too_long) if frame_length > MAX_FRAME_SIZE
|
89
|
+
|
90
|
+
# Check buffer size
|
91
|
+
return if @data.getbyte(frame_length-1) == nil # Buffer incomplete
|
92
|
+
|
93
|
+
# Remove frame header
|
94
|
+
@data.slice!(0...pointer)
|
95
|
+
pointer = 0
|
96
|
+
|
97
|
+
# Read application data (unmasked if required)
|
98
|
+
@data.set_mask if mask
|
99
|
+
pointer += 4 if mask
|
100
|
+
application_data = @data.getbytes(pointer, payload_length)
|
101
|
+
application_data.force_encoding('UTF-8') if application_data.respond_to?(:force_encoding)
|
102
|
+
pointer += payload_length
|
103
|
+
@data.unset_mask if mask
|
104
|
+
|
105
|
+
# Throw away data up to pointer
|
106
|
+
@data.slice!(0...pointer)
|
107
|
+
|
108
|
+
raise(WebSocket::Error, :unexpected_continuation_frame) if frame_type == :continuation && !@frame_type
|
109
|
+
|
110
|
+
if more
|
111
|
+
@application_data_buffer ||= ''
|
112
|
+
@application_data_buffer << application_data
|
113
|
+
@frame_type ||= frame_type
|
114
|
+
else
|
115
|
+
# Message is complete
|
116
|
+
if frame_type == :continuation
|
117
|
+
@application_data_buffer << application_data
|
118
|
+
# Test valid UTF-8 encoding
|
119
|
+
raise(WebSocket::Error, :invalid_payload_encoding) if @frame_type == :text && @application_data_buffer.respond_to?(:valid_encoding?) && !@application_data_buffer.valid_encoding?
|
120
|
+
message = self.class.new(:version => version, :type => @frame_type, :data => @application_data_buffer, :decoded => true)
|
121
|
+
@application_data_buffer = nil
|
122
|
+
@frame_type = nil
|
123
|
+
return message
|
124
|
+
else
|
125
|
+
raise(WebSocket::Error, :invalid_payload_encoding) if frame_type == :text && application_data.respond_to?(:valid_encoding?) && !application_data.valid_encoding?
|
126
|
+
return self.class.new(:version => version, :type => frame_type, :data => application_data, :decoded => true)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
return nil
|
131
|
+
rescue WebSocket::Error => e
|
132
|
+
set_error(e.message.to_sym) and return
|
133
|
+
end
|
134
|
+
|
135
|
+
# This allows flipping the more bit to fin for draft 04
|
136
|
+
def fin; false; end
|
137
|
+
|
138
|
+
def masking?; false; end
|
139
|
+
|
140
|
+
FRAME_TYPES = {
|
141
|
+
:continuation => 0,
|
142
|
+
:close => 1,
|
143
|
+
:ping => 2,
|
144
|
+
:pong => 3,
|
145
|
+
:text => 4,
|
146
|
+
:binary => 5
|
147
|
+
}
|
148
|
+
|
149
|
+
FRAME_TYPES_INVERSE = FRAME_TYPES.invert
|
150
|
+
|
151
|
+
def type_to_opcode(frame_type)
|
152
|
+
FRAME_TYPES[frame_type] || raise(WebSocket::Error, :unknown_frame_type)
|
153
|
+
end
|
154
|
+
|
155
|
+
def opcode_to_type(opcode)
|
156
|
+
FRAME_TYPES_INVERSE[opcode] || raise(WebSocket::Error, :unknown_opcode)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|