Class: Protocol::WebSocket::Frame
- Inherits:
-
Object
- Object
- Protocol::WebSocket::Frame
show all
- Includes:
- Comparable
- Defined in:
- lib/protocol/websocket/frame.rb
Constant Summary
collapse
- OPCODE =
0
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
Constructor Details
#initialize(finished = true, opcode = self.class::OPCODE, mask = false, payload = nil) ⇒ Frame
31
32
33
34
35
36
37
|
# File 'lib/protocol/websocket/frame.rb', line 31
def initialize(finished = true, opcode = self.class::OPCODE, mask = false, payload = nil)
@finished = finished
@opcode = opcode
@mask = mask
@length = payload&.bytesize
@payload = payload
end
|
Instance Attribute Details
#finished ⇒ Object
The generic frame header uses the following binary representation:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-------------------------——————————-+ |F|R|R|R| opcode|M| Payload len | Extended payload length | |I|S|S|S| (4) |A| (7) | (16/64) | |N|V|V|V| |S| | (if payload len==126/127) | | |1|2|3| |K| | | ------------------------- - - - - - - - - - - - - - - - + | Extended payload length continued, if payload len == 127 | + - - - - - - - - - - - - - - - ------------------------------- | |Masking-key, if MASK set to 1 | -------------------------------——————————-+ | Masking-key (continued) | Payload Data | ——————————– - - - - - - - - - - - - - - - : Payload Data continued … : + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + | Payload Data continued … | ---------------------------------------------------------------
80
81
82
|
# File 'lib/protocol/websocket/frame.rb', line 80
def finished
@finished
end
|
#length ⇒ Object
Returns the value of attribute length.
83
84
85
|
# File 'lib/protocol/websocket/frame.rb', line 83
def length
@length
end
|
#mask ⇒ Object
Returns the value of attribute mask.
82
83
84
|
# File 'lib/protocol/websocket/frame.rb', line 82
def mask
@mask
end
|
#opcode ⇒ Object
Returns the value of attribute opcode.
81
82
83
|
# File 'lib/protocol/websocket/frame.rb', line 81
def opcode
@opcode
end
|
#payload ⇒ Object
Returns the value of attribute payload.
84
85
86
|
# File 'lib/protocol/websocket/frame.rb', line 84
def payload
@payload
end
|
Class Method Details
127
128
129
130
131
132
133
134
135
|
# File 'lib/protocol/websocket/frame.rb', line 127
def self.(buffer)
byte = buffer.unpack("C").first
finished = (byte & 0b1000_0000 != 0)
opcode = byte & 0b0000_1111
return finished, opcode
end
|
.read(finished, opcode, stream, maximum_frame_size) ⇒ Object
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
# File 'lib/protocol/websocket/frame.rb', line 137
def self.read(finished, opcode, stream, maximum_frame_size)
buffer = stream.read(1) or raise EOFError
byte = buffer.unpack("C").first
mask = (byte & 0b1000_0000 != 0)
length = byte & 0b0111_1111
if length == 126
buffer = stream.read(2) or raise EOFError
length = buffer.unpack('n').first
elsif length == 127
buffer = stream.read(4) or raise EOFError
length = buffer.unpack('Q>').first
end
if length > maximum_frame_size
raise ProtocolError, "Invalid payload length: #{@length} > #{maximum_frame_size}!"
end
if mask
mask = stream.read(4) or raise EOFError
end
payload = stream.read(length) or raise EOFError
if payload.bytesize != length
raise EOFError, "Incorrect payload length: #{@length} != #{@payload.bytesize}!"
end
return self.new(finished, opcode, mask, payload)
end
|
Instance Method Details
#<=>(other) ⇒ Object
39
40
41
|
# File 'lib/protocol/websocket/frame.rb', line 39
def <=> other
to_ary <=> other.to_ary
end
|
#apply(connection) ⇒ Object
123
124
125
|
# File 'lib/protocol/websocket/frame.rb', line 123
def apply(connection)
connection.receive_frame(self)
end
|
#continued? ⇒ Boolean
55
56
57
|
# File 'lib/protocol/websocket/frame.rb', line 55
def continued?
@finished == false
end
|
#control? ⇒ Boolean
47
48
49
|
# File 'lib/protocol/websocket/frame.rb', line 47
def control?
@opcode & 0x8
end
|
#finished? ⇒ Boolean
51
52
53
|
# File 'lib/protocol/websocket/frame.rb', line 51
def finished?
@finished == true
end
|
#pack(data, mask = @mask) ⇒ Object
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# File 'lib/protocol/websocket/frame.rb', line 90
def pack(data, mask = @mask)
length = data.bytesize
if length.bit_length > 63
raise ProtocolError, "Frame length #{@length} bigger than allowed maximum!"
end
if @mask = mask
@payload = String.new.b
for i in 0...data.bytesize do
@payload << (data.getbyte(i) ^ mask.getbyte(i % 4))
end
else
@payload = data
@length = length
end
end
|
#to_ary ⇒ Object
43
44
45
|
# File 'lib/protocol/websocket/frame.rb', line 43
def to_ary
[@finished, @opcode, @mask, @length, @payload]
end
|
#unpack ⇒ Object
86
87
88
|
# File 'lib/protocol/websocket/frame.rb', line 86
def unpack
@payload
end
|
#write(stream) ⇒ Object
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
# File 'lib/protocol/websocket/frame.rb', line 169
def write(stream)
buffer = String.new.b
if @payload&.bytesize != @length
raise ProtocolError, "Invalid payload length: #{@length} != #{@payload.bytesize}!"
end
if @mask and @mask.bytesize != 4
raise ProtocolError, "Invalid mask length!"
end
if length <= 125
short_length = length
elsif length.bit_length <= 16
short_length = 126
else
short_length = 127
end
buffer << [
(@finished ? 0b1000_0000 : 0) | @opcode,
(@mask ? 0b1000_0000 : 0) | short_length,
].pack('CC')
if short_length == 126
buffer << [@length].pack('n')
elsif short_length == 127
buffer << [@length].pack('Q>')
end
stream.write(buffer)
stream.write(@payload)
end
|