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 #define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
28
29 #if !defined(LWS_WITHOUT_EXTENSIONS)
30 static int
lws_extension_server_handshake(struct lws * wsi,char ** p,int budget)31 lws_extension_server_handshake(struct lws *wsi, char **p, int budget)
32 {
33 struct lws_context *context = wsi->context;
34 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
35 char ext_name[64], *args, *end = (*p) + budget - 1;
36 const struct lws_ext_options *opts, *po;
37 const struct lws_extension *ext;
38 struct lws_ext_option_arg oa;
39 int n, m, more = 1;
40 int ext_count = 0;
41 char ignore;
42 char *c;
43
44 /*
45 * Figure out which extensions the client has that we want to
46 * enable on this connection, and give him back the list
47 */
48 if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS))
49 return 0;
50
51 /*
52 * break down the list of client extensions
53 * and go through them
54 */
55
56 if (lws_hdr_copy(wsi, (char *)pt->serv_buf, context->pt_serv_buf_size,
57 WSI_TOKEN_EXTENSIONS) < 0)
58 return 1;
59
60 c = (char *)pt->serv_buf;
61 lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c);
62 wsi->ws->count_act_ext = 0;
63 ignore = 0;
64 n = 0;
65 args = NULL;
66
67 /*
68 * We may get a simple request
69 *
70 * Sec-WebSocket-Extensions: permessage-deflate
71 *
72 * or an elaborated one with requested options
73 *
74 * Sec-WebSocket-Extensions: permessage-deflate; \
75 * server_no_context_takeover; \
76 * client_no_context_takeover
77 */
78
79 while (more) {
80
81 if (c >= (char *)pt->serv_buf + 255)
82 return -1;
83
84 if (*c && (*c != ',' && *c != '\t')) {
85 if (*c == ';') {
86 ignore = 1;
87 if (!args)
88 args = c + 1;
89 }
90 if (ignore || *c == ' ') {
91 c++;
92 continue;
93 }
94 ext_name[n] = *c++;
95 if (n < (int)sizeof(ext_name) - 1)
96 n++;
97 continue;
98 }
99 ext_name[n] = '\0';
100
101 ignore = 0;
102 if (!*c)
103 more = 0;
104 else {
105 c++;
106 if (!n)
107 continue;
108 }
109
110 while (args && *args == ' ')
111 args++;
112
113 /* check a client's extension against our support */
114
115 ext = wsi->vhost->ws.extensions;
116
117 while (ext && ext->callback) {
118
119 if (strcmp(ext_name, ext->name)) {
120 ext++;
121 continue;
122 }
123
124 /*
125 * oh, we do support this one he asked for... but let's
126 * confirm he only gave it once
127 */
128 for (m = 0; m < wsi->ws->count_act_ext; m++)
129 if (wsi->ws->active_extensions[m] == ext) {
130 lwsl_info("ext mentioned twice\n");
131 return 1; /* shenanigans */
132 }
133
134 /*
135 * ask user code if it's OK to apply it on this
136 * particular connection + protocol
137 */
138 m = (wsi->protocol->callback)(wsi,
139 LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
140 wsi->user_space, ext_name, 0);
141
142 /*
143 * zero return from callback means go ahead and allow
144 * the extension, it's what we get if the callback is
145 * unhandled
146 */
147 if (m) {
148 ext++;
149 continue;
150 }
151
152 /* apply it */
153
154 ext_count++;
155
156 /* instantiate the extension on this conn */
157
158 wsi->ws->active_extensions[wsi->ws->count_act_ext] = ext;
159
160 /* allow him to construct his context */
161
162 if (ext->callback(lws_get_context(wsi), ext, wsi,
163 LWS_EXT_CB_CONSTRUCT,
164 (void *)&wsi->ws->act_ext_user[
165 wsi->ws->count_act_ext],
166 (void *)&opts, 0)) {
167 lwsl_info("ext %s failed construction\n",
168 ext_name);
169 ext_count--;
170 ext++;
171
172 continue;
173 }
174
175 if (ext_count > 1)
176 *(*p)++ = ',';
177 else
178 LWS_CPYAPP(*p,
179 "\x0d\x0aSec-WebSocket-Extensions: ");
180 *p += lws_snprintf(*p, (end - *p), "%s", ext_name);
181
182 /*
183 * The client may send a bunch of different option
184 * sets for the same extension, we are supposed to
185 * pick one we like the look of. The option sets are
186 * separated by comma.
187 *
188 * Actually we just either accept the first one or
189 * nothing.
190 *
191 * Go through the options trying to apply the
192 * recognized ones
193 */
194
195 lwsl_info("ext args %s\n", args);
196
197 while (args && *args && *args != ',') {
198 while (*args == ' ')
199 args++;
200 po = opts;
201 while (po->name) {
202 /* only support arg-less options... */
203 if (po->type != EXTARG_NONE ||
204 strncmp(args, po->name,
205 strlen(po->name))) {
206 po++;
207 continue;
208 }
209 oa.option_name = NULL;
210 oa.option_index = (int)(po - opts);
211 oa.start = NULL;
212 oa.len = 0;
213 lwsl_info("setting '%s'\n", po->name);
214 if (!ext->callback(lws_get_context(wsi),
215 ext, wsi,
216 LWS_EXT_CB_OPTION_SET,
217 wsi->ws->act_ext_user[
218 wsi->ws->count_act_ext],
219 &oa, (end - *p))) {
220
221 *p += lws_snprintf(*p,
222 (end - *p),
223 "; %s", po->name);
224 lwsl_debug("adding option %s\n",
225 po->name);
226 }
227 po++;
228 }
229 while (*args && *args != ',' && *args != ';')
230 args++;
231
232 if (*args == ';')
233 args++;
234 }
235
236 wsi->ws->count_act_ext++;
237 lwsl_parser("cnt_act_ext <- %d\n",
238 wsi->ws->count_act_ext);
239
240 if (args && *args == ',')
241 more = 0;
242
243 ext++;
244 }
245
246 n = 0;
247 args = NULL;
248 }
249
250 return 0;
251 }
252 #endif
253
254 int
lws_process_ws_upgrade2(struct lws * wsi)255 lws_process_ws_upgrade2(struct lws *wsi)
256 {
257 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
258 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
259 const struct lws_protocol_vhost_options *pvos = NULL;
260 const char *ws_prot_basic_auth = NULL;
261
262
263 /*
264 * Allow basic auth a look-in now we bound the wsi to the protocol.
265 *
266 * For vhost ws basic auth, it is "basic-auth": "path" as usual but
267 * applied to the protocol's entry in the vhost's "ws-protocols":
268 * section, as a pvo.
269 */
270
271 pvos = lws_vhost_protocol_options(wsi->vhost, wsi->protocol->name);
272 if (pvos && pvos->options &&
273 !lws_pvo_get_str((void *)pvos->options, "basic-auth",
274 &ws_prot_basic_auth)) {
275 lwsl_info("%s: ws upgrade requires basic auth\n", __func__);
276 switch (lws_check_basic_auth(wsi, ws_prot_basic_auth, LWSAUTHM_DEFAULT
277 /* no callback based auth here */)) {
278 case LCBA_CONTINUE:
279 break;
280 case LCBA_FAILED_AUTH:
281 return lws_unauthorised_basic_auth(wsi);
282 case LCBA_END_TRANSACTION:
283 lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
284 return lws_http_transaction_completed(wsi);
285 }
286 }
287 #endif
288
289 /*
290 * We are upgrading to ws, so http/1.1 + h2 and keepalive + pipelined
291 * header considerations about keeping the ah around no longer apply.
292 *
293 * However it's common for the first ws protocol data to have been
294 * coalesced with the browser upgrade request and to already be in the
295 * ah rx buffer.
296 */
297
298 lws_pt_lock(pt, __func__);
299
300 if (!wsi->h2_stream_carries_ws)
301 lws_role_transition(wsi, LWSIFR_SERVER, LRS_ESTABLISHED,
302 &role_ops_ws);
303
304 lws_pt_unlock(pt);
305
306 /* allocate the ws struct for the wsi */
307
308 wsi->ws = lws_zalloc(sizeof(*wsi->ws), "ws struct");
309 if (!wsi->ws) {
310 lwsl_notice("OOM\n");
311 return 1;
312 }
313
314 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
315 wsi->ws->ietf_spec_revision =
316 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
317
318 /* allocate wsi->user storage */
319 if (lws_ensure_user_space(wsi)) {
320 lwsl_notice("problem with user space\n");
321 return 1;
322 }
323
324 /*
325 * Give the user code a chance to study the request and
326 * have the opportunity to deny it
327 */
328 if ((wsi->protocol->callback)(wsi,
329 LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
330 wsi->user_space,
331 lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
332 lwsl_warn("User code denied connection\n");
333 return 1;
334 }
335
336 /*
337 * Perform the handshake according to the protocol version the
338 * client announced
339 */
340
341 switch (wsi->ws->ietf_spec_revision) {
342 default:
343 lwsl_notice("Unknown client spec version %d\n",
344 wsi->ws->ietf_spec_revision);
345 wsi->ws->ietf_spec_revision = 13;
346 //return 1;
347 /* fallthru */
348 case 13:
349 #if defined(LWS_WITH_HTTP2)
350 if (wsi->h2_stream_carries_ws) {
351 if (lws_h2_ws_handshake(wsi)) {
352 lwsl_notice("h2 ws handshake failed\n");
353 return 1;
354 }
355 lws_role_transition(wsi,
356 LWSIFR_SERVER | LWSIFR_P_ENCAP_H2,
357 LRS_ESTABLISHED, &role_ops_ws);
358
359 /*
360 * There should be no validity checking since we
361 * are encapsulated in something else with its own
362 * validity checking
363 */
364
365 __lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_validity,
366 LWS_SET_TIMER_USEC_CANCEL);
367 } else
368 #endif
369 {
370 lwsl_parser("lws_parse calling handshake_04\n");
371 if (handshake_0405(wsi->context, wsi)) {
372 lwsl_notice("hs0405 has failed the connection\n");
373 return 1;
374 }
375 }
376 break;
377 }
378
379 lws_server_init_wsi_for_ws(wsi);
380 lwsl_parser("accepted v%02d connection\n", wsi->ws->ietf_spec_revision);
381
382 #if defined(LWS_WITH_ACCESS_LOG)
383 {
384 char *uptr = "unknown method", combo[128], dotstar[64];
385 int l = 14, meth = lws_http_get_uri_and_method(wsi, &uptr, &l);
386
387 if (wsi->h2_stream_carries_ws)
388 wsi->http.request_version = HTTP_VERSION_2;
389
390 wsi->http.access_log.response = 101;
391
392 lws_strnncpy(dotstar, uptr, l, sizeof(dotstar));
393 l = lws_snprintf(combo, sizeof(combo), "%s (%s)", dotstar,
394 wsi->protocol->name);
395
396 if (meth < 0)
397 meth = 0;
398 lws_prepare_access_log_info(wsi, combo, l, meth);
399 lws_access_log(wsi);
400 }
401 #endif
402
403 lwsl_info("%s: %p: dropping ah on ws upgrade\n", __func__, wsi);
404 lws_header_table_detach(wsi, 1);
405
406 return 0;
407 }
408
409 int
lws_process_ws_upgrade(struct lws * wsi)410 lws_process_ws_upgrade(struct lws *wsi)
411 {
412 const struct lws_protocols *pcol = NULL;
413 char buf[128], name[64];
414 struct lws_tokenize ts;
415 lws_tokenize_elem e;
416 int n;
417
418 if (!wsi->protocol)
419 lwsl_err("NULL protocol at lws_read\n");
420
421 /*
422 * It's either websocket or h2->websocket
423 *
424 * If we are on h1, confirm we got the required "connection: upgrade"
425 * header. h2 / ws-over-h2 does not have this.
426 */
427
428 #if defined(LWS_WITH_HTTP2)
429 if (!wsi->mux_substream) {
430 #endif
431
432 lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |
433 LWS_TOKENIZE_F_DOT_NONTERM |
434 LWS_TOKENIZE_F_RFC7230_DELIMS |
435 LWS_TOKENIZE_F_MINUS_NONTERM);
436 n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_CONNECTION);
437 if (n <= 0)
438 goto bad_conn_format;
439 ts.len = n;
440
441 do {
442 e = lws_tokenize(&ts);
443 switch (e) {
444 case LWS_TOKZE_TOKEN:
445 if (!strncasecmp(ts.token, "upgrade", ts.token_len))
446 e = LWS_TOKZE_ENDED;
447 break;
448
449 case LWS_TOKZE_DELIMITER:
450 break;
451
452 default: /* includes ENDED */
453 bad_conn_format:
454 lwsl_err("%s: malformed or absent conn hdr\n",
455 __func__);
456
457 return 1;
458 }
459 } while (e > 0);
460
461 #if defined(LWS_WITH_HTTP2)
462 }
463 #endif
464
465 #if defined(LWS_WITH_HTTP_PROXY)
466 {
467 const struct lws_http_mount *hit;
468 int uri_len = 0, meth;
469 char *uri_ptr;
470
471 meth = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len);
472 hit = lws_find_mount(wsi, uri_ptr, uri_len);
473
474 if (hit && (meth == LWSHUMETH_GET ||
475 meth == LWSHUMETH_CONNECT ||
476 meth == LWSHUMETH_COLON_PATH) &&
477 (hit->origin_protocol == LWSMPRO_HTTPS ||
478 hit->origin_protocol == LWSMPRO_HTTP))
479 /*
480 * We are an h1 ws upgrade on a urlpath that corresponds
481 * to a proxying mount. Don't try to deal with it
482 * locally, eg, we won't even have the right protocol
483 * handler since we're not the guy handling it, just a
484 * conduit.
485 *
486 * Instead open the related ongoing h1 connection
487 * according to the mount configuration and proxy
488 * whatever that has to say from now on.
489 */
490 return lws_http_proxy_start(wsi, hit, uri_ptr, 1);
491 }
492 #endif
493
494 /*
495 * Select the first protocol we support from the list
496 * the client sent us.
497 */
498
499 lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |
500 LWS_TOKENIZE_F_MINUS_NONTERM |
501 LWS_TOKENIZE_F_DOT_NONTERM |
502 LWS_TOKENIZE_F_RFC7230_DELIMS);
503 n = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_PROTOCOL);
504 if (n < 0) {
505 lwsl_err("%s: protocol list too long\n", __func__);
506 return 1;
507 }
508 ts.len = n;
509 if (!ts.len) {
510 int n = wsi->vhost->default_protocol_index;
511 /*
512 * Some clients only have one protocol and do not send the
513 * protocol list header... allow it and match to the vhost's
514 * default protocol (which itself defaults to zero).
515 *
516 * Setting the vhost default protocol index to -1 or anything
517 * more than the actual number of protocols on the vhost causes
518 * these "no protocol" ws connections to be rejected.
519 */
520
521 if (n >= wsi->vhost->count_protocols) {
522 lwsl_notice("%s: rejecting ws upg with no protocol\n",
523 __func__);
524
525 return 1;
526 }
527
528 lwsl_info("%s: defaulting to prot handler %d\n", __func__, n);
529
530 lws_bind_protocol(wsi, &wsi->vhost->protocols[n],
531 "ws upgrade default pcol");
532
533 goto alloc_ws;
534 }
535
536 /* otherwise go through the user-provided protocol list */
537
538 do {
539 e = lws_tokenize(&ts);
540 switch (e) {
541 case LWS_TOKZE_TOKEN:
542
543 if (lws_tokenize_cstr(&ts, name, sizeof(name))) {
544 lwsl_err("%s: pcol name too long\n", __func__);
545
546 return 1;
547 }
548 lwsl_debug("checking %s\n", name);
549 pcol = lws_vhost_name_to_protocol(wsi->vhost, name);
550 if (pcol) {
551 /* if we know it, bind to it and stop looking */
552 lws_bind_protocol(wsi, pcol, "ws upg pcol");
553 e = LWS_TOKZE_ENDED;
554 }
555 break;
556
557 case LWS_TOKZE_DELIMITER:
558 case LWS_TOKZE_ENDED:
559 break;
560
561 default:
562 lwsl_err("%s: malformatted protocol list", __func__);
563
564 return 1;
565 }
566 } while (e > 0);
567
568 /* we didn't find a protocol he wanted? */
569
570 if (!pcol) {
571 lwsl_notice("No supported protocol \"%s\"\n", buf);
572
573 return 1;
574 }
575
576 alloc_ws:
577
578 return lws_process_ws_upgrade2(wsi);
579 }
580
581 int
handshake_0405(struct lws_context * context,struct lws * wsi)582 handshake_0405(struct lws_context *context, struct lws *wsi)
583 {
584 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
585 struct lws_process_html_args args;
586 unsigned char hash[20];
587 int n, accept_len;
588 char *response;
589 char *p;
590
591 if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||
592 !lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {
593 lwsl_info("handshake_04 missing pieces\n");
594 /* completed header processing, but missing some bits */
595 goto bail;
596 }
597
598 if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >=
599 MAX_WEBSOCKET_04_KEY_LEN) {
600 lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN);
601 goto bail;
602 }
603
604 /*
605 * since key length is restricted above (currently 128), cannot
606 * overflow
607 */
608 n = sprintf((char *)pt->serv_buf,
609 "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
610 lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
611
612 lws_SHA1(pt->serv_buf, n, hash);
613
614 accept_len = lws_b64_encode_string((char *)hash, 20,
615 (char *)pt->serv_buf, context->pt_serv_buf_size);
616 if (accept_len < 0) {
617 lwsl_warn("Base64 encoded hash too long\n");
618 goto bail;
619 }
620
621 /* allocate the per-connection user memory (if any) */
622 if (lws_ensure_user_space(wsi))
623 goto bail;
624
625 /* create the response packet */
626
627 /* make a buffer big enough for everything */
628
629 response = (char *)pt->serv_buf + MAX_WEBSOCKET_04_KEY_LEN +
630 256 + LWS_PRE;
631 p = response;
632 LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
633 "Upgrade: WebSocket\x0d\x0a"
634 "Connection: Upgrade\x0d\x0a"
635 "Sec-WebSocket-Accept: ");
636 strcpy(p, (char *)pt->serv_buf);
637 p += accept_len;
638
639 /* we can only return the protocol header if:
640 * - one came in, and ... */
641 if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) &&
642 /* - it is not an empty string */
643 wsi->protocol->name &&
644 wsi->protocol->name[0]) {
645 const char *prot = wsi->protocol->name;
646
647 #if defined(LWS_WITH_HTTP_PROXY)
648 if (wsi->proxied_ws_parent && wsi->child_list)
649 prot = wsi->child_list->ws->actual_protocol;
650 #endif
651
652 LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
653 p += lws_snprintf(p, 128, "%s", prot);
654 }
655
656 #if !defined(LWS_WITHOUT_EXTENSIONS)
657 /*
658 * Figure out which extensions the client has that we want to
659 * enable on this connection, and give him back the list.
660 *
661 * Give him a limited write bugdet
662 */
663 if (lws_extension_server_handshake(wsi, &p, 192))
664 goto bail;
665 #endif
666 LWS_CPYAPP(p, "\x0d\x0a");
667
668 args.p = p;
669 args.max_len = lws_ptr_diff((char *)pt->serv_buf +
670 context->pt_serv_buf_size, p);
671 if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
672 LWS_CALLBACK_ADD_HEADERS,
673 wsi->user_space, &args, 0))
674 goto bail;
675
676 p = args.p;
677
678 /* end of response packet */
679
680 LWS_CPYAPP(p, "\x0d\x0a");
681
682 /* okay send the handshake response accepting the connection */
683
684 lwsl_parser("issuing resp pkt %d len\n",
685 lws_ptr_diff(p, response));
686 #if defined(DEBUG)
687 fwrite(response, 1, p - response, stderr);
688 #endif
689 n = lws_write(wsi, (unsigned char *)response, p - response,
690 LWS_WRITE_HTTP_HEADERS);
691 if (n != (p - response)) {
692 lwsl_info("%s: ERROR writing to socket %d\n", __func__, n);
693 goto bail;
694 }
695
696 /* alright clean up and set ourselves into established state */
697
698 lwsi_set_state(wsi, LRS_ESTABLISHED);
699 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
700
701 {
702 const char * uri_ptr =
703 lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
704 int uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
705 const struct lws_http_mount *hit =
706 lws_find_mount(wsi, uri_ptr, uri_len);
707 if (hit && hit->cgienv &&
708 wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO,
709 wsi->user_space, (void *)hit->cgienv, 0))
710 return 1;
711 }
712
713 return 0;
714
715 bail:
716 /* caller will free up his parsing allocations */
717 return -1;
718 }
719
720
721
722 /*
723 * Once we reach LWS_RXPS_WS_FRAME_PAYLOAD, we know how much
724 * to expect in that state and can deal with it in bulk more efficiently.
725 */
726
727 static int
lws_ws_frame_rest_is_payload(struct lws * wsi,uint8_t ** buf,size_t len)728 lws_ws_frame_rest_is_payload(struct lws *wsi, uint8_t **buf, size_t len)
729 {
730 struct lws_ext_pm_deflate_rx_ebufs pmdrx;
731 unsigned int avail = (unsigned int)len;
732 uint8_t *buffer = *buf, mask[4];
733 #if !defined(LWS_WITHOUT_EXTENSIONS)
734 unsigned int old_packet_length = (int)wsi->ws->rx_packet_length;
735 #endif
736 int n = 0;
737
738 /*
739 * With zlib, we can give it as much input as we like. The pmd
740 * extension will draw it down in chunks (default 1024).
741 *
742 * If we try to restrict how much we give it, because we must go
743 * back to the event loop each time, we will drop the remainder...
744 */
745
746 #if !defined(LWS_WITHOUT_EXTENSIONS)
747 if (!wsi->ws->count_act_ext)
748 #endif
749 {
750 if (wsi->protocol->rx_buffer_size)
751 avail = (int)wsi->protocol->rx_buffer_size;
752 else
753 avail = wsi->context->pt_serv_buf_size;
754 }
755
756 /* do not consume more than we should */
757 if (avail > wsi->ws->rx_packet_length)
758 avail = (unsigned int)wsi->ws->rx_packet_length;
759
760 /* do not consume more than what is in the buffer */
761 if (avail > len)
762 avail = (unsigned int)len;
763
764 if (!avail)
765 return 0;
766
767 pmdrx.eb_in.token = buffer;
768 pmdrx.eb_in.len = avail;
769 pmdrx.eb_out.token = buffer;
770 pmdrx.eb_out.len = avail;
771
772 if (!wsi->ws->all_zero_nonce) {
773
774 for (n = 0; n < 4; n++)
775 mask[n] = wsi->ws->mask[(wsi->ws->mask_idx + n) & 3];
776
777 /* deal with 4-byte chunks using unwrapped loop */
778 n = avail >> 2;
779 while (n--) {
780 *(buffer) = *(buffer) ^ mask[0];
781 buffer++;
782 *(buffer) = *(buffer) ^ mask[1];
783 buffer++;
784 *(buffer) = *(buffer) ^ mask[2];
785 buffer++;
786 *(buffer) = *(buffer) ^ mask[3];
787 buffer++;
788 }
789 /* and the remaining bytes bytewise */
790 for (n = 0; n < (int)(avail & 3); n++) {
791 *(buffer) = *(buffer) ^ mask[n];
792 buffer++;
793 }
794
795 wsi->ws->mask_idx = (wsi->ws->mask_idx + avail) & 3;
796 }
797
798 lwsl_info("%s: using %d of raw input (total %d on offer)\n", __func__,
799 avail, (int)len);
800
801 (*buf) += avail;
802 len -= avail;
803 wsi->ws->rx_packet_length -= avail;
804
805 #if !defined(LWS_WITHOUT_EXTENSIONS)
806 n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &pmdrx, 0);
807 lwsl_info("%s: ext says %d / ebuf_out.len %d\n", __func__, n,
808 pmdrx.eb_out.len);
809
810 /*
811 * ebuf may be pointing somewhere completely different now,
812 * it's the output
813 */
814
815 if (n < 0) {
816 /*
817 * we may rely on this to get RX, just drop connection
818 */
819 lwsl_notice("%s: LWS_EXT_CB_PAYLOAD_RX blew out\n", __func__);
820 wsi->socket_is_permanently_unusable = 1;
821
822 return -1;
823 }
824
825 /*
826 * if we had an rx fragment right at the last compressed byte of the
827 * message, we can get a zero length inflated output, where no prior
828 * rx inflated output marked themselves with FIN, since there was
829 * raw ws payload still to drain at that time.
830 *
831 * Then we need to generate a zero length ws rx that can be understood
832 * as the message completion.
833 */
834
835 if (!pmdrx.eb_out.len && /* zero-length inflation output */
836 n == PMDR_EMPTY_FINAL && /* nothing to drain from the inflator */
837 old_packet_length && /* we gave the inflator new input */
838 !wsi->ws->rx_packet_length && /* raw ws packet payload all gone */
839 wsi->ws->final && /* the raw ws packet is a FIN guy */
840 wsi->protocol->callback &&
841 !wsi->wsistate_pre_close) {
842
843 lwsl_ext("%s: issuing zero length FIN pkt\n", __func__);
844
845 if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
846 LWS_CALLBACK_RECEIVE,
847 wsi->user_space, NULL, 0))
848 return -1;
849
850 return avail;
851 }
852
853 /*
854 * If doing permessage-deflate, above was the only way to get a zero
855 * length receive. Otherwise we're more willing.
856 */
857 if (wsi->ws->count_act_ext && !pmdrx.eb_out.len)
858 return avail;
859
860 if (n == PMDR_HAS_PENDING)
861 /* extension had more... main loop will come back */
862 lws_add_wsi_to_draining_ext_list(wsi);
863 else
864 lws_remove_wsi_from_draining_ext_list(wsi);
865 #endif
866
867 if (pmdrx.eb_out.len &&
868 wsi->ws->check_utf8 && !wsi->ws->defeat_check_utf8) {
869 if (lws_check_utf8(&wsi->ws->utf8,
870 pmdrx.eb_out.token,
871 pmdrx.eb_out.len)) {
872 lws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,
873 (uint8_t *)"bad utf8", 8);
874 goto utf8_fail;
875 }
876
877 /* we are ending partway through utf-8 character? */
878 if (!wsi->ws->rx_packet_length && wsi->ws->final &&
879 wsi->ws->utf8 && !n) {
880 lwsl_info("FINAL utf8 error\n");
881 lws_close_reason(wsi, LWS_CLOSE_STATUS_INVALID_PAYLOAD,
882 (uint8_t *)"partial utf8", 12);
883
884 utf8_fail:
885 lwsl_info("utf8 error\n");
886 lwsl_hexdump_info(pmdrx.eb_out.token, pmdrx.eb_out.len);
887
888 return -1;
889 }
890 }
891
892 if (wsi->protocol->callback && !wsi->wsistate_pre_close)
893 if (user_callback_handle_rxflow(wsi->protocol->callback, wsi,
894 LWS_CALLBACK_RECEIVE,
895 wsi->user_space,
896 pmdrx.eb_out.token,
897 pmdrx.eb_out.len))
898 return -1;
899
900 wsi->ws->first_fragment = 0;
901
902 #if !defined(LWS_WITHOUT_EXTENSIONS)
903 lwsl_info("%s: input used %d, output %d, rem len %d, rx_draining_ext %d\n",
904 __func__, avail, pmdrx.eb_out.len, (int)len,
905 wsi->ws->rx_draining_ext);
906 #endif
907
908 return avail; /* how much we used from the input */
909 }
910
911
912 int
lws_parse_ws(struct lws * wsi,unsigned char ** buf,size_t len)913 lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len)
914 {
915 unsigned char *bufin = *buf;
916 int m, bulk = 0;
917
918 lwsl_debug("%s: received %d byte packet\n", __func__, (int)len);
919
920 //lwsl_hexdump_notice(*buf, len);
921
922 /* let the rx protocol state machine have as much as it needs */
923
924 while (len) {
925 /*
926 * we were accepting input but now we stopped doing so
927 */
928 if (wsi->rxflow_bitmap) {
929 lwsl_info("%s: doing rxflow, caching %d\n", __func__,
930 (int)len);
931 /*
932 * Since we cached the remaining available input, we
933 * can say we "consumed" it.
934 *
935 * But what about the case where the available input
936 * came out of the rxflow cache already? If we are
937 * effectively "putting it back in the cache", we have
938 * leave it where it is, already pointed to by the head.
939 */
940 if (lws_rxflow_cache(wsi, *buf, 0, (int)len) ==
941 LWSRXFC_TRIMMED) {
942 /*
943 * We dealt with it by trimming the existing
944 * rxflow cache HEAD to account for what we used.
945 *
946 * indicate we didn't use anything to the caller
947 * so he doesn't do any consumed processing
948 */
949 lwsl_info("%s: trimming inside rxflow cache\n",
950 __func__);
951 *buf = bufin;
952 } else
953 *buf += len;
954
955 return 1;
956 }
957 #if !defined(LWS_WITHOUT_EXTENSIONS)
958 if (wsi->ws->rx_draining_ext) {
959 lwsl_debug("%s: draining rx ext\n", __func__);
960 m = lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR, 0);
961 if (m < 0)
962 return -1;
963 continue;
964 }
965 #endif
966
967 /* consume payload bytes efficiently */
968 while (wsi->lws_rx_parse_state == LWS_RXPS_WS_FRAME_PAYLOAD &&
969 (wsi->ws->opcode == LWSWSOPC_TEXT_FRAME ||
970 wsi->ws->opcode == LWSWSOPC_BINARY_FRAME ||
971 wsi->ws->opcode == LWSWSOPC_CONTINUATION) &&
972 len) {
973 uint8_t *bin = *buf;
974
975 bulk = 1;
976 m = lws_ws_frame_rest_is_payload(wsi, buf, len);
977 assert((int)lws_ptr_diff(*buf, bin) <= (int)len);
978 len -= lws_ptr_diff(*buf, bin);
979
980 if (!m) {
981
982 break;
983 }
984 if (m < 0) {
985 lwsl_info("%s: rest_is_payload bailed\n",
986 __func__);
987 return -1;
988 }
989 }
990
991 if (!bulk) {
992 /* process the byte */
993 m = lws_ws_rx_sm(wsi, 0, *(*buf)++);
994 len--;
995 } else {
996 /*
997 * We already handled this byte in bulk, just deal
998 * with the ramifications
999 */
1000 #if !defined(LWS_WITHOUT_EXTENSIONS)
1001 lwsl_debug("%s: coming out of bulk with len %d, "
1002 "wsi->ws->rx_draining_ext %d\n",
1003 __func__, (int)len,
1004 wsi->ws->rx_draining_ext);
1005 #endif
1006 m = lws_ws_rx_sm(wsi, ALREADY_PROCESSED_IGNORE_CHAR |
1007 ALREADY_PROCESSED_NO_CB, 0);
1008 }
1009
1010 if (m < 0) {
1011 lwsl_info("%s: lws_ws_rx_sm bailed %d\n", __func__,
1012 bulk);
1013
1014 return -1;
1015 }
1016
1017 bulk = 0;
1018 }
1019
1020 lwsl_debug("%s: exit with %d unused\n", __func__, (int)len);
1021
1022 return 0;
1023 }
1024