v2 / vlib / net / websocket / message.v
293 lines · 275 sloc · 8.87 KB · 7f5cc6fb4bb0e1a24cf27934023d41efa88f30b3
Raw
1module websocket
2
3import encoding.utf8
4
5const header_len_offset = 2 // offset for lengthpart of websocket header
6
7const buffer_size = 256 // default buffer size
8
9const extended_payload16_end_byte = 4 // header length with 16-bit extended payload
10
11const extended_payload64_end_byte = 10
12
13// Fragment represents a websocket data fragment
14struct Fragment {
15 data []u8 // included data payload data in a fragment
16 opcode OPCode // interpretation of the payload data
17}
18
19// Frame represents a data frame header
20struct Frame {
21mut:
22 // length of the websocket header part
23 header_len int = 2
24 // size of total frame
25 frame_size int = 2
26 fin bool // true if final fragment of message
27 rsv1 bool // reserved for future use in websocket RFC
28 rsv2 bool // reserved for future use in websocket RFC
29 rsv3 bool // reserved for future use in websocket RFC
30 opcode OPCode // interpretation of the payload data
31 has_mask bool // true if the payload data is masked
32 payload_len int // payload length
33 masking_key [4]u8 // all frames from client to server is masked with this key
34}
35
36const invalid_close_codes = [999, 1004, 1005, 1006, 1014, 1015, 1016, 1100, 2000, 2999, 5000, 65536]
37
38// validate_client validates client frame rules from RFC6455
39pub fn (mut ws Client) validate_frame(frame &Frame) ! {
40 if frame.rsv1 || frame.rsv2 || frame.rsv3 {
41 ws.close(1002, 'rsv cannot be other than 0, not negotiated')!
42 return error('rsv cannot be other than 0, not negotiated')
43 }
44 if (int(frame.opcode) >= 3 && int(frame.opcode) <= 7)
45 || (int(frame.opcode) >= 11 && int(frame.opcode) <= 15) {
46 ws.close(1002, 'use of reserved opcode')!
47 return error('use of reserved opcode')
48 }
49 if frame.has_mask && !ws.is_server {
50 // server should never send masked frames
51 // to client, close connection
52 ws.close(1002, 'client got masked frame')!
53 return error('client sent masked frame')
54 }
55 if is_control_frame(frame.opcode) {
56 if !frame.fin {
57 ws.close(1002, 'control message must not be fragmented')!
58 return error('unexpected control frame with no fin')
59 }
60 if frame.payload_len > 125 {
61 ws.close(1002, 'control frames must not exceed 125 bytes')!
62 return error('unexpected control frame payload length')
63 }
64 }
65 if frame.fin == false && ws.fragments.len == 0 && frame.opcode == .continuation {
66 err_msg := 'unexecpected continuation, there are no frames to continue, ${frame}'
67 ws.close(1002, err_msg)!
68 return error(err_msg)
69 }
70}
71
72// is_control_frame returns true if the frame is a control frame
73fn is_control_frame(opcode OPCode) bool {
74 return opcode !in [.text_frame, .binary_frame, .continuation]
75}
76
77// is_data_frame returns true if the frame is a control frame
78fn is_data_frame(opcode OPCode) bool {
79 return opcode in [.text_frame, .binary_frame]
80}
81
82// read_payload reads the message payload from the socket
83fn (mut ws Client) read_payload(frame &Frame) ![]u8 {
84 if frame.payload_len == 0 {
85 return []u8{}
86 }
87 mut buffer := []u8{cap: frame.payload_len}
88 mut read_buf := [1]u8{}
89 mut bytes_read := 0
90 for bytes_read < frame.payload_len {
91 len := ws.socket_read_ptr(&read_buf[0], 1)!
92 if len != 1 {
93 return error('expected read all message, got zero')
94 }
95 bytes_read += len
96 buffer << read_buf[0]
97 }
98 if bytes_read != frame.payload_len {
99 return error('failed to read payload')
100 }
101 if frame.has_mask {
102 for i in 0 .. frame.payload_len {
103 buffer[i] ^= frame.masking_key[i % 4] & 0xff
104 }
105 }
106 return buffer
107}
108
109// validate_utf_8 validates payload for valid utf8 encoding
110// - Future implementation needs to support fail fast utf errors for strict autobahn conformance
111fn (mut ws Client) validate_utf_8(opcode OPCode, payload []u8) ! {
112 if opcode in [.text_frame, .close] && !utf8.validate(payload.data, payload.len) {
113 ws.logger.error('malformed utf8 payload, payload len: (${payload.len})')
114 ws.send_error_event('Received malformed utf8.')
115 ws.close(1007, 'malformed utf8 payload')!
116 return error('malformed utf8 payload')
117 }
118}
119
120// read_next_message reads 1 to n frames to compose a message
121pub fn (mut ws Client) read_next_message() !Message {
122 for {
123 frame := ws.parse_frame_header()!
124 ws.validate_frame(&frame)!
125 frame_payload := ws.read_payload(&frame)!
126 if is_control_frame(frame.opcode) {
127 // Control frames can interject other frames
128 // and need to be returned immediately
129 msg := Message{
130 opcode: OPCode(frame.opcode)
131 payload: frame_payload.clone()
132 }
133 unsafe { frame_payload.free() }
134 return msg
135 }
136 // if the message is fragmented we just put it on fragments
137 // a fragment is allowed to have zero size payload
138 if !frame.fin {
139 ws.fragments << &Fragment{
140 data: frame_payload.clone()
141 opcode: frame.opcode
142 }
143 unsafe { frame_payload.free() }
144 continue
145 }
146 if ws.fragments.len == 0 {
147 ws.validate_utf_8(frame.opcode, frame_payload) or {
148 ws.logger.error('UTF8 validation error: ${err}, len of payload(${frame_payload.len})')
149 ws.send_error_event('UTF8 validation error: ${err}, len of payload(${frame_payload.len})')
150 return err
151 }
152 msg := Message{
153 opcode: OPCode(frame.opcode)
154 payload: frame_payload.clone()
155 }
156 unsafe { frame_payload.free() }
157 return msg
158 }
159 defer {
160 ws.fragments = []
161 }
162 if is_data_frame(frame.opcode) {
163 ws.close(0, '')!
164 return error('Unexpected frame opcode')
165 }
166 payload := ws.payload_from_fragments(frame_payload)!
167 opcode := ws.opcode_from_fragments()
168 ws.validate_utf_8(opcode, payload)!
169 msg := Message{
170 opcode: opcode
171 payload: payload.clone()
172 }
173 unsafe {
174 frame_payload.free()
175 payload.free()
176 }
177 return msg
178 }
179 return error('none')
180}
181
182// payload_from_fragments returns the whole payload from fragmented message
183fn (ws &Client) payload_from_fragments(fin_payload []u8) ![]u8 {
184 mut total_size := 0
185 for f in ws.fragments {
186 if f.data.len > 0 {
187 total_size += f.data.len
188 }
189 }
190 total_size += fin_payload.len
191 if total_size == 0 {
192 return []u8{}
193 }
194 mut total_buffer := []u8{cap: total_size}
195 for f in ws.fragments {
196 if f.data.len > 0 {
197 total_buffer << f.data
198 }
199 }
200 total_buffer << fin_payload
201 return total_buffer
202}
203
204// opcode_from_fragments returns the opcode for message from the first fragment sent
205fn (ws &Client) opcode_from_fragments() OPCode {
206 return OPCode(ws.fragments[0].opcode)
207}
208
209// parse_frame_header parses next message by decoding the incoming frames
210pub fn (mut ws Client) parse_frame_header() !Frame {
211 mut buffer := [256]u8{}
212 mut bytes_read := 0
213 mut frame := Frame{}
214 mut rbuff := [1]u8{}
215 mut mask_end_byte := 0
216 for ws.get_state() == .open {
217 read_bytes := ws.socket_read_ptr(&rbuff[0], 1)!
218 if read_bytes == 0 {
219 return error('websocket peer closed connection')
220 }
221 buffer[bytes_read] = rbuff[0]
222 bytes_read++
223 // parses the first two header bytes to get basic frame information
224 if bytes_read == header_len_offset {
225 frame.fin = (buffer[0] & 0x80) == 0x80
226 frame.rsv1 = (buffer[0] & 0x40) == 0x40
227 frame.rsv2 = (buffer[0] & 0x20) == 0x20
228 frame.rsv3 = (buffer[0] & 0x10) == 0x10
229 frame.opcode = unsafe { OPCode(int(buffer[0] & 0x7F)) }
230 frame.has_mask = (buffer[1] & 0x80) == 0x80
231 frame.payload_len = buffer[1] & 0x7F
232 // if the frame has a mask, set the byte position where the mask ends
233 if frame.has_mask {
234 mask_end_byte = if frame.payload_len < 126 {
235 header_len_offset + 4
236 } else if frame.payload_len == 126 {
237 header_len_offset + 6
238 } else if frame.payload_len == 127 {
239 header_len_offset + 12
240 } else {
241 0
242 } // impossible
243 }
244 frame.payload_len = frame.payload_len
245 frame.frame_size = frame.header_len + frame.payload_len
246 if !frame.has_mask && frame.payload_len < 126 {
247 break
248 }
249 }
250 if frame.payload_len == 126 && bytes_read == extended_payload16_end_byte {
251 frame.header_len += 2
252 frame.payload_len = 0
253 frame.payload_len |= int(u32(buffer[2]) << 8)
254 frame.payload_len |= int(buffer[3])
255 frame.frame_size = frame.header_len + frame.payload_len
256 if !frame.has_mask {
257 break
258 }
259 }
260 if frame.payload_len == 127 && bytes_read == extended_payload64_end_byte {
261 frame.header_len += 8
262 // these shift operators needs 64 bit on clang with -prod flag
263 mut payload_len := u64(0)
264 payload_len |= u64(buffer[2]) << 56
265 payload_len |= u64(buffer[3]) << 48
266 payload_len |= u64(buffer[4]) << 40
267 payload_len |= u64(buffer[5]) << 32
268 payload_len |= u64(buffer[6]) << 24
269 payload_len |= u64(buffer[7]) << 16
270 payload_len |= u64(buffer[8]) << 8
271 payload_len |= u64(buffer[9])
272 frame.payload_len = int(payload_len)
273 if !frame.has_mask {
274 break
275 }
276 }
277 if frame.has_mask && bytes_read == mask_end_byte {
278 frame.masking_key[0] = buffer[mask_end_byte - 4]
279 frame.masking_key[1] = buffer[mask_end_byte - 3]
280 frame.masking_key[2] = buffer[mask_end_byte - 2]
281 frame.masking_key[3] = buffer[mask_end_byte - 1]
282 break
283 }
284 }
285 return frame
286}
287
288// unmask_sequence unmask any given sequence
289fn (f &Frame) unmask_sequence(mut buffer []u8) {
290 for i in 0 .. buffer.len {
291 buffer[i] ^= f.masking_key[i % 4] & 0xff
292 }
293}
294