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 * These are the standardized defaults.
29 * Override what actually goes in the vhost settings in platform or user code.
30 * Leave these alone because they are used to determine "what is different
31 * from the protocol defaults".
32 */
33 const struct http2_settings lws_h2_defaults = { {
34 1,
35 /* H2SET_HEADER_TABLE_SIZE */ 4096,
36 /* *** This controls how many entries in the dynamic table ***
37 * Allows the sender to inform the remote endpoint of the maximum
38 * size of the header compression table used to decode header
39 * blocks, in octets. The encoder can select any size equal to or
40 * less than this value by using signaling specific to the header
41 * compression format inside a header block (see [COMPRESSION]).
42 * The initial value is 4,096 octets.
43 */
44 /* H2SET_ENABLE_PUSH */ 1,
45 /* H2SET_MAX_CONCURRENT_STREAMS */ 0x7fffffff,
46 /* H2SET_INITIAL_WINDOW_SIZE */ 65535,
47 /* H2SET_MAX_FRAME_SIZE */ 16384,
48 /* H2SET_MAX_HEADER_LIST_SIZE */ 0x7fffffff,
49 /*< This advisory setting informs a peer of the maximum size of
50 * header list that the sender is prepared to accept, in octets.
51 * The value is based on the uncompressed size of header fields,
52 * including the length of the name and value in octets plus an
53 * overhead of 32 octets for each header field.
54 */
55 /* H2SET_RESERVED7 */ 0,
56 /* H2SET_ENABLE_CONNECT_PROTOCOL */ 0,
57 }};
58
59 /* these are the "lws defaults"... they can be overridden in plat */
60
61 const struct http2_settings lws_h2_stock_settings = { {
62 1,
63 /* H2SET_HEADER_TABLE_SIZE */ 65536, /* ffox */
64 /* *** This controls how many entries in the dynamic table ***
65 * Allows the sender to inform the remote endpoint of the maximum
66 * size of the header compression table used to decode header
67 * blocks, in octets. The encoder can select any size equal to or
68 * less than this value by using signaling specific to the header
69 * compression format inside a header block (see [COMPRESSION]).
70 * The initial value is 4,096 octets.
71 *
72 * Can't pass h2spec with less than 4096 here...
73 */
74 /* H2SET_ENABLE_PUSH */ 0,
75 /* H2SET_MAX_CONCURRENT_STREAMS */ 24,
76 /* H2SET_INITIAL_WINDOW_SIZE */ 0,
77 /*< This is managed by explicit WINDOW_UPDATE. Because otherwise no
78 * way to precisely control it when we do want to.
79 */
80 /* H2SET_MAX_FRAME_SIZE */ 16384,
81 /* H2SET_MAX_HEADER_LIST_SIZE */ 4096,
82 /*< This advisory setting informs a peer of the maximum size of
83 * header list that the sender is prepared to accept, in octets.
84 * The value is based on the uncompressed size of header fields,
85 * including the length of the name and value in octets plus an
86 * overhead of 32 octets for each header field.
87 */
88 /* H2SET_RESERVED7 */ 0,
89 /* H2SET_ENABLE_CONNECT_PROTOCOL */ 1,
90 }};
91
92 /*
93 * The wsi at this level is the network wsi
94 */
95
96 static int
rops_handle_POLLIN_h2(struct lws_context_per_thread * pt,struct lws * wsi,struct lws_pollfd * pollfd)97 rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi,
98 struct lws_pollfd *pollfd)
99 {
100 struct lws_tokens ebuf;
101 unsigned int pending = 0;
102 char buffered = 0;
103 struct lws *wsi1;
104 int n, m;
105
106 #ifdef LWS_WITH_CGI
107 if (wsi->http.cgi && (pollfd->revents & LWS_POLLOUT)) {
108 if (lws_handle_POLLOUT_event(wsi, pollfd))
109 return LWS_HPI_RET_PLEASE_CLOSE_ME;
110
111 return LWS_HPI_RET_HANDLED;
112 }
113 #endif
114
115 lwsl_info("%s: wsistate 0x%x, pollout %d\n", __func__,
116 (unsigned int)wsi->wsistate, pollfd->revents & LWS_POLLOUT);
117
118 /*
119 * something went wrong with parsing the handshake, and
120 * we ended up back in the event loop without completing it
121 */
122 if (lwsi_state(wsi) == LRS_PRE_WS_SERVING_ACCEPT) {
123 wsi->socket_is_permanently_unusable = 1;
124 return LWS_HPI_RET_PLEASE_CLOSE_ME;
125 }
126
127 if (lwsi_state(wsi) == LRS_WAITING_CONNECT) {
128 #if defined(LWS_WITH_CLIENT)
129 if ((pollfd->revents & LWS_POLLOUT) &&
130 lws_handle_POLLOUT_event(wsi, pollfd)) {
131 lwsl_debug("POLLOUT event closed it\n");
132 return LWS_HPI_RET_PLEASE_CLOSE_ME;
133 }
134
135 n = lws_client_socket_service(wsi, pollfd);
136 if (n)
137 return LWS_HPI_RET_WSI_ALREADY_DIED;
138 #endif
139 return LWS_HPI_RET_HANDLED;
140 }
141
142 /* 1: something requested a callback when it was OK to write */
143
144 if ((pollfd->revents & LWS_POLLOUT) &&
145 lwsi_state_can_handle_POLLOUT(wsi) &&
146 lws_handle_POLLOUT_event(wsi, pollfd)) {
147 if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
148 lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
149 /* the write failed... it's had it */
150 wsi->socket_is_permanently_unusable = 1;
151
152 return LWS_HPI_RET_PLEASE_CLOSE_ME;
153 }
154
155 if (lwsi_state(wsi) == LRS_RETURNED_CLOSE ||
156 lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE ||
157 lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) {
158 /*
159 * we stopped caring about anything except control
160 * packets. Force flow control off, defeat tx
161 * draining.
162 */
163 lws_rx_flow_control(wsi, 1);
164 #if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
165 if (wsi->ws)
166 wsi->ws->tx_draining_ext = 0;
167 #endif
168 }
169
170 if (wsi->mux_substream || wsi->upgraded_to_http2) {
171 wsi1 = lws_get_network_wsi(wsi);
172 if (wsi1 && lws_has_buffered_out(wsi1))
173 /*
174 * We cannot deal with any kind of new RX
175 * because we are dealing with a partial send
176 * (new RX may trigger new http_action() that
177 * expect to be able to send)
178 */
179 return LWS_HPI_RET_HANDLED;
180 }
181
182 read:
183 /* 3: network wsi buflist needs to be drained */
184
185 // lws_buflist_describe(&wsi->buflist, wsi, __func__);
186
187 ebuf.len = (int)lws_buflist_next_segment_len(&wsi->buflist,
188 &ebuf.token);
189 if (ebuf.len) {
190 lwsl_info("draining buflist (len %d)\n", ebuf.len);
191 buffered = 1;
192 goto drain;
193 }
194
195 if (!lws_ssl_pending(wsi) &&
196 !(pollfd->revents & pollfd->events & LWS_POLLIN))
197 return LWS_HPI_RET_HANDLED;
198
199 if (!(lwsi_role_client(wsi) &&
200 (lwsi_state(wsi) != LRS_ESTABLISHED &&
201 lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS))) {
202
203 ebuf.token = pt->serv_buf;
204 ebuf.len = lws_ssl_capable_read(wsi,
205 ebuf.token,
206 wsi->context->pt_serv_buf_size);
207 switch (ebuf.len) {
208 case 0:
209 lwsl_info("%s: zero length read\n", __func__);
210 return LWS_HPI_RET_PLEASE_CLOSE_ME;
211 case LWS_SSL_CAPABLE_MORE_SERVICE:
212 lwsl_info("SSL Capable more service\n");
213 return LWS_HPI_RET_HANDLED;
214 case LWS_SSL_CAPABLE_ERROR:
215 lwsl_info("%s: LWS_SSL_CAPABLE_ERROR\n", __func__);
216 return LWS_HPI_RET_PLEASE_CLOSE_ME;
217 }
218
219 // lwsl_notice("%s: Actual RX %d\n", __func__, ebuf.len);
220 // if (ebuf.len > 0)
221 // lwsl_hexdump_notice(ebuf.token, ebuf.len);
222 }
223
224 if (ebuf.len < 0)
225 return LWS_HPI_RET_PLEASE_CLOSE_ME;
226
227 drain:
228 #if defined(LWS_WITH_CLIENT)
229 if (lwsi_role_http(wsi) && lwsi_role_client(wsi) &&
230 wsi->hdr_parsing_completed && !wsi->told_user_closed) {
231
232 /*
233 * In SSL mode we get POLLIN notification about
234 * encrypted data in.
235 *
236 * But that is not necessarily related to decrypted
237 * data out becoming available; in may need to perform
238 * other in or out before that happens.
239 *
240 * simply mark ourselves as having readable data
241 * and turn off our POLLIN
242 */
243 wsi->client_rx_avail = 1;
244 if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
245 return LWS_HPI_RET_PLEASE_CLOSE_ME;
246
247 /* let user code know, he'll usually ask for writeable
248 * callback and drain / re-enable it there
249 */
250 if (user_callback_handle_rxflow(
251 wsi->protocol->callback,
252 wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
253 wsi->user_space, NULL, 0)) {
254 lwsl_info("RECEIVE_CLIENT_HTTP closed it\n");
255 return LWS_HPI_RET_PLEASE_CLOSE_ME;
256 }
257
258 return LWS_HPI_RET_HANDLED;
259 }
260 #endif
261
262 /* service incoming data */
263
264 if (ebuf.len) {
265 n = 0;
266 if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY &&
267 lwsi_state(wsi) != LRS_DISCARD_BODY)
268 n = lws_read_h2(wsi, ebuf.token, ebuf.len);
269 else
270 n = lws_read_h1(wsi, ebuf.token, ebuf.len);
271
272 if (n < 0) {
273 /* we closed wsi */
274 return LWS_HPI_RET_WSI_ALREADY_DIED;
275 }
276
277 if (n && buffered) {
278 // lwsl_notice("%s: h2 use %d\n", __func__, n);
279 m = (int)lws_buflist_use_segment(&wsi->buflist, (size_t)n);
280 lwsl_info("%s: draining rxflow: used %d, next %d\n",
281 __func__, n, m);
282 if (!m) {
283 lwsl_notice("%s: removed %p from dll_buflist\n",
284 __func__, wsi);
285 lws_dll2_remove(&wsi->dll_buflist);
286 }
287 } else
288 if (n && n != ebuf.len) {
289 // lwsl_notice("%s: h2 append seg %d\n", __func__, ebuf.len - n);
290 m = lws_buflist_append_segment(&wsi->buflist,
291 ebuf.token + n,
292 ebuf.len - n);
293 if (m < 0)
294 return LWS_HPI_RET_PLEASE_CLOSE_ME;
295 if (m) {
296 lwsl_debug("%s: added %p to rxflow list\n",
297 __func__, wsi);
298 if (lws_dll2_is_detached(&wsi->dll_buflist))
299 lws_dll2_add_head(&wsi->dll_buflist,
300 &pt->dll_buflist_owner);
301 }
302 }
303 }
304
305 // lws_buflist_describe(&wsi->buflist, wsi, __func__);
306
307 #if 0
308
309 /*
310 * This seems to be too aggressive... we don't want the ah stuck
311 * there but eg, WINDOW_UPDATE may come and detach it if we leave
312 * it like that... it will get detached at stream close
313 */
314
315 if (wsi->http.ah
316 #if defined(LWS_WITH_CLIENT)
317 && !wsi->client_h2_alpn
318 #endif
319 ) {
320 lwsl_err("xxx\n");
321
322 lws_header_table_detach(wsi, 0);
323 }
324 #endif
325
326 pending = lws_ssl_pending(wsi);
327 if (pending) {
328 // lwsl_info("going around\n");
329 goto read;
330 }
331
332 return LWS_HPI_RET_HANDLED;
333 }
334
rops_handle_POLLOUT_h2(struct lws * wsi)335 int rops_handle_POLLOUT_h2(struct lws *wsi)
336 {
337 // lwsl_notice("%s\n", __func__);
338
339 if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY)
340 return LWS_HP_RET_USER_SERVICE;
341
342 /*
343 * Priority 1: H2 protocol packets
344 */
345 if ((wsi->upgraded_to_http2
346 #if defined(LWS_WITH_CLIENT)
347 || wsi->client_h2_alpn
348 #endif
349 ) && wsi->h2.h2n->pps) {
350 lwsl_info("servicing pps\n");
351 /*
352 * this is called on the network connection, but may close
353 * substreams... that may affect callers
354 */
355 if (lws_h2_do_pps_send(wsi)) {
356 wsi->socket_is_permanently_unusable = 1;
357 return LWS_HP_RET_BAIL_DIE;
358 }
359 if (wsi->h2.h2n->pps)
360 return LWS_HP_RET_BAIL_OK;
361
362 /* we can resume whatever we were doing */
363 lws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_ENABLE |
364 LWS_RXFLOW_REASON_H2_PPS_PENDING);
365
366 return LWS_HP_RET_BAIL_OK; /* leave POLLOUT active */
367 }
368
369 /* Priority 2: if we are closing, not allowed to send more data frags
370 * which means user callback or tx ext flush banned now
371 */
372 if (lwsi_state(wsi) == LRS_RETURNED_CLOSE)
373 return LWS_HP_RET_USER_SERVICE;
374
375 return LWS_HP_RET_USER_SERVICE;
376 }
377
378 static int
rops_write_role_protocol_h2(struct lws * wsi,unsigned char * buf,size_t len,enum lws_write_protocol * wp)379 rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len,
380 enum lws_write_protocol *wp)
381 {
382 unsigned char flags = 0, base = (*wp) & 0x1f;
383 size_t olen = len;
384 int n;
385 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
386 unsigned char mtubuf[4096 + LWS_PRE];
387 #endif
388
389 /* if not in a state to send stuff, then just send nothing */
390
391 if (!lwsi_role_ws(wsi) && !wsi->mux_stream_immortal &&
392 base != LWS_WRITE_HTTP &&
393 base != LWS_WRITE_HTTP_FINAL &&
394 base != LWS_WRITE_HTTP_HEADERS_CONTINUATION &&
395 base != LWS_WRITE_HTTP_HEADERS && lwsi_state(wsi) != LRS_BODY &&
396 ((lwsi_state(wsi) != LRS_RETURNED_CLOSE &&
397 lwsi_state(wsi) != LRS_WAITING_TO_SEND_CLOSE &&
398 lwsi_state(wsi) != LRS_ESTABLISHED &&
399 lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK)
400 #if defined(LWS_ROLE_WS)
401 || base != LWS_WRITE_CLOSE
402 #endif
403 )) {
404 //assert(0);
405 lwsl_notice("%s: binning wsistate 0x%x %d: %s\n", __func__,
406 (unsigned int)wsi->wsistate, *wp, wsi->protocol ?
407 wsi->protocol->name : "no protocol");
408
409 return 0;
410 }
411
412 /* compression transform... */
413
414 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
415 if (wsi->http.lcs) {
416 unsigned char *out = mtubuf + LWS_PRE;
417 size_t o = sizeof(mtubuf) - LWS_PRE;
418
419 n = lws_http_compression_transform(wsi, buf, len, wp, &out, &o);
420 if (n)
421 return n;
422
423 lwsl_info("%s: %p: transformed %d bytes to %d "
424 "(wp 0x%x, more %d)\n", __func__,
425 wsi, (int)len, (int)o, (int)*wp,
426 wsi->http.comp_ctx.may_have_more);
427
428 buf = out;
429 len = o;
430 base = (*wp) & 0x1f;
431
432 if (!len)
433 return olen;
434 }
435 #endif
436
437 /*
438 * ws-over-h2 also ends up here after the ws framing applied
439 */
440
441 n = LWS_H2_FRAME_TYPE_DATA;
442 if (base == LWS_WRITE_HTTP_HEADERS) {
443 n = LWS_H2_FRAME_TYPE_HEADERS;
444 if (!((*wp) & LWS_WRITE_NO_FIN))
445 flags = LWS_H2_FLAG_END_HEADERS;
446 if (wsi->h2.send_END_STREAM ||
447 ((*wp) & LWS_WRITE_H2_STREAM_END)) {
448 flags |= LWS_H2_FLAG_END_STREAM;
449 wsi->h2.send_END_STREAM = 1;
450 }
451 }
452
453 if (base == LWS_WRITE_HTTP_HEADERS_CONTINUATION) {
454 n = LWS_H2_FRAME_TYPE_CONTINUATION;
455 if (!((*wp) & LWS_WRITE_NO_FIN))
456 flags = LWS_H2_FLAG_END_HEADERS;
457 if (wsi->h2.send_END_STREAM ||
458 ((*wp) & LWS_WRITE_H2_STREAM_END)) {
459 flags |= LWS_H2_FLAG_END_STREAM;
460 wsi->h2.send_END_STREAM = 1;
461 }
462 }
463
464 if ((base == LWS_WRITE_HTTP ||
465 base == LWS_WRITE_HTTP_FINAL) &&
466 wsi->http.tx_content_length) {
467 wsi->http.tx_content_remain -= len;
468 lwsl_info("%s: wsi %p: tx_content_rem = %llu\n", __func__, wsi,
469 (unsigned long long)wsi->http.tx_content_remain);
470 if (!wsi->http.tx_content_remain) {
471 lwsl_info("%s: selecting final write mode\n", __func__);
472 base = *wp = LWS_WRITE_HTTP_FINAL;
473 }
474 }
475
476 if (base == LWS_WRITE_HTTP_FINAL || ((*wp) & LWS_WRITE_H2_STREAM_END)) {
477 lwsl_info("%s: %p: setting END_STREAM\n", __func__, wsi);
478 flags |= LWS_H2_FLAG_END_STREAM;
479 wsi->h2.send_END_STREAM = 1;
480 }
481
482 n = lws_h2_frame_write(wsi, n, flags, wsi->mux.my_sid, (int)len, buf);
483 if (n < 0)
484 return n;
485
486 /* hide it may have been compressed... */
487
488 return (int)olen;
489 }
490
491 static int
rops_check_upgrades_h2(struct lws * wsi)492 rops_check_upgrades_h2(struct lws *wsi)
493 {
494 #if defined(LWS_ROLE_WS)
495 char *p;
496
497 /*
498 * with H2 there's also a way to upgrade a stream to something
499 * else... :method is CONNECT and :protocol says the name of
500 * the new protocol we want to carry. We have to have sent a
501 * SETTINGS saying that we support it though.
502 */
503 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
504 if (!wsi->vhost->h2.set.s[H2SET_ENABLE_CONNECT_PROTOCOL] ||
505 !wsi->mux_substream || !p || strcmp(p, "CONNECT"))
506 return LWS_UPG_RET_CONTINUE;
507
508 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_COLON_PROTOCOL);
509 if (!p || strcmp(p, "websocket"))
510 return LWS_UPG_RET_CONTINUE;
511
512 #if defined(LWS_WITH_SERVER_STATUS)
513 wsi->vhost->conn_stats.ws_upg++;
514 #endif
515 lwsl_info("Upgrade h2 to ws\n");
516 lws_mux_mark_immortal(wsi);
517 wsi->h2_stream_carries_ws = 1;
518
519 if (lws_process_ws_upgrade(wsi))
520 return LWS_UPG_RET_BAIL;
521
522 lwsl_info("Upgraded h2 to ws OK\n");
523
524 return LWS_UPG_RET_DONE;
525 #else
526 return LWS_UPG_RET_CONTINUE;
527 #endif
528 }
529
530 static int
rops_init_vhost_h2(struct lws_vhost * vh,const struct lws_context_creation_info * info)531 rops_init_vhost_h2(struct lws_vhost *vh,
532 const struct lws_context_creation_info *info)
533 {
534 vh->h2.set = vh->context->set;
535 if (info->http2_settings[0]) {
536 int n;
537
538 for (n = 1; n < LWS_H2_SETTINGS_LEN; n++)
539 vh->h2.set.s[n] = info->http2_settings[n];
540 }
541
542 return 0;
543 }
544
545 int
rops_pt_init_destroy_h2(struct lws_context * context,const struct lws_context_creation_info * info,struct lws_context_per_thread * pt,int destroy)546 rops_pt_init_destroy_h2(struct lws_context *context,
547 const struct lws_context_creation_info *info,
548 struct lws_context_per_thread *pt, int destroy)
549 {
550 context->set = lws_h2_stock_settings;
551
552 /*
553 * We only want to do this once... we will do it if we are built
554 * otherwise h1 ops will do it (or nobody if no http at all)
555 */
556 #if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
557 if (!destroy) {
558
559 pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
560
561 __lws_sul_insert(&pt->pt_sul_owner, &pt->sul_ah_lifecheck,
562 30 * LWS_US_PER_SEC);
563 } else
564 lws_dll2_remove(&pt->sul_ah_lifecheck.list);
565 #endif
566
567 return 0;
568 }
569
570
571 static int
rops_tx_credit_h2(struct lws * wsi,char peer_to_us,int add)572 rops_tx_credit_h2(struct lws *wsi, char peer_to_us, int add)
573 {
574 struct lws *nwsi = lws_get_network_wsi(wsi);
575 int n;
576
577 if (add) {
578 if (peer_to_us == LWSTXCR_PEER_TO_US) {
579 /*
580 * We want to tell the peer they can write an additional
581 * "add" bytes to us
582 */
583 return lws_h2_update_peer_txcredit(wsi, -1, add);
584 }
585
586 /*
587 * We're being told we can write an additional "add" bytes
588 * to the peer
589 */
590
591 wsi->txc.tx_cr += add;
592 nwsi->txc.tx_cr += add;
593
594 return 0;
595 }
596
597 if (peer_to_us == LWSTXCR_US_TO_PEER)
598 return lws_h2_tx_cr_get(wsi);
599
600 n = wsi->txc.peer_tx_cr_est;
601 if (n > nwsi->txc.peer_tx_cr_est)
602 n = nwsi->txc.peer_tx_cr_est;
603
604 return n;
605 }
606
607 static int
rops_destroy_role_h2(struct lws * wsi)608 rops_destroy_role_h2(struct lws *wsi)
609 {
610 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
611 struct allocated_headers *ah;
612
613 /* we may not have an ah, but may be on the waiting list... */
614 lwsl_info("%s: wsi %p: ah det due to close\n", __func__, wsi);
615 __lws_header_table_detach(wsi, 0);
616
617 ah = pt->http.ah_list;
618
619 while (ah) {
620 if (ah->in_use && ah->wsi == wsi) {
621 lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
622 ah->in_use = 0;
623 ah->wsi = NULL;
624 pt->http.ah_count_in_use--;
625 break;
626 }
627 ah = ah->next;
628 }
629
630 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
631 lws_http_compression_destroy(wsi);
632 #endif
633
634 if (wsi->upgraded_to_http2 || wsi->mux_substream) {
635 lws_hpack_destroy_dynamic_header(wsi);
636
637 if (wsi->h2.h2n)
638 lws_free_set_NULL(wsi->h2.h2n);
639 }
640
641 return 0;
642 }
643
644 static int
rops_close_kill_connection_h2(struct lws * wsi,enum lws_close_status reason)645 rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason)
646 {
647
648 #if defined(LWS_WITH_HTTP_PROXY)
649 if (wsi->http.proxy_clientside) {
650
651 wsi->http.proxy_clientside = 0;
652
653 if (user_callback_handle_rxflow(wsi->protocol->callback,
654 wsi,
655 LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
656 wsi->user_space, NULL, 0))
657 wsi->http.proxy_clientside = 0;
658 }
659 #endif
660
661 if (wsi->mux_substream && wsi->h2_stream_carries_ws)
662 lws_h2_rst_stream(wsi, 0, "none");
663 /* else
664 if (wsi->mux_substream)
665 lws_h2_rst_stream(wsi, H2_ERR_STREAM_CLOSED, "swsi got closed");
666 */
667
668 lwsl_info(" wsi: %p, his parent %p: siblings:\n", wsi, wsi->mux.parent_wsi);
669 lws_wsi_mux_dump_children(wsi);
670
671 if (wsi->upgraded_to_http2 || wsi->mux_substream
672 #if defined(LWS_WITH_CLIENT)
673 || wsi->client_mux_substream
674 #endif
675 ) {
676 lwsl_info("closing %p: parent %p\n", wsi, wsi->mux.parent_wsi);
677
678 if (wsi->mux.child_list && lwsl_visible(LLL_INFO)) {
679 lwsl_info(" parent %p: closing children: list:\n", wsi);
680 lws_wsi_mux_dump_children(wsi);
681 }
682 lws_wsi_mux_close_children(wsi, reason);
683 }
684
685 if (wsi->upgraded_to_http2) {
686 /* remove pps */
687 struct lws_h2_protocol_send *w = wsi->h2.h2n->pps, *w1;
688
689 while (w) {
690 w1 = w->next;
691 free(w);
692 w = w1;
693 }
694 wsi->h2.h2n->pps = NULL;
695 }
696
697 if ((
698 #if defined(LWS_WITH_CLIENT)
699 wsi->client_mux_substream ||
700 #endif
701 wsi->mux_substream) &&
702 wsi->mux.parent_wsi) {
703 lws_wsi_mux_sibling_disconnect(wsi);
704 if (wsi->h2.pending_status_body)
705 lws_free_set_NULL(wsi->h2.pending_status_body);
706 }
707
708 return 0;
709 }
710
711 static int
rops_callback_on_writable_h2(struct lws * wsi)712 rops_callback_on_writable_h2(struct lws *wsi)
713 {
714 #if defined(LWS_WITH_CLIENT)
715 struct lws *network_wsi;
716 #endif
717 int already;
718
719 // if (!lwsi_role_h2(wsi) && !lwsi_role_h2_ENCAPSULATION(wsi))
720 // return 0;
721
722 if (wsi->mux.requested_POLLOUT
723 #if defined(LWS_WITH_CLIENT)
724 && !wsi->client_h2_alpn
725 #endif
726 ) {
727 lwsl_debug("already pending writable\n");
728 // return 1;
729 }
730
731 /* is this for DATA or for control messages? */
732
733 if (wsi->upgraded_to_http2 && !wsi->h2.h2n->pps &&
734 lws_wsi_txc_check_skint(&wsi->txc, lws_h2_tx_cr_get(wsi))) {
735 /*
736 * refuse his efforts to get WRITABLE if we have no credit and
737 * no non-DATA pps to send
738 */
739 lwsl_err("%s: skint\n", __func__);
740 return 0;
741 }
742
743 #if defined(LWS_WITH_CLIENT)
744 network_wsi = lws_get_network_wsi(wsi);
745 #endif
746 already = lws_wsi_mux_mark_parents_needing_writeable(wsi);
747
748 /* for network action, act only on the network wsi */
749
750 if (already
751 #if defined(LWS_WITH_CLIENT)
752 && !network_wsi->client_h2_alpn
753 && !network_wsi->client_mux_substream
754 #endif
755 )
756 return 1;
757
758 return 0;
759 }
760
761 #if defined(LWS_WITH_SERVER)
762 static int
lws_h2_bind_for_post_before_action(struct lws * wsi)763 lws_h2_bind_for_post_before_action(struct lws *wsi)
764 {
765 const char *p;
766
767 p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
768 if (p && !strcmp(p, "POST")) {
769 const struct lws_http_mount *hit =
770 lws_find_mount(wsi,
771 lws_hdr_simple_ptr(wsi,
772 WSI_TOKEN_HTTP_COLON_PATH),
773 lws_hdr_total_length(wsi,
774 WSI_TOKEN_HTTP_COLON_PATH));
775
776 lwsl_debug("%s: %s: hit %p: %s\n", __func__,
777 lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH),
778 hit, hit ? hit->origin : "null");
779 if (hit) {
780 const struct lws_protocols *pp;
781 const char *name = hit->origin;
782
783 if (hit->protocol)
784 name = hit->protocol;
785
786 pp = lws_vhost_name_to_protocol(wsi->vhost, name);
787 if (!pp) {
788 lwsl_info("Unable to find protocol '%s'\n", name);
789 return 1;
790 }
791
792 if (lws_bind_protocol(wsi, pp, __func__))
793 return 1;
794 }
795
796 lwsl_info("%s: setting LRS_BODY from 0x%x (%s)\n", __func__,
797 (int)wsi->wsistate, wsi->protocol->name);
798 lwsi_set_state(wsi, LRS_BODY);
799 }
800
801 return 0;
802 }
803 #endif
804
805 /*
806 * we are the 'network wsi' for potentially many muxed child wsi with
807 * no network connection of their own, who have to use us for all their
808 * network actions. So we use a round-robin scheme to share out the
809 * POLLOUT notifications to our children.
810 *
811 * But because any child could exhaust the socket's ability to take
812 * writes, we can only let one child get notified each time.
813 *
814 * In addition children may be closed / deleted / added between POLLOUT
815 * notifications, so we can't hold pointers
816 */
817
818 static int
rops_perform_user_POLLOUT_h2(struct lws * wsi)819 rops_perform_user_POLLOUT_h2(struct lws *wsi)
820 {
821 struct lws **wsi2;
822 #if defined(LWS_ROLE_WS)
823 int write_type = LWS_WRITE_PONG;
824 #endif
825 int n;
826
827 wsi = lws_get_network_wsi(wsi);
828
829 wsi->mux.requested_POLLOUT = 0;
830 // if (!wsi->h2.initialized) {
831 // lwsl_info("pollout on uninitialized http2 conn\n");
832 // return 0;
833 // }
834
835 lws_wsi_mux_dump_waiting_children(wsi);
836
837 wsi2 = &wsi->mux.child_list;
838 if (!*wsi2)
839 return 0;
840
841 do {
842 struct lws *w, **wa;
843
844 wa = &(*wsi2)->mux.sibling_list;
845 if (!(*wsi2)->mux.requested_POLLOUT)
846 goto next_child;
847
848 /*
849 * we're going to do writable callback for this child.
850 * move him to be the last child
851 */
852
853 lwsl_debug("servicing child %p\n", *wsi2);
854
855 w = lws_wsi_mux_move_child_to_tail(wsi2);
856
857 if (!w) {
858 wa = &wsi->mux.child_list;
859 goto next_child;
860 }
861
862 lwsl_info("%s: child %p (wsistate 0x%x)\n", __func__, w,
863 (unsigned int)w->wsistate);
864
865 /* priority 1: post compression-transform buffered output */
866
867 if (lws_has_buffered_out(w)) {
868 lwsl_debug("%s: completing partial\n", __func__);
869 if (lws_issue_raw(w, NULL, 0) < 0) {
870 lwsl_info("%s signalling to close\n", __func__);
871 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
872 "h2 end stream 1");
873 wa = &wsi->mux.child_list;
874 goto next_child;
875 }
876 lws_callback_on_writable(w);
877 wa = &wsi->mux.child_list;
878 goto next_child;
879 }
880
881 /* priority 2: pre compression-transform buffered output */
882
883 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
884 if (w->http.comp_ctx.buflist_comp ||
885 w->http.comp_ctx.may_have_more) {
886 enum lws_write_protocol wp = LWS_WRITE_HTTP;
887
888 lwsl_info("%s: completing comp partial"
889 "(buflist_comp %p, may %d)\n",
890 __func__, w->http.comp_ctx.buflist_comp,
891 w->http.comp_ctx.may_have_more);
892
893 if (rops_write_role_protocol_h2(w, NULL, 0, &wp) < 0) {
894 lwsl_info("%s signalling to close\n", __func__);
895 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
896 "comp write fail");
897 }
898 lws_callback_on_writable(w);
899 wa = &wsi->mux.child_list;
900 goto next_child;
901 }
902 #endif
903
904 /* priority 3: if no buffered out and waiting for that... */
905
906 if (lwsi_state(w) == LRS_FLUSHING_BEFORE_CLOSE) {
907 w->socket_is_permanently_unusable = 1;
908 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
909 "h2 end stream 1");
910 wa = &wsi->mux.child_list;
911 goto next_child;
912 }
913
914 /* if we arrived here, even by looping, we checked choked */
915 w->could_have_pending = 0;
916 wsi->could_have_pending = 0;
917
918 if (w->h2.pending_status_body) {
919 w->h2.send_END_STREAM = 1;
920 n = lws_write(w, (uint8_t *)w->h2.pending_status_body +
921 LWS_PRE,
922 strlen(w->h2.pending_status_body +
923 LWS_PRE), LWS_WRITE_HTTP_FINAL);
924 lws_free_set_NULL(w->h2.pending_status_body);
925 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
926 "h2 end stream 1");
927 wa = &wsi->mux.child_list;
928 goto next_child;
929 }
930
931 #if defined(LWS_WITH_CLIENT)
932 if (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) {
933 if (lws_h2_client_handshake(w))
934 return -1;
935
936 goto next_child;
937 }
938 #endif
939
940 #if defined(LWS_WITH_SERVER)
941 if (lwsi_state(w) == LRS_DEFERRING_ACTION) {
942
943 /*
944 * we had to defer the http_action to the POLLOUT
945 * handler, because we know it will send something and
946 * only in the POLLOUT handler do we know for sure
947 * that there is no partial pending on the network wsi.
948 */
949
950 lwsi_set_state(w, LRS_ESTABLISHED);
951
952 lws_h2_bind_for_post_before_action(w);
953
954 lwsl_info(" h2 action start...\n");
955 n = lws_http_action(w);
956 if (n < 0)
957 lwsl_info (" h2 action result %d\n", n);
958 else
959 lwsl_info(" h2 action result %d "
960 "(wsi->http.rx_content_remain %lld)\n",
961 n, w->http.rx_content_remain);
962
963 /*
964 * Commonly we only managed to start a larger transfer
965 * that will complete asynchronously under its own wsi
966 * states. In those cases we will hear about
967 * END_STREAM going out in the POLLOUT handler.
968 */
969 if (n >= 0 && !w->h2.pending_status_body &&
970 (n || w->h2.send_END_STREAM)) {
971 lwsl_info("closing stream after h2 action\n");
972 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
973 "h2 end stream");
974 wa = &wsi->mux.child_list;
975 }
976
977 if (n < 0)
978 wa = &wsi->mux.child_list;
979
980 goto next_child;
981 }
982
983 #if defined(LWS_WITH_FILE_OPS)
984
985 if (lwsi_state(w) == LRS_ISSUING_FILE) {
986
987 if (lws_wsi_txc_check_skint(&w->txc,
988 lws_h2_tx_cr_get(w))) {
989 wa = &wsi->mux.child_list;
990 goto next_child;
991 }
992
993 ((volatile struct lws *)w)->leave_pollout_active = 0;
994
995 /* >0 == completion, <0 == error
996 *
997 * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION
998 * callback when it's done. That's the case even if we
999 * just completed the send, so wait for that.
1000 */
1001 n = lws_serve_http_file_fragment(w);
1002 lwsl_debug("lws_serve_http_file_fragment says %d\n", n);
1003
1004 /*
1005 * We will often hear about out having sent the final
1006 * DATA here... if so close the actual wsi
1007 */
1008 if (n < 0 || w->h2.send_END_STREAM) {
1009 lwsl_debug("Closing POLLOUT child %p\n", w);
1010 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1011 "h2 end stream file");
1012 wa = &wsi->mux.child_list;
1013 goto next_child;
1014 }
1015 if (n > 0)
1016 if (lws_http_transaction_completed(w))
1017 return -1;
1018 if (!n) {
1019 lws_callback_on_writable(w);
1020 (w)->mux.requested_POLLOUT = 1;
1021 }
1022
1023 goto next_child;
1024 }
1025 #endif
1026 #endif
1027
1028 #if defined(LWS_ROLE_WS)
1029
1030 /* Notify peer that we decided to close */
1031
1032 if (lwsi_role_ws(w) &&
1033 lwsi_state(w) == LRS_WAITING_TO_SEND_CLOSE) {
1034 lwsl_debug("sending close packet\n");
1035 w->waiting_to_send_close_frame = 0;
1036 n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE],
1037 w->ws->close_in_ping_buffer_len,
1038 LWS_WRITE_CLOSE);
1039 if (n >= 0) {
1040 lwsi_set_state(w, LRS_AWAITING_CLOSE_ACK);
1041 lws_set_timeout(w, PENDING_TIMEOUT_CLOSE_ACK, 5);
1042 lwsl_debug("sent close frame, awaiting ack\n");
1043 }
1044
1045 goto next_child;
1046 }
1047
1048 /*
1049 * Acknowledge receipt of peer's notification he closed,
1050 * then logically close ourself
1051 */
1052
1053 if ((lwsi_role_ws(w) && w->ws->ping_pending_flag) ||
1054 (lwsi_state(w) == LRS_RETURNED_CLOSE &&
1055 w->ws->payload_is_close)) {
1056
1057 if (w->ws->payload_is_close)
1058 write_type = LWS_WRITE_CLOSE |
1059 LWS_WRITE_H2_STREAM_END;
1060
1061 n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE],
1062 w->ws->ping_payload_len, write_type);
1063 if (n < 0)
1064 return -1;
1065
1066 /* well he is sent, mark him done */
1067 w->ws->ping_pending_flag = 0;
1068 if (w->ws->payload_is_close) {
1069 /* oh... a close frame... then we are done */
1070 lwsl_debug("Ack'd peer's close packet\n");
1071 w->ws->payload_is_close = 0;
1072 lwsi_set_state(w, LRS_RETURNED_CLOSE);
1073 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1074 "returned close packet");
1075 wa = &wsi->mux.child_list;
1076 goto next_child;
1077 }
1078
1079 lws_callback_on_writable(w);
1080 (w)->mux.requested_POLLOUT = 1;
1081
1082 /* otherwise for PING, leave POLLOUT active both ways */
1083 goto next_child;
1084 }
1085 #endif
1086
1087 /*
1088 * set client wsi to immortal long-poll mode; send END_STREAM
1089 * flag on headers to indicate to a server, that allows
1090 * it, that you want them to leave the stream in a long poll
1091 * ro immortal state. We have to send headers so the client
1092 * understands the http connection is ongoing.
1093 */
1094
1095 if (w->h2.send_END_STREAM && w->h2.long_poll) {
1096 uint8_t buf[LWS_PRE + 1];
1097 enum lws_write_protocol wp = 0;
1098
1099 if (!rops_write_role_protocol_h2(w, buf + LWS_PRE, 0,
1100 &wp)) {
1101 lwsl_info("%s: wsi %p: entering ro long poll\n",
1102 __func__, w);
1103 lws_mux_mark_immortal(w);
1104 } else
1105 lwsl_err("%s: wsi %p: failed to set long poll\n",
1106 __func__, w);
1107 goto next_child;
1108 }
1109
1110 if (lws_callback_as_writeable(w)) {
1111 lwsl_info("Closing POLLOUT child (end stream %d)\n",
1112 w->h2.send_END_STREAM);
1113 lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
1114 "h2 pollout handle");
1115 wa = &wsi->mux.child_list;
1116 } else
1117 if (w->h2.send_END_STREAM)
1118 lws_h2_state(w, LWS_H2_STATE_HALF_CLOSED_LOCAL);
1119
1120 next_child:
1121 wsi2 = wa;
1122 } while (wsi2 && *wsi2 && !lws_send_pipe_choked(wsi));
1123
1124 // lws_wsi_mux_dump_waiting_children(wsi);
1125
1126 if (lws_wsi_mux_action_pending_writeable_reqs(wsi))
1127 return -1;
1128
1129 return 0;
1130 }
1131
1132 static struct lws *
rops_encapsulation_parent_h2(struct lws * wsi)1133 rops_encapsulation_parent_h2(struct lws *wsi)
1134 {
1135 if (wsi->mux.parent_wsi)
1136 return wsi->mux.parent_wsi;
1137
1138 return NULL;
1139 }
1140
1141 static int
rops_alpn_negotiated_h2(struct lws * wsi,const char * alpn)1142 rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
1143 {
1144 struct allocated_headers *ah;
1145
1146 lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi));
1147 #if defined(LWS_WITH_CLIENT)
1148 if (lwsi_role_client(wsi)) {
1149 lwsl_info("%s: upgraded to H2\n", __func__);
1150 wsi->client_h2_alpn = 1;
1151 }
1152 #endif
1153
1154 wsi->upgraded_to_http2 = 1;
1155 #if defined(LWS_WITH_SERVER_STATUS)
1156 wsi->vhost->conn_stats.h2_alpn++;
1157 #endif
1158
1159 /* adopt the header info */
1160
1161 ah = wsi->http.ah;
1162
1163 lws_role_transition(wsi, LWSIFR_SERVER, LRS_H2_AWAIT_PREFACE,
1164 &role_ops_h2);
1165
1166 /* http2 union member has http union struct at start */
1167 wsi->http.ah = ah;
1168
1169 if (!wsi->h2.h2n)
1170 wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n");
1171 if (!wsi->h2.h2n)
1172 return 1;
1173
1174 lws_h2_init(wsi);
1175
1176 /* HTTP2 union */
1177
1178 lws_hpack_dynamic_size(wsi,
1179 wsi->h2.h2n->our_set.s[H2SET_HEADER_TABLE_SIZE]);
1180 wsi->txc.tx_cr = 65535;
1181
1182 lwsl_info("%s: wsi %p: configured for h2\n", __func__, wsi);
1183
1184 return 0;
1185 }
1186
1187 static int
rops_issue_keepalive_h2(struct lws * wsi,int isvalid)1188 rops_issue_keepalive_h2(struct lws *wsi, int isvalid)
1189 {
1190 struct lws *nwsi = lws_get_network_wsi(wsi);
1191 struct lws_h2_protocol_send *pps;
1192 uint64_t us = lws_now_usecs();
1193
1194 if (isvalid) {
1195 _lws_validity_confirmed_role(nwsi);
1196
1197 return 0;
1198 }
1199
1200 /*
1201 * We can only send these frames on the network connection itself...
1202 * we shouldn't be tracking validity on anything else
1203 */
1204
1205 assert(wsi == nwsi);
1206
1207 pps = lws_h2_new_pps(LWS_H2_PPS_PING);
1208 if (!pps)
1209 return 1;
1210
1211 /*
1212 * The peer is defined to copy us back the unchanged payload in another
1213 * PING frame this time with ACK set. So by sending that out with the
1214 * current time, it's an interesting opportunity to learn the effective
1215 * RTT on the link when the PONG comes in, plus or minus the time to
1216 * schedule the PPS.
1217 */
1218
1219 memcpy(pps->u.ping.ping_payload, &us, 8);
1220 lws_pps_schedule(nwsi, pps);
1221
1222 return 0;
1223 }
1224
1225 const struct lws_role_ops role_ops_h2 = {
1226 /* role name */ "h2",
1227 /* alpn id */ "h2",
1228 /* check_upgrades */ rops_check_upgrades_h2,
1229 /* pt_init_destroy */ rops_pt_init_destroy_h2,
1230 /* init_vhost */ rops_init_vhost_h2,
1231 /* destroy_vhost */ NULL,
1232 /* service_flag_pending */ NULL,
1233 /* handle_POLLIN */ rops_handle_POLLIN_h2,
1234 /* handle_POLLOUT */ rops_handle_POLLOUT_h2,
1235 /* perform_user_POLLOUT */ rops_perform_user_POLLOUT_h2,
1236 /* callback_on_writable */ rops_callback_on_writable_h2,
1237 /* tx_credit */ rops_tx_credit_h2,
1238 /* write_role_protocol */ rops_write_role_protocol_h2,
1239 /* encapsulation_parent */ rops_encapsulation_parent_h2,
1240 /* alpn_negotiated */ rops_alpn_negotiated_h2,
1241 /* close_via_role_protocol */ NULL,
1242 /* close_role */ NULL,
1243 /* close_kill_connection */ rops_close_kill_connection_h2,
1244 /* destroy_role */ rops_destroy_role_h2,
1245 /* adoption_bind */ NULL,
1246 /* client_bind */ NULL,
1247 /* issue_keepalive */ rops_issue_keepalive_h2,
1248 /* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
1249 LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
1250 /* rx cb clnt, srv */ { LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
1251 0 /* may be POST, etc */ },
1252 /* writeable cb clnt, srv */ { LWS_CALLBACK_CLIENT_HTTP_WRITEABLE,
1253 LWS_CALLBACK_HTTP_WRITEABLE },
1254 /* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
1255 LWS_CALLBACK_CLOSED_HTTP },
1256 /* protocol_bind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL,
1257 LWS_CALLBACK_HTTP_BIND_PROTOCOL },
1258 /* protocol_unbind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL,
1259 LWS_CALLBACK_HTTP_DROP_PROTOCOL },
1260 /* file_handle */ 0,
1261 };
1262