/src/libwebsockets/lib/roles/ws/client-parser-ws.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * libwebsockets - small server side websockets and web server implementation |
3 | | * |
4 | | * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to |
8 | | * deal in the Software without restriction, including without limitation the |
9 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | | * sell copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | | * IN THE SOFTWARE. |
23 | | */ |
24 | | |
25 | | #include "private-lib-core.h" |
26 | | |
27 | | /* |
28 | | * parsers.c: lws_ws_rx_sm() needs to be roughly kept in |
29 | | * sync with changes here, esp related to ext draining |
30 | | * |
31 | | * |
32 | | * We return eithe LWS_HPI_RET_PLEASE_CLOSE_ME if we identified |
33 | | * a situation that requires the stream to close now, or |
34 | | * LWS_HPI_RET_HANDLED if we can continue okay. |
35 | | */ |
36 | | |
37 | | lws_handling_result_t |
38 | | lws_ws_client_rx_sm(struct lws *wsi, unsigned char c) |
39 | 0 | { |
40 | 0 | int callback_action = LWS_CALLBACK_CLIENT_RECEIVE; |
41 | 0 | struct lws_ext_pm_deflate_rx_ebufs pmdrx; |
42 | 0 | unsigned short close_code; |
43 | 0 | unsigned char *pp; |
44 | 0 | int handled, m, n; |
45 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
46 | | int rx_draining_ext = 0; |
47 | | #endif |
48 | |
|
49 | 0 | pmdrx.eb_in.token = NULL; |
50 | 0 | pmdrx.eb_in.len = 0; |
51 | 0 | pmdrx.eb_out.token = NULL; |
52 | 0 | pmdrx.eb_out.len = 0; |
53 | |
|
54 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
55 | | if (wsi->ws->rx_draining_ext) { |
56 | | assert(!c); |
57 | | |
58 | | lws_remove_wsi_from_draining_ext_list(wsi); |
59 | | rx_draining_ext = 1; |
60 | | lwsl_wsi_debug(wsi, "doing draining flow"); |
61 | | |
62 | | goto drain_extension; |
63 | | } |
64 | | #endif |
65 | |
|
66 | 0 | switch (wsi->lws_rx_parse_state) { |
67 | 0 | case LWS_RXPS_NEW: |
68 | | /* control frames (PING) may interrupt checkable sequences */ |
69 | 0 | wsi->ws->defeat_check_utf8 = 0; |
70 | |
|
71 | 0 | switch (wsi->ws->ietf_spec_revision) { |
72 | 0 | case 13: |
73 | 0 | wsi->ws->opcode = c & 0xf; |
74 | | /* revisit if an extension wants them... */ |
75 | 0 | switch (wsi->ws->opcode) { |
76 | 0 | case LWSWSOPC_TEXT_FRAME: |
77 | 0 | wsi->ws->rsv_first_msg = (c & 0x70); |
78 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
79 | | /* |
80 | | * set the expectation that we will have to |
81 | | * fake up the zlib trailer to the inflator for |
82 | | * this frame |
83 | | */ |
84 | | wsi->ws->pmd_trailer_application = !!(c & 0x40); |
85 | | #endif |
86 | 0 | wsi->ws->continuation_possible = 1; |
87 | 0 | wsi->ws->check_utf8 = lws_check_opt( |
88 | 0 | wsi->a.context->options, |
89 | 0 | LWS_SERVER_OPTION_VALIDATE_UTF8); |
90 | 0 | wsi->ws->utf8 = 0; |
91 | 0 | wsi->ws->first_fragment = 1; |
92 | 0 | break; |
93 | 0 | case LWSWSOPC_BINARY_FRAME: |
94 | 0 | wsi->ws->rsv_first_msg = (c & 0x70); |
95 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
96 | | /* |
97 | | * set the expectation that we will have to |
98 | | * fake up the zlib trailer to the inflator for |
99 | | * this frame |
100 | | */ |
101 | | wsi->ws->pmd_trailer_application = !!(c & 0x40); |
102 | | #endif |
103 | 0 | wsi->ws->check_utf8 = 0; |
104 | 0 | wsi->ws->continuation_possible = 1; |
105 | 0 | wsi->ws->first_fragment = 1; |
106 | 0 | break; |
107 | 0 | case LWSWSOPC_CONTINUATION: |
108 | 0 | if (!wsi->ws->continuation_possible) { |
109 | 0 | lwsl_wsi_info(wsi, "disordered continuation"); |
110 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
111 | 0 | } |
112 | 0 | wsi->ws->first_fragment = 0; |
113 | 0 | break; |
114 | 0 | case LWSWSOPC_CLOSE: |
115 | 0 | wsi->ws->check_utf8 = 0; |
116 | 0 | wsi->ws->utf8 = 0; |
117 | 0 | break; |
118 | 0 | case 3: |
119 | 0 | case 4: |
120 | 0 | case 5: |
121 | 0 | case 6: |
122 | 0 | case 7: |
123 | 0 | case 0xb: |
124 | 0 | case 0xc: |
125 | 0 | case 0xd: |
126 | 0 | case 0xe: |
127 | 0 | case 0xf: |
128 | 0 | if (wsi->ws->allow_unknown_opcode) |
129 | 0 | break; |
130 | 0 | lwsl_wsi_info(wsi, "illegal opcode"); |
131 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
132 | 0 | default: |
133 | 0 | wsi->ws->defeat_check_utf8 = 1; |
134 | 0 | break; |
135 | 0 | } |
136 | 0 | wsi->ws->rsv = (c & 0x70); |
137 | | /* revisit if an extension wants them... */ |
138 | 0 | if ( |
139 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
140 | | !wsi->ws->count_act_ext && |
141 | | #endif |
142 | 0 | wsi->ws->rsv && !wsi->ws->allow_reserved_bits) { |
143 | 0 | lwsl_wsi_info(wsi, "illegal rsv bits set"); |
144 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
145 | 0 | } |
146 | 0 | wsi->ws->final = !!((c >> 7) & 1); |
147 | 0 | lwsl_wsi_ext(wsi, " This RX frame Final %d", |
148 | 0 | wsi->ws->final); |
149 | |
|
150 | 0 | if (wsi->ws->owed_a_fin && |
151 | 0 | (wsi->ws->opcode == LWSWSOPC_TEXT_FRAME || |
152 | 0 | wsi->ws->opcode == LWSWSOPC_BINARY_FRAME)) { |
153 | 0 | lwsl_wsi_info(wsi, "hey you owed us a FIN"); |
154 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
155 | 0 | } |
156 | 0 | if ((!(wsi->ws->opcode & 8)) && wsi->ws->final) { |
157 | 0 | wsi->ws->continuation_possible = 0; |
158 | 0 | wsi->ws->owed_a_fin = 0; |
159 | 0 | } |
160 | |
|
161 | 0 | if ((wsi->ws->opcode & 8) && !wsi->ws->final) { |
162 | 0 | lwsl_wsi_info(wsi, "control msg can't be fragmented"); |
163 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
164 | 0 | } |
165 | 0 | if (!wsi->ws->final) |
166 | 0 | wsi->ws->owed_a_fin = 1; |
167 | |
|
168 | 0 | switch (wsi->ws->opcode) { |
169 | 0 | case LWSWSOPC_TEXT_FRAME: |
170 | 0 | case LWSWSOPC_BINARY_FRAME: |
171 | 0 | wsi->ws->frame_is_binary = wsi->ws->opcode == |
172 | 0 | LWSWSOPC_BINARY_FRAME; |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN; |
176 | 0 | break; |
177 | | |
178 | 0 | default: |
179 | 0 | lwsl_wsi_err(wsi, "unknown spec version %02d", |
180 | 0 | wsi->ws->ietf_spec_revision); |
181 | 0 | break; |
182 | 0 | } |
183 | 0 | break; |
184 | | |
185 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN: |
186 | |
|
187 | 0 | wsi->ws->this_frame_masked = !!(c & 0x80); |
188 | 0 | if (wsi->ws->this_frame_masked) |
189 | 0 | goto server_cannot_mask; |
190 | | |
191 | 0 | switch (c & 0x7f) { |
192 | 0 | case 126: |
193 | | /* control frames are not allowed to have big lengths */ |
194 | 0 | if (wsi->ws->opcode & 8) |
195 | 0 | goto illegal_ctl_length; |
196 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2; |
197 | 0 | break; |
198 | 0 | case 127: |
199 | | /* control frames are not allowed to have big lengths */ |
200 | 0 | if (wsi->ws->opcode & 8) |
201 | 0 | goto illegal_ctl_length; |
202 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8; |
203 | 0 | break; |
204 | 0 | default: |
205 | 0 | wsi->ws->rx_packet_length = c & 0x7f; |
206 | 0 | if (wsi->ws->this_frame_masked) |
207 | 0 | wsi->lws_rx_parse_state = |
208 | 0 | LWS_RXPS_07_COLLECT_FRAME_KEY_1; |
209 | 0 | else { |
210 | 0 | if (wsi->ws->rx_packet_length) { |
211 | 0 | wsi->lws_rx_parse_state = |
212 | 0 | LWS_RXPS_WS_FRAME_PAYLOAD; |
213 | 0 | } else { |
214 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_NEW; |
215 | 0 | goto spill; |
216 | 0 | } |
217 | 0 | } |
218 | 0 | break; |
219 | 0 | } |
220 | 0 | break; |
221 | | |
222 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN16_2: |
223 | 0 | wsi->ws->rx_packet_length = (size_t)((unsigned int)c << 8); |
224 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1; |
225 | 0 | break; |
226 | | |
227 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN16_1: |
228 | 0 | wsi->ws->rx_packet_length |= c; |
229 | 0 | if (wsi->ws->this_frame_masked) |
230 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_1; |
231 | 0 | else { |
232 | 0 | if (wsi->ws->rx_packet_length) |
233 | 0 | wsi->lws_rx_parse_state = |
234 | 0 | LWS_RXPS_WS_FRAME_PAYLOAD; |
235 | 0 | else { |
236 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_NEW; |
237 | 0 | goto spill; |
238 | 0 | } |
239 | 0 | } |
240 | 0 | break; |
241 | | |
242 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_8: |
243 | 0 | if (c & 0x80) { |
244 | 0 | lwsl_wsi_warn(wsi, "b63 of length must be zero"); |
245 | | /* kill the connection */ |
246 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
247 | 0 | } |
248 | 0 | #if defined __LP64__ |
249 | 0 | wsi->ws->rx_packet_length = ((size_t)c) << 56; |
250 | | #else |
251 | | wsi->ws->rx_packet_length = 0; |
252 | | #endif |
253 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7; |
254 | 0 | break; |
255 | | |
256 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_7: |
257 | 0 | #if defined __LP64__ |
258 | 0 | wsi->ws->rx_packet_length |= ((size_t)c) << 48; |
259 | 0 | #endif |
260 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6; |
261 | 0 | break; |
262 | | |
263 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_6: |
264 | 0 | #if defined __LP64__ |
265 | 0 | wsi->ws->rx_packet_length |= ((size_t)c) << 40; |
266 | 0 | #endif |
267 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5; |
268 | 0 | break; |
269 | | |
270 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_5: |
271 | 0 | #if defined __LP64__ |
272 | 0 | wsi->ws->rx_packet_length |= ((size_t)c) << 32; |
273 | 0 | #endif |
274 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4; |
275 | 0 | break; |
276 | | |
277 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_4: |
278 | 0 | wsi->ws->rx_packet_length |= ((size_t)c) << 24; |
279 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3; |
280 | 0 | break; |
281 | | |
282 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_3: |
283 | 0 | wsi->ws->rx_packet_length |= ((size_t)c) << 16; |
284 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2; |
285 | 0 | break; |
286 | | |
287 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_2: |
288 | 0 | wsi->ws->rx_packet_length |= ((size_t)c) << 8; |
289 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1; |
290 | 0 | break; |
291 | | |
292 | 0 | case LWS_RXPS_04_FRAME_HDR_LEN64_1: |
293 | 0 | wsi->ws->rx_packet_length |= (size_t)c; |
294 | 0 | if (wsi->ws->this_frame_masked) |
295 | 0 | wsi->lws_rx_parse_state = |
296 | 0 | LWS_RXPS_07_COLLECT_FRAME_KEY_1; |
297 | 0 | else { |
298 | 0 | if (wsi->ws->rx_packet_length) |
299 | 0 | wsi->lws_rx_parse_state = |
300 | 0 | LWS_RXPS_WS_FRAME_PAYLOAD; |
301 | 0 | else { |
302 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_NEW; |
303 | 0 | goto spill; |
304 | 0 | } |
305 | 0 | } |
306 | 0 | break; |
307 | | |
308 | 0 | case LWS_RXPS_07_COLLECT_FRAME_KEY_1: |
309 | 0 | wsi->ws->mask[0] = c; |
310 | 0 | if (c) |
311 | 0 | wsi->ws->all_zero_nonce = 0; |
312 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2; |
313 | 0 | break; |
314 | | |
315 | 0 | case LWS_RXPS_07_COLLECT_FRAME_KEY_2: |
316 | 0 | wsi->ws->mask[1] = c; |
317 | 0 | if (c) |
318 | 0 | wsi->ws->all_zero_nonce = 0; |
319 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3; |
320 | 0 | break; |
321 | | |
322 | 0 | case LWS_RXPS_07_COLLECT_FRAME_KEY_3: |
323 | 0 | wsi->ws->mask[2] = c; |
324 | 0 | if (c) |
325 | 0 | wsi->ws->all_zero_nonce = 0; |
326 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4; |
327 | 0 | break; |
328 | | |
329 | 0 | case LWS_RXPS_07_COLLECT_FRAME_KEY_4: |
330 | 0 | wsi->ws->mask[3] = c; |
331 | 0 | if (c) |
332 | 0 | wsi->ws->all_zero_nonce = 0; |
333 | |
|
334 | 0 | if (wsi->ws->rx_packet_length) |
335 | 0 | wsi->lws_rx_parse_state = |
336 | 0 | LWS_RXPS_WS_FRAME_PAYLOAD; |
337 | 0 | else { |
338 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_NEW; |
339 | 0 | goto spill; |
340 | 0 | } |
341 | 0 | break; |
342 | | |
343 | 0 | case LWS_RXPS_WS_FRAME_PAYLOAD: |
344 | |
|
345 | 0 | assert(wsi->ws->rx_ubuf); |
346 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
347 | | if (wsi->ws->rx_draining_ext) |
348 | | goto drain_extension; |
349 | | #endif |
350 | 0 | if (wsi->ws->this_frame_masked && !wsi->ws->all_zero_nonce) |
351 | 0 | c ^= wsi->ws->mask[(wsi->ws->mask_idx++) & 3]; |
352 | | |
353 | | /* |
354 | | * unmask and collect the payload body in |
355 | | * rx_ubuf_head + LWS_PRE |
356 | | */ |
357 | |
|
358 | 0 | wsi->ws->rx_ubuf[LWS_PRE + (wsi->ws->rx_ubuf_head++)] = c; |
359 | |
|
360 | 0 | if (--wsi->ws->rx_packet_length == 0) { |
361 | | /* spill because we have the whole frame */ |
362 | 0 | wsi->lws_rx_parse_state = LWS_RXPS_NEW; |
363 | 0 | lwsl_wsi_debug(wsi, "spilling as we have the whole frame"); |
364 | 0 | goto spill; |
365 | 0 | } |
366 | | |
367 | | /* |
368 | | * if there's no protocol max frame size given, we are |
369 | | * supposed to default to context->pt_serv_buf_size |
370 | | */ |
371 | 0 | if (!wsi->a.protocol->rx_buffer_size && |
372 | 0 | wsi->ws->rx_ubuf_head != wsi->a.context->pt_serv_buf_size) |
373 | 0 | break; |
374 | | |
375 | 0 | if (wsi->a.protocol->rx_buffer_size && |
376 | 0 | wsi->ws->rx_ubuf_head != wsi->a.protocol->rx_buffer_size) |
377 | 0 | break; |
378 | | |
379 | | /* spill because we filled our rx buffer */ |
380 | | |
381 | 0 | lwsl_wsi_debug(wsi, "spilling as we filled our rx buffer"); |
382 | 0 | spill: |
383 | |
|
384 | 0 | handled = 0; |
385 | | |
386 | | /* |
387 | | * is this frame a control packet we should take care of at this |
388 | | * layer? If so service it and hide it from the user callback |
389 | | */ |
390 | |
|
391 | 0 | switch (wsi->ws->opcode) { |
392 | 0 | case LWSWSOPC_CLOSE: |
393 | 0 | pp = &wsi->ws->rx_ubuf[LWS_PRE]; |
394 | 0 | if (lws_check_opt(wsi->a.context->options, |
395 | 0 | LWS_SERVER_OPTION_VALIDATE_UTF8) && |
396 | 0 | wsi->ws->rx_ubuf_head > 2 && |
397 | 0 | lws_check_utf8(&wsi->ws->utf8, pp + 2, |
398 | 0 | wsi->ws->rx_ubuf_head - 2)) |
399 | 0 | goto utf8_fail; |
400 | | |
401 | | /* is this an acknowledgment of our close? */ |
402 | 0 | if (lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) { |
403 | | /* |
404 | | * fine he has told us he is closing too, let's |
405 | | * finish our close |
406 | | */ |
407 | 0 | lwsl_wsi_parser(wsi, "seen server's close ack"); |
408 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
409 | 0 | } |
410 | | |
411 | 0 | lwsl_wsi_parser(wsi, "client sees server close len = %d", |
412 | 0 | (int)wsi->ws->rx_ubuf_head); |
413 | 0 | if (wsi->ws->rx_ubuf_head >= 2) { |
414 | 0 | close_code = (unsigned short)((pp[0] << 8) | pp[1]); |
415 | 0 | if (close_code < 1000 || |
416 | 0 | close_code == 1004 || |
417 | 0 | close_code == 1005 || |
418 | 0 | close_code == 1006 || |
419 | 0 | (close_code >= 1016 && close_code < 3000) |
420 | 0 | ) { |
421 | 0 | pp[0] = (LWS_CLOSE_STATUS_PROTOCOL_ERR >> 8) & 0xff; |
422 | 0 | pp[1] = LWS_CLOSE_STATUS_PROTOCOL_ERR & 0xff; |
423 | 0 | } |
424 | 0 | } |
425 | 0 | if (user_callback_handle_rxflow( |
426 | 0 | wsi->a.protocol->callback, wsi, |
427 | 0 | LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, |
428 | 0 | wsi->user_space, pp, |
429 | 0 | wsi->ws->rx_ubuf_head)) |
430 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
431 | | |
432 | 0 | memcpy(wsi->ws->ping_payload_buf + LWS_PRE, pp, |
433 | 0 | wsi->ws->rx_ubuf_head); |
434 | 0 | wsi->ws->close_in_ping_buffer_len = |
435 | 0 | (uint8_t)wsi->ws->rx_ubuf_head; |
436 | |
|
437 | 0 | lwsl_wsi_info(wsi, "scheduling return close as ack"); |
438 | 0 | __lws_change_pollfd(wsi, LWS_POLLIN, 0); |
439 | 0 | lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 3); |
440 | 0 | wsi->waiting_to_send_close_frame = 1; |
441 | 0 | wsi->close_needs_ack = 0; |
442 | 0 | lwsi_set_state(wsi, LRS_WAITING_TO_SEND_CLOSE); |
443 | 0 | lws_callback_on_writable(wsi); |
444 | 0 | handled = 1; |
445 | 0 | break; |
446 | | |
447 | 0 | case LWSWSOPC_PING: |
448 | 0 | lwsl_wsi_info(wsi, "received %d byte ping, sending pong", |
449 | 0 | (int)wsi->ws->rx_ubuf_head); |
450 | | |
451 | | /* he set a close reason on this guy, ignore PING */ |
452 | 0 | if (wsi->ws->close_in_ping_buffer_len) |
453 | 0 | goto ping_drop; |
454 | | |
455 | 0 | if (wsi->ws->pong_pending_flag) { |
456 | | /* |
457 | | * there is already a pending pong payload |
458 | | * we should just log and drop |
459 | | */ |
460 | 0 | lwsl_wsi_parser(wsi, "DROP PING since one pending"); |
461 | 0 | goto ping_drop; |
462 | 0 | } |
463 | | |
464 | | /* control packets can only be < 128 bytes long */ |
465 | 0 | if (wsi->ws->rx_ubuf_head > 128 - 3) { |
466 | 0 | lwsl_wsi_parser(wsi, "DROP PING payload too large"); |
467 | 0 | goto ping_drop; |
468 | 0 | } |
469 | | |
470 | | /* stash the pong payload */ |
471 | 0 | memcpy(wsi->ws->pong_payload_buf + LWS_PRE, |
472 | 0 | &wsi->ws->rx_ubuf[LWS_PRE], |
473 | 0 | wsi->ws->rx_ubuf_head); |
474 | |
|
475 | 0 | wsi->ws->pong_payload_len = (uint8_t)wsi->ws->rx_ubuf_head; |
476 | 0 | wsi->ws->pong_pending_flag = 1; |
477 | | |
478 | | /* get it sent as soon as possible */ |
479 | 0 | lws_callback_on_writable(wsi); |
480 | 0 | ping_drop: |
481 | 0 | wsi->ws->rx_ubuf_head = 0; |
482 | 0 | handled = 1; |
483 | 0 | break; |
484 | | |
485 | 0 | case LWSWSOPC_PONG: |
486 | 0 | lwsl_wsi_info(wsi, "Received pong"); |
487 | 0 | lwsl_hexdump_wsi_debug(wsi, &wsi->ws->rx_ubuf[LWS_PRE], |
488 | 0 | wsi->ws->rx_ubuf_head); |
489 | |
|
490 | 0 | lws_validity_confirmed(wsi); |
491 | | /* issue it */ |
492 | 0 | callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG; |
493 | 0 | break; |
494 | | |
495 | 0 | case LWSWSOPC_CONTINUATION: |
496 | 0 | case LWSWSOPC_TEXT_FRAME: |
497 | 0 | case LWSWSOPC_BINARY_FRAME: |
498 | 0 | break; |
499 | | |
500 | 0 | default: |
501 | | /* not handled or failed */ |
502 | 0 | lwsl_wsi_ext(wsi, "Unhandled ext opc 0x%x", wsi->ws->opcode); |
503 | 0 | wsi->ws->rx_ubuf_head = 0; |
504 | |
|
505 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
506 | 0 | } |
507 | | |
508 | | /* |
509 | | * No it's real payload, pass it up to the user callback. |
510 | | * |
511 | | * We have been statefully collecting it in the |
512 | | * LWS_RXPS_WS_FRAME_PAYLOAD clause above. |
513 | | * |
514 | | * It's nicely buffered with the pre-padding taken care of |
515 | | * so it can be sent straight out again using lws_write. |
516 | | * |
517 | | * However, now we have a chunk of it, we want to deal with it |
518 | | * all here. Since this may be input to permessage-deflate and |
519 | | * there are block limits on that for input and output, we may |
520 | | * need to iterate. |
521 | | */ |
522 | 0 | if (handled) |
523 | 0 | goto already_done; |
524 | | |
525 | 0 | pmdrx.eb_in.token = &wsi->ws->rx_ubuf[LWS_PRE]; |
526 | 0 | pmdrx.eb_in.len = (int)wsi->ws->rx_ubuf_head; |
527 | | |
528 | | /* for the non-pm-deflate case */ |
529 | |
|
530 | 0 | pmdrx.eb_out = pmdrx.eb_in; |
531 | |
|
532 | 0 | lwsl_wsi_debug(wsi, "starting disbursal of %d deframed rx", |
533 | 0 | (int)wsi->ws->rx_ubuf_head); |
534 | |
|
535 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
536 | | drain_extension: |
537 | | #endif |
538 | 0 | do { |
539 | | |
540 | | // lwsl_wsi_notice("pmdrx.eb_in.len: %d", |
541 | | // (int)pmdrx.eb_in.len); |
542 | |
|
543 | 0 | n = PMDR_DID_NOTHING; |
544 | |
|
545 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
546 | | lwsl_wsi_ext(wsi, "+++ passing %d %p to ext", |
547 | | pmdrx.eb_in.len, pmdrx.eb_in.token); |
548 | | |
549 | | n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, |
550 | | &pmdrx, 0); |
551 | | lwsl_wsi_ext(wsi, "Ext RX returned %d", n); |
552 | | if (n < 0) { |
553 | | wsi->socket_is_permanently_unusable = 1; |
554 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
555 | | } |
556 | | if (n == PMDR_DID_NOTHING) |
557 | | /* ie, not PMDR_NOTHING_WE_SHOULD_DO */ |
558 | | break; |
559 | | #endif |
560 | 0 | lwsl_wsi_ext(wsi, "post inflate ebuf in len %d / out len %d", |
561 | 0 | pmdrx.eb_in.len, pmdrx.eb_out.len); |
562 | |
|
563 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
564 | | if (rx_draining_ext && !pmdrx.eb_out.len) { |
565 | | lwsl_wsi_debug(wsi, " --- ending drain on 0 read result"); |
566 | | goto already_done; |
567 | | } |
568 | | |
569 | | if (n == PMDR_HAS_PENDING) { /* 1 means stuff to drain */ |
570 | | /* extension had more... main loop will come back */ |
571 | | lwsl_wsi_ext(wsi, "adding to draining ext list"); |
572 | | lws_add_wsi_to_draining_ext_list(wsi); |
573 | | } else { |
574 | | lwsl_wsi_ext(wsi, "removing from draining ext list"); |
575 | | lws_remove_wsi_from_draining_ext_list(wsi); |
576 | | } |
577 | | rx_draining_ext = wsi->ws->rx_draining_ext; |
578 | | #endif |
579 | |
|
580 | 0 | if (wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) { |
581 | |
|
582 | 0 | if (lws_check_utf8(&wsi->ws->utf8, |
583 | 0 | pmdrx.eb_out.token, |
584 | 0 | (unsigned int)pmdrx.eb_out.len)) { |
585 | 0 | lws_close_reason(wsi, |
586 | 0 | LWS_CLOSE_STATUS_INVALID_PAYLOAD, |
587 | 0 | (uint8_t *)"bad utf8", 8); |
588 | 0 | goto utf8_fail; |
589 | 0 | } |
590 | | |
591 | | /* we are ending partway through utf-8 character? */ |
592 | 0 | if (!wsi->ws->rx_packet_length && |
593 | 0 | wsi->ws->final && wsi->ws->utf8 |
594 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
595 | | /* if ext not negotiated, going to be UNKNOWN */ |
596 | | && (n == PMDR_EMPTY_FINAL || n == PMDR_UNKNOWN) |
597 | | #endif |
598 | 0 | ) { |
599 | 0 | lwsl_wsi_info(wsi, "FINAL utf8 error"); |
600 | 0 | lws_close_reason(wsi, |
601 | 0 | LWS_CLOSE_STATUS_INVALID_PAYLOAD, |
602 | 0 | (uint8_t *)"partial utf8", 12); |
603 | 0 | utf8_fail: |
604 | 0 | lwsl_wsi_info(wsi, "utf8 error"); |
605 | 0 | lwsl_hexdump_wsi_info(wsi, pmdrx.eb_out.token, |
606 | 0 | (unsigned int)pmdrx.eb_out.len); |
607 | |
|
608 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
609 | 0 | } |
610 | 0 | } |
611 | | |
612 | 0 | if (pmdrx.eb_out.len < 0 && |
613 | 0 | callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG) |
614 | 0 | goto already_done; |
615 | | |
616 | 0 | if (!pmdrx.eb_out.token) |
617 | 0 | goto already_done; |
618 | | |
619 | 0 | pmdrx.eb_out.token[pmdrx.eb_out.len] = '\0'; |
620 | |
|
621 | 0 | if (!wsi->a.protocol->callback) |
622 | 0 | goto already_done; |
623 | | |
624 | 0 | if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG) |
625 | 0 | lwsl_wsi_info(wsi, "Client doing pong callback"); |
626 | |
|
627 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
628 | | if (n == PMDR_HAS_PENDING) |
629 | | /* extension had more... main loop will come back |
630 | | * we want callback to be done with this set, if so, |
631 | | * because lws_is_final() hides it was final until the |
632 | | * last chunk |
633 | | */ |
634 | | lws_add_wsi_to_draining_ext_list(wsi); |
635 | | else |
636 | | lws_remove_wsi_from_draining_ext_list(wsi); |
637 | | #endif |
638 | |
|
639 | 0 | if (lwsi_state(wsi) == LRS_RETURNED_CLOSE || |
640 | 0 | lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE || |
641 | 0 | lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) |
642 | 0 | goto already_done; |
643 | | |
644 | | /* if pmd not enabled, in == out */ |
645 | | |
646 | 0 | if (n == PMDR_DID_NOTHING |
647 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
648 | | || n == PMDR_NOTHING_WE_SHOULD_DO |
649 | | || n == PMDR_UNKNOWN |
650 | | #endif |
651 | 0 | ) |
652 | 0 | pmdrx.eb_in.len -= pmdrx.eb_out.len; |
653 | |
|
654 | 0 | m = wsi->a.protocol->callback(wsi, |
655 | 0 | (enum lws_callback_reasons)callback_action, |
656 | 0 | wsi->user_space, pmdrx.eb_out.token, |
657 | 0 | (unsigned int)pmdrx.eb_out.len); |
658 | |
|
659 | 0 | wsi->ws->first_fragment = 0; |
660 | |
|
661 | 0 | lwsl_wsi_debug(wsi, "bulk ws rx: inp used %d, output %d", |
662 | 0 | (int)wsi->ws->rx_ubuf_head, |
663 | 0 | (int)pmdrx.eb_out.len); |
664 | | |
665 | | /* if user code wants to close, let caller know */ |
666 | 0 | if (m) |
667 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
668 | |
|
669 | 0 | } while (pmdrx.eb_in.len |
670 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
671 | | || rx_draining_ext |
672 | | #endif |
673 | 0 | ); |
674 | | |
675 | 0 | already_done: |
676 | 0 | wsi->ws->rx_ubuf_head = 0; |
677 | 0 | break; |
678 | 0 | default: |
679 | 0 | lwsl_wsi_err(wsi, "client rx illegal state"); |
680 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
681 | 0 | } |
682 | | |
683 | 0 | return LWS_HPI_RET_HANDLED; |
684 | | |
685 | 0 | illegal_ctl_length: |
686 | 0 | lwsl_wsi_warn(wsi, "Control frame asking for extended length is illegal"); |
687 | | |
688 | | /* kill the connection */ |
689 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
690 | | |
691 | 0 | server_cannot_mask: |
692 | 0 | lws_close_reason(wsi, |
693 | 0 | LWS_CLOSE_STATUS_PROTOCOL_ERR, |
694 | 0 | (uint8_t *)"srv mask", 8); |
695 | |
|
696 | 0 | lwsl_wsi_warn(wsi, "Server must not mask"); |
697 | | |
698 | | /* kill the connection */ |
699 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
700 | 0 | } |
701 | | |
702 | | |