Class: Protocol::WebSocket::Frame
- Inherits:
-
Object
- Object
- Protocol::WebSocket::Frame
- Includes:
- Comparable
- Defined in:
- lib/protocol/websocket/frame.rb
Constant Summary collapse
- CONTINUATION =
Opcodes
0x0- TEXT =
0x1- BINARY =
0x2- CLOSE =
0x8- PING =
0x9- PONG =
0xA
Instance Attribute Summary collapse
-
#fin ⇒ Object
The generic frame header uses the following binary representation:.
-
#length ⇒ Object
Returns the value of attribute length.
-
#mask ⇒ Object
Returns the value of attribute mask.
-
#opcode ⇒ Object
Returns the value of attribute opcode.
-
#payload ⇒ Object
Returns the value of attribute payload.
Class Method Summary collapse
Instance Method Summary collapse
- #<=>(other) ⇒ Object
- #continued? ⇒ Boolean
- #control? ⇒ Boolean
-
#initialize(fin = true, opcode = 0, mask = nil, payload = nil) ⇒ Frame
constructor
A new instance of Frame.
- #pack(payload) ⇒ Object
- #read(stream) ⇒ Object
- #to_ary ⇒ Object
- #unpack ⇒ Object
- #write(stream) ⇒ Object
Constructor Details
#initialize(fin = true, opcode = 0, mask = nil, payload = nil) ⇒ Frame
Returns a new instance of Frame.
37 38 39 40 41 42 43 |
# File 'lib/protocol/websocket/frame.rb', line 37 def initialize(fin = true, opcode = 0, mask = nil, payload = nil) @fin = fin @opcode = opcode @mask = mask @length = payload&.bytesize @payload = payload end |
Instance Attribute Details
#fin ⇒ 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 … | ---------------------------------------------------------------
92 93 94 |
# File 'lib/protocol/websocket/frame.rb', line 92 def fin @fin end |
#length ⇒ Object
Returns the value of attribute length.
95 96 97 |
# File 'lib/protocol/websocket/frame.rb', line 95 def length @length end |
#mask ⇒ Object
Returns the value of attribute mask.
94 95 96 |
# File 'lib/protocol/websocket/frame.rb', line 94 def mask @mask end |
#opcode ⇒ Object
Returns the value of attribute opcode.
93 94 95 |
# File 'lib/protocol/websocket/frame.rb', line 93 def opcode @opcode end |
#payload ⇒ Object
Returns the value of attribute payload.
96 97 98 |
# File 'lib/protocol/websocket/frame.rb', line 96 def payload @payload end |
Class Method Details
.read(stream) ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/protocol/websocket/frame.rb', line 45 def self.read(stream) frame = self.new if frame.read(stream) return frame end rescue EOFError return nil end |
Instance Method Details
#<=>(other) ⇒ Object
55 56 57 |
# File 'lib/protocol/websocket/frame.rb', line 55 def <=> other to_ary <=> other.to_ary end |
#continued? ⇒ Boolean
67 68 69 |
# File 'lib/protocol/websocket/frame.rb', line 67 def continued? @fin == false end |
#control? ⇒ Boolean
63 64 65 |
# File 'lib/protocol/websocket/frame.rb', line 63 def control? @opcode & 0x8 end |
#pack(payload) ⇒ Object
102 103 104 105 106 107 108 109 |
# File 'lib/protocol/websocket/frame.rb', line 102 def pack(payload) @payload = payload @length = payload.bytesize if @length.bit_length > 64 raise ProtocolError, "Frame length #{@length} bigger than allowed 64-bit field!" end end |
#read(stream) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/protocol/websocket/frame.rb', line 111 def read(stream) buffer = stream.read(2) or raise EOFError first, second = buffer.unpack("CC") @fin = (first & 0b1000_0000 != 0) # rsv = byte & 0b0111_0000 @opcode = first & 0b0000_1111 @mask = (second & 0b1000_0000 != 0) @length = second & 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 @mask @mask = stream.read(4) or raise EOFError @payload = read_mask(@mask, @length, stream) else @mask = nil @payload = stream.read(@length) or raise EOFError end if @payload&.bytesize != @length raise ProtocolError, "Invalid payload size: #{@length} != #{@payload.bytesize}!" end return true end |
#to_ary ⇒ Object
59 60 61 |
# File 'lib/protocol/websocket/frame.rb', line 59 def to_ary [@fin, @opcode, @mask, @length, @payload] end |
#unpack ⇒ Object
98 99 100 |
# File 'lib/protocol/websocket/frame.rb', line 98 def unpack @payload end |
#write(stream) ⇒ Object
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/protocol/websocket/frame.rb', line 145 def write(stream) buffer = String.new.b if @payload&.bytesize != @length raise ProtocolError, "Invalid payload size: #{@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 << [ (@fin ? 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 if @mask buffer << @mask write_mask(@mask, @payload, buffer) stream.write(buffer) else stream.write(buffer) stream.write(@payload) end end |