Coverage Report

Created: 2025-07-11 06:34

/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