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