Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"", "gen_ut":1713871857, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets", "f":3, "items": [ {"schema":"libjg2-1", "cid":"e76fe5be1291ac9aa189bb2e5f60662e", "oid":{ "oid": "f28a45246e7ea479718ddba5e80deb355b23f5f3", "alias": [ "refs/heads/main"]},"blobname": "lib/roles/h2/http2.c", "blob": "/*\n * libwebsockets - small server side websockets and web server implementation\n *\n * Copyright (C) 2010 - 2019 Andy Green \u003candy@warmcat.com\u003e\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \u0022Software\u0022), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n#include \u0022private-lib-core.h\u0022\n\n/*\n * bitmap of control messages that are valid to receive for each http2 state\n */\n\nstatic const uint16_t http2_rx_validity[] \u003d {\n\t/* LWS_H2S_IDLE */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n//\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE)| /* ignore */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n\t/* LWS_H2S_RESERVED_LOCAL */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE),\n\t/* LWS_H2S_RESERVED_REMOTE */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY),\n\t/* LWS_H2S_OPEN */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_DATA) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PUSH_PROMISE) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PING) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_GOAWAY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n\t/* LWS_H2S_HALF_CLOSED_REMOTE */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM),\n\t/* LWS_H2S_HALF_CLOSED_LOCAL */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_DATA) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_HEADERS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PUSH_PROMISE) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PING) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_GOAWAY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_CONTINUATION),\n\t/* LWS_H2S_CLOSED */\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_SETTINGS) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_PRIORITY) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_WINDOW_UPDATE) |\n\t\t(1 \u003c\u003c LWS_H2_FRAME_TYPE_RST_STREAM),\n};\n\nstatic const char *preface \u003d \u0022PRI * HTTP/2.0\u005cx0d\u005cx0a\u005cx0d\u005cx0aSM\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022;\n\nstatic const char * const h2_state_names[] \u003d {\n\t\u0022LWS_H2S_IDLE\u0022,\n\t\u0022LWS_H2S_RESERVED_LOCAL\u0022,\n\t\u0022LWS_H2S_RESERVED_REMOTE\u0022,\n\t\u0022LWS_H2S_OPEN\u0022,\n\t\u0022LWS_H2S_HALF_CLOSED_REMOTE\u0022,\n\t\u0022LWS_H2S_HALF_CLOSED_LOCAL\u0022,\n\t\u0022LWS_H2S_CLOSED\u0022,\n};\n\n#if 0\nstatic const char * const h2_setting_names[] \u003d {\n\t\u0022\u0022,\n\t\u0022H2SET_HEADER_TABLE_SIZE\u0022,\n\t\u0022H2SET_ENABLE_PUSH\u0022,\n\t\u0022H2SET_MAX_CONCURRENT_STREAMS\u0022,\n\t\u0022H2SET_INITIAL_WINDOW_SIZE\u0022,\n\t\u0022H2SET_MAX_FRAME_SIZE\u0022,\n\t\u0022H2SET_MAX_HEADER_LIST_SIZE\u0022,\n\t\u0022reserved\u0022,\n\t\u0022H2SET_ENABLE_CONNECT_PROTOCOL\u0022\n};\n\nvoid\nlws_h2_dump_settings(struct http2_settings *set)\n{\n\tint n;\n\n\tfor (n \u003d 1; n \u003c H2SET_COUNT; n++)\n\t\tlwsl_notice(\u0022 %30s: %10d\u005cn\u0022, h2_setting_names[n], set-\u003es[n]);\n}\n#else\nvoid\nlws_h2_dump_settings(struct http2_settings *set)\n{\n}\n#endif\n\nstruct lws_h2_protocol_send *\nlws_h2_new_pps(enum lws_h2_protocol_send_type type)\n{\n\tstruct lws_h2_protocol_send *pps \u003d lws_malloc(sizeof(*pps), \u0022pps\u0022);\n\n\tif (pps)\n\t\tpps-\u003etype \u003d type;\n\n\treturn pps;\n}\n\nvoid lws_h2_init(struct lws *wsi)\n{\n\twsi-\u003eh2.h2n-\u003eour_set \u003d wsi-\u003ea.vhost-\u003eh2.set;\n\twsi-\u003eh2.h2n-\u003epeer_set \u003d lws_h2_defaults;\n}\n\nvoid\nlws_h2_state(struct lws *wsi, enum lws_h2_states s)\n{\n\tif (!wsi)\n\t\treturn;\n\tlwsl_info(\u0022%s: %s: state %s -\u003e %s\u005cn\u0022, __func__, lws_wsi_tag(wsi),\n\t\t\th2_state_names[wsi-\u003eh2.h2_state],\n\t\t\th2_state_names[s]);\n\t\t\n\t(void)h2_state_names;\n\twsi-\u003eh2.h2_state \u003d (uint8_t)s;\n}\n\nint\nlws_h2_update_peer_txcredit(struct lws *wsi, unsigned int sid, int bump)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\tstruct lws_h2_protocol_send *pps;\n\n\tassert(wsi);\n\n\tif (!bump)\n\t\treturn 0;\n\n\tif (sid \u003d\u003d (unsigned int)-1)\n\t\tsid \u003d wsi-\u003emux.my_sid;\n\n\tlwsl_info(\u0022%s: sid %d: bump %d -\u003e %d\u005cn\u0022, __func__, sid, bump,\n\t\t\t(int)wsi-\u003etxc.peer_tx_cr_est + bump);\n\n\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);\n\tif (!pps)\n\t\treturn 1;\n\n\tpps-\u003eu.update_window.sid \u003d (unsigned int)sid;\n\tpps-\u003eu.update_window.credit \u003d (unsigned int)bump;\n\twsi-\u003etxc.peer_tx_cr_est +\u003d bump;\n\n\tlws_wsi_txc_describe(\u0026wsi-\u003etxc, __func__, wsi-\u003emux.my_sid);\n\n\tlws_pps_schedule(wsi, pps);\n\n\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW);\n\tif (!pps)\n\t\treturn 1;\n\n\tpps-\u003eu.update_window.sid \u003d 0;\n\tpps-\u003eu.update_window.credit \u003d (unsigned int)bump;\n\tnwsi-\u003etxc.peer_tx_cr_est +\u003d bump;\n\n\tlws_wsi_txc_describe(\u0026nwsi-\u003etxc, __func__, nwsi-\u003emux.my_sid);\n\n\tlws_pps_schedule(nwsi, pps);\n\n\treturn 0;\n}\n\nint\nlws_h2_get_peer_txcredit_estimate(struct lws *wsi)\n{\n\tlws_wsi_txc_describe(\u0026wsi-\u003etxc, __func__, wsi-\u003emux.my_sid);\n\treturn (int)wsi-\u003etxc.peer_tx_cr_est;\n}\n\nstatic int\nlws_h2_update_peer_txcredit_thresh(struct lws *wsi, unsigned int sid, int threshold, int bump)\n{\n\tif (wsi-\u003etxc.peer_tx_cr_est \u003e threshold)\n\t\treturn 0;\n\n\treturn lws_h2_update_peer_txcredit(wsi, sid, bump);\n}\n\n/* cx + vh lock */\n\nstatic struct lws *\n__lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,\n\t\t unsigned int sid)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(parent_wsi);\n\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eh2.h2n;\n\tchar tmp[50], tmp1[50];\n\tunsigned int n, b \u003d 0;\n\tstruct lws *wsi;\n\tconst char *p;\n\n\tlws_context_assert_lock_held(vh-\u003econtext);\n\tlws_vhost_assert_lock_held(vh);\n\n\t/*\n\t * The identifier of a newly established stream MUST be numerically\n \t * greater than all streams that the initiating endpoint has opened or\n \t * reserved. This governs streams that are opened using a HEADERS frame\n \t * and streams that are reserved using PUSH_PROMISE. An endpoint that\n \t * receives an unexpected stream identifier MUST respond with a\n \t * connection error (Section 5.4.1) of type PROTOCOL_ERROR.\n\t */\n\tif (sid \u003c\u003d h2n-\u003ehighest_sid_opened) {\n\t\tlwsl_info(\u0022%s: tried to open lower sid %d (%d)\u005cn\u0022, __func__,\n\t\t\t\tsid, (int)h2n-\u003ehighest_sid_opened);\n\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, \u0022Bad sid\u0022);\n\t\treturn NULL;\n\t}\n\n\t/* no more children allowed by parent */\n\tif (parent_wsi-\u003emux.child_count + 1 \u003e\n\t parent_wsi-\u003eh2.h2n-\u003eour_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n\t\tlwsl_notice(\u0022reached concurrent stream limit\u005cn\u0022);\n\t\treturn NULL;\n\t}\n\n\tn \u003d 0;\n\tp \u003d \u0026parent_wsi-\u003elc.gutag[1];\n\tdo {\n\t\tif (*p \u003d\u003d '|') {\n\t\t\tb++;\n\t\t\tif (b \u003d\u003d 3)\n\t\t\t\tcontinue;\n\t\t}\n\t\ttmp1[n++] \u003d *p++;\n\t} while (b \u003c 3 \u0026\u0026 n \u003c sizeof(tmp1) - 2);\n\ttmp1[n] \u003d '\u005c0';\n\tlws_snprintf(tmp, sizeof(tmp), \u0022h2_sid%u_(%s)\u0022, sid, tmp1);\n\twsi \u003d lws_create_new_server_wsi(vh, parent_wsi-\u003etsi, LWSLCG_WSI_MUX, tmp);\n\tif (!wsi) {\n\t\tlwsl_notice(\u0022new server wsi failed (%s)\u005cn\u0022, lws_vh_tag(vh));\n\t\treturn NULL;\n\t}\n\n#if defined(LWS_WITH_SERVER)\n\tif (lwsi_role_server(parent_wsi)) {\n\t\tlws_metrics_caliper_bind(wsi-\u003ecal_conn, wsi-\u003ea.context-\u003emth_srv);\n\t}\n#endif\n\n\th2n-\u003ehighest_sid_opened \u003d sid;\n\n\tlws_wsi_mux_insert(wsi, parent_wsi, sid);\n\tif (sid \u003e\u003d h2n-\u003ehighest_sid)\n\t\th2n-\u003ehighest_sid \u003d sid + 2;\n\n\twsi-\u003emux_substream \u003d 1;\n\twsi-\u003eseen_nonpseudoheader \u003d 0;\n\n\twsi-\u003etxc.tx_cr \u003d (int32_t)nwsi-\u003eh2.h2n-\u003epeer_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\twsi-\u003etxc.peer_tx_cr_est \u003d\n\t\t\t(int32_t)nwsi-\u003eh2.h2n-\u003eour_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\n\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n\tlwsi_set_role(wsi, lwsi_role(parent_wsi));\n\n\twsi-\u003ea.protocol \u003d \u0026vh-\u003eprotocols[0];\n\tif (lws_ensure_user_space(wsi))\n\t\tgoto bail1;\n\n#if defined(LWS_WITH_SERVER) \u0026\u0026 defined(LWS_WITH_SECURE_STREAMS)\n\tif (lws_adopt_ss_server_accept(wsi))\n\t\tgoto bail1;\n#endif\n\n\t/* get the ball rolling */\n\tlws_validity_confirmed(wsi);\n\n\tlwsl_info(\u0022%s: %s new ch %s, sid %d, usersp\u003d%p\u005cn\u0022, __func__,\n\t\t lws_wsi_tag(parent_wsi), lws_wsi_tag(wsi), sid, wsi-\u003euser_space);\n\n\tlws_wsi_txc_describe(\u0026wsi-\u003etxc, __func__, wsi-\u003emux.my_sid);\n\tlws_wsi_txc_describe(\u0026nwsi-\u003etxc, __func__, 0);\n\n\treturn wsi;\n\nbail1:\n\t/* undo the insert */\n\tparent_wsi-\u003emux.child_list \u003d wsi-\u003emux.sibling_list;\n\tparent_wsi-\u003emux.child_count--;\n\n\tif (wsi-\u003euser_space)\n\t\tlws_free_set_NULL(wsi-\u003euser_space);\n\tvh-\u003eprotocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);\n\t__lws_vhost_unbind_wsi(wsi);\n\tlws_free(wsi);\n\n\treturn NULL;\n}\n\nstruct lws *\nlws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(parent_wsi);\n\n\t/* no more children allowed by parent */\n\tif (parent_wsi-\u003emux.child_count + 1 \u003e\n\t parent_wsi-\u003eh2.h2n-\u003eour_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n\t\tlwsl_notice(\u0022reached concurrent stream limit\u005cn\u0022);\n\t\treturn NULL;\n\t}\n\n\t/* sid is set just before issuing the headers, ensuring monoticity */\n\n\twsi-\u003eseen_nonpseudoheader \u003d 0;\n#if defined(LWS_WITH_CLIENT)\n\twsi-\u003eclient_mux_substream \u003d 1;\n#endif\n\twsi-\u003eh2.initialized \u003d 1;\n\n#if 0\n\t/* only assign sid at header send time when we know it */\n\tif (!wsi-\u003emux.my_sid) {\n\t\twsi-\u003emux.my_sid \u003d nwsi-\u003eh2.h2n-\u003ehighest_sid;\n\t\tnwsi-\u003eh2.h2n-\u003ehighest_sid +\u003d 2;\n\t}\n#endif\n\n\tlwsl_info(\u0022%s: binding wsi %s to sid %d (next %d)\u005cn\u0022, __func__,\n\t\tlws_wsi_tag(wsi), (int)wsi-\u003emux.my_sid, (int)nwsi-\u003eh2.h2n-\u003ehighest_sid);\n\n\tlws_wsi_mux_insert(wsi, parent_wsi, wsi-\u003emux.my_sid);\n\n\twsi-\u003etxc.tx_cr \u003d (int32_t)nwsi-\u003eh2.h2n-\u003epeer_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\twsi-\u003etxc.peer_tx_cr_est \u003d (int32_t)\n\t\t\tnwsi-\u003eh2.h2n-\u003eour_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\n\tlws_wsi_txc_describe(\u0026wsi-\u003etxc, __func__, wsi-\u003emux.my_sid);\n\n\tif (lws_ensure_user_space(wsi))\n\t\tgoto bail1;\n\n\tlws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,\n\t\t\t \u0026role_ops_h2);\n\n\tlws_callback_on_writable(wsi);\n\n\treturn wsi;\n\nbail1:\n\t/* undo the insert */\n\tparent_wsi-\u003emux.child_list \u003d wsi-\u003emux.sibling_list;\n\tparent_wsi-\u003emux.child_count--;\n\n\tif (wsi-\u003euser_space)\n\t\tlws_free_set_NULL(wsi-\u003euser_space);\n\twsi-\u003ea.protocol-\u003ecallback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0);\n\tlws_free(wsi);\n\n\treturn NULL;\n}\n\n\nint\nlws_h2_issue_preface(struct lws *wsi)\n{\n\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eh2.h2n;\n\tstruct lws_h2_protocol_send *pps;\n\n\tif (!h2n) {\n\t\tlwsl_warn(\u0022%s: no valid h2n\u005cn\u0022, __func__);\n\t\treturn 1;\n\t}\n\n\tif (h2n-\u003esent_preface)\n\t\treturn 1;\n\n\tlwsl_debug(\u0022%s: %s: fd %d\u005cn\u0022, __func__, lws_wsi_tag(wsi), (int)wsi-\u003edesc.sockfd);\n\n\tif (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) !\u003d\n\t\t(int)strlen(preface))\n\t\treturn 1;\n\n\th2n-\u003esent_preface \u003d 1;\n\n\tlws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS,\n\t\t\t \u0026role_ops_h2);\n\n\th2n-\u003ecount \u003d 0;\n\twsi-\u003etxc.tx_cr \u003d 65535;\n\n\t/*\n\t * we must send a settings frame\n\t */\n\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);\n\tif (!pps)\n\t\treturn 1;\n\tlws_pps_schedule(wsi, pps);\n\tlwsl_info(\u0022%s: h2 client sending settings\u005cn\u0022, __func__);\n\n\treturn 0;\n}\n\nvoid\nlws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eh2.h2n;\n\n\tif (!h2n) {\n\t\tlwsl_warn(\u0022%s: null h2n\u005cn\u0022, __func__);\n\t\tlws_free(pps);\n\t\treturn;\n\t}\n\n\tpps-\u003enext \u003d h2n-\u003epps;\n\th2n-\u003epps \u003d pps;\n\tlws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE |\n\t\t\t\t LWS_RXFLOW_REASON_H2_PPS_PENDING);\n\tlws_callback_on_writable(wsi);\n}\n\nint\nlws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason)\n{\n\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eh2.h2n;\n\tstruct lws_h2_protocol_send *pps;\n\n\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n\t\treturn 0;\n\n\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_GOAWAY);\n\tif (!pps)\n\t\treturn 1;\n\n\tlwsl_info(\u0022%s: %s: ERR 0x%x, '%s'\u005cn\u0022, __func__, lws_wsi_tag(wsi), (int)err, reason);\n\n\tpps-\u003eu.ga.err \u003d err;\n\tpps-\u003eu.ga.highest_sid \u003d h2n-\u003ehighest_sid;\n\tlws_strncpy(pps-\u003eu.ga.str, reason, sizeof(pps-\u003eu.ga.str));\n\tlws_pps_schedule(wsi, pps);\n\n\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n\n\treturn 0;\n}\n\nint\nlws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\tstruct lws_h2_netconn *h2n \u003d nwsi-\u003eh2.h2n;\n\tstruct lws_h2_protocol_send *pps;\n\n\tif (!h2n)\n\t\treturn 0;\n\n\tif (!wsi-\u003eh2_stream_carries_ws \u0026\u0026 h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n\t\treturn 0;\n\n\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_RST_STREAM);\n\tif (!pps)\n\t\treturn 1;\n\n\tlwsl_info(\u0022%s: RST_STREAM 0x%x, sid %d, REASON '%s'\u005cn\u0022, __func__,\n\t\t (int)err, wsi-\u003emux.my_sid, reason);\n\n\tpps-\u003eu.rs.sid \u003d wsi-\u003emux.my_sid;\n\tpps-\u003eu.rs.err \u003d err;\n\n\tlws_pps_schedule(wsi, pps);\n\n\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n\tlws_h2_state(wsi, LWS_H2_STATE_CLOSED);\n\n\treturn 0;\n}\n\nint\nlws_h2_settings(struct lws *wsi, struct http2_settings *settings,\n\t\tunsigned char *buf, int len)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\tunsigned int a, b;\n\n\tif (!len)\n\t\treturn 0;\n\n\tif (len \u003c LWS_H2_SETTINGS_LEN)\n\t\treturn 1;\n\n\twhile (len \u003e\u003d LWS_H2_SETTINGS_LEN) {\n\t\ta \u003d (unsigned int)((buf[0] \u003c\u003c 8) | buf[1]);\n\t\tif (!a || a \u003e\u003d H2SET_COUNT)\n\t\t\tgoto skip;\n\t\tb \u003d (unsigned int)(buf[2] \u003c\u003c 24 | buf[3] \u003c\u003c 16 | buf[4] \u003c\u003c 8 | buf[5]);\n\n\t\tswitch (a) {\n\t\tcase H2SET_HEADER_TABLE_SIZE:\n\t\t\tbreak;\n\t\tcase H2SET_ENABLE_PUSH:\n\t\t\tif (b \u003e 1) {\n\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022ENABLE_PUSH invalid arg\u0022);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase H2SET_MAX_CONCURRENT_STREAMS:\n\t\t\tbreak;\n\t\tcase H2SET_INITIAL_WINDOW_SIZE:\n\t\t\tif (b \u003e 0x7fffffff) {\n\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR,\n\t\t\t\t\t \u0022Initial Window beyond max\u0022);\n\t\t\t\treturn 1;\n\t\t\t}\n\n#if defined(LWS_WITH_CLIENT)\n#if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX)\n\t\t\tif (\n#else\n\t\t\tif (wsi-\u003eflags \u0026 LCCSCF_H2_QUIRK_OVERFLOWS_TXCR \u0026\u0026\n#endif\n\t\t\t b \u003d\u003d 0x7fffffff) {\n\t\t\t\tb \u003e\u003e\u003d 4;\n\n\t\t\t\tbreak;\n\t\t\t}\n#endif\n\n\t\t\t/*\n\t\t\t * In addition to changing the flow-control window for\n\t\t\t * streams that are not yet active, a SETTINGS frame\n\t\t\t * can alter the initial flow-control window size for\n\t\t\t * streams with active flow-control windows (that is,\n\t\t\t * streams in the \u0022open\u0022 or \u0022half-closed (remote)\u0022\n\t\t\t * state). When the value of\n\t\t\t * SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver\n\t\t\t * MUST adjust the size of all stream flow-control\n\t\t\t * windows that it maintains by the difference between\n\t\t\t * the new value and the old value.\n\t\t\t */\n\n\t\t\tlws_start_foreach_ll(struct lws *, w,\n\t\t\t\t\t nwsi-\u003emux.child_list) {\n\t\t\t\tlwsl_info(\u0022%s: adi child tc cr %d +%d -\u003e %d\u0022,\n\t\t\t\t\t __func__, (int)w-\u003etxc.tx_cr,\n\t\t\t\t\t b - (unsigned int)settings-\u003es[a],\n\t\t\t\t\t (int)(w-\u003etxc.tx_cr + (int)b -\n\t\t\t\t\t\t (int)settings-\u003es[a]));\n\t\t\t\tw-\u003etxc.tx_cr +\u003d (int)b - (int)settings-\u003es[a];\n\t\t\t\tif (w-\u003etxc.tx_cr \u003e 0 \u0026\u0026\n\t\t\t\t w-\u003etxc.tx_cr \u003c\u003d\n\t\t\t\t\t\t (int32_t)(b - settings-\u003es[a]))\n\n\t\t\t\t\tlws_callback_on_writable(w);\n\t\t\t} lws_end_foreach_ll(w, mux.sibling_list);\n\n\t\t\tbreak;\n\t\tcase H2SET_MAX_FRAME_SIZE:\n\t\t\tif (b \u003c wsi-\u003ea.vhost-\u003eh2.set.s[H2SET_MAX_FRAME_SIZE]) {\n\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022Frame size \u003c initial\u0022);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif (b \u003e 0x00ffffff) {\n\t\t\t\tlws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022Settings Frame size above max\u0022);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase H2SET_MAX_HEADER_LIST_SIZE:\n\t\t\tbreak;\n\t\t}\n\t\tsettings-\u003es[a] \u003d b;\n\t\tlwsl_info(\u0022http2 settings %d \u003c- 0x%x\u005cn\u0022, a, b);\nskip:\n\t\tlen -\u003d LWS_H2_SETTINGS_LEN;\n\t\tbuf +\u003d LWS_H2_SETTINGS_LEN;\n\t}\n\n\tif (len)\n\t\treturn 1;\n\n\tlws_h2_dump_settings(settings);\n\n\treturn 0;\n}\n\n/* RFC7640 Sect 6.9\n *\n * The WINDOW_UPDATE frame can be specific to a stream or to the entire\n * connection. In the former case, the frame's stream identifier\n * indicates the affected stream; in the latter, the value \u00220\u0022 indicates\n * that the entire connection is the subject of the frame.\n *\n * ...\n *\n * Two flow-control windows are applicable: the stream flow-control\n * window and the connection flow-control window. The sender MUST NOT\n * send a flow-controlled frame with a length that exceeds the space\n * available in either of the flow-control windows advertised by the\n * receiver. Frames with zero length with the END_STREAM flag set (that\n * is, an empty DATA frame) MAY be sent if there is no available space\n * in either flow-control window.\n */\n\nint\nlws_h2_tx_cr_get(struct lws *wsi)\n{\n\tint c \u003d wsi-\u003etxc.tx_cr;\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\n\tif (!wsi-\u003emux_substream \u0026\u0026 !nwsi-\u003eupgraded_to_http2)\n\t\treturn ~0x80000000;\n\n\tlwsl_info (\u0022%s: %s: own tx credit %d: nwsi credit %d\u005cn\u0022,\n\t\t __func__, lws_wsi_tag(wsi), c, (int)nwsi-\u003etxc.tx_cr);\n\n\tif (nwsi-\u003etxc.tx_cr \u003c c)\n\t\tc \u003d nwsi-\u003etxc.tx_cr;\n\n\tif (c \u003c 0)\n\t\treturn 0;\n\n\treturn c;\n}\n\nvoid\nlws_h2_tx_cr_consume(struct lws *wsi, int consumed)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\n\twsi-\u003etxc.tx_cr -\u003d consumed;\n\n\tif (nwsi !\u003d wsi)\n\t\tnwsi-\u003etxc.tx_cr -\u003d consumed;\n}\n\nint lws_h2_frame_write(struct lws *wsi, int type, int flags,\n\t\t unsigned int sid, unsigned int len, unsigned char *buf)\n{\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\tunsigned char *p \u003d \u0026buf[-LWS_H2_FRAME_HEADER_LENGTH];\n\tint n;\n\n\t//if (wsi-\u003eh2_stream_carries_ws)\n\t// lwsl_hexdump_level(LLL_NOTICE, buf, len);\n\n\t*p++ \u003d (uint8_t)(len \u003e\u003e 16);\n\t*p++ \u003d (uint8_t)(len \u003e\u003e 8);\n\t*p++ \u003d (uint8_t)len;\n\t*p++ \u003d (uint8_t)type;\n\t*p++ \u003d (uint8_t)flags;\n\t*p++ \u003d (uint8_t)(sid \u003e\u003e 24);\n\t*p++ \u003d (uint8_t)(sid \u003e\u003e 16);\n\t*p++ \u003d (uint8_t)(sid \u003e\u003e 8);\n\t*p++ \u003d (uint8_t)sid;\n\n\tlwsl_debug(\u0022%s: %s (eff %s). typ %d, fl 0x%x, sid\u003d%d, len\u003d%d, \u0022\n\t\t \u0022txcr\u003d%d, nwsi-\u003etxcr\u003d%d\u005cn\u0022, __func__, lws_wsi_tag(wsi),\n\t\t lws_wsi_tag(nwsi), type, flags,\n\t\t sid, len, (int)wsi-\u003etxc.tx_cr, (int)nwsi-\u003etxc.tx_cr);\n\n\tif (type \u003d\u003d LWS_H2_FRAME_TYPE_DATA) {\n\t\tif (wsi-\u003etxc.tx_cr \u003c (int)len)\n\n\t\t\tlwsl_info(\u0022%s: %s: sending payload len %d\u0022\n\t\t\t\t \u0022 but tx_cr only %d!\u005cn\u0022, __func__,\n\t\t\t\t lws_wsi_tag(wsi), len, (int)wsi-\u003etxc.tx_cr);\n\t\t\t\tlws_h2_tx_cr_consume(wsi, (int)len);\n\t}\n\n\tn \u003d lws_issue_raw(nwsi, \u0026buf[-LWS_H2_FRAME_HEADER_LENGTH],\n\t\t\t len + LWS_H2_FRAME_HEADER_LENGTH);\n\tif (n \u003c 0)\n\t\treturn n;\n\n\tif (n \u003e\u003d LWS_H2_FRAME_HEADER_LENGTH)\n\t\treturn n - LWS_H2_FRAME_HEADER_LENGTH;\n\n\treturn n;\n}\n\nstatic void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf)\n{\n\t*buf++ \u003d (uint8_t)(n \u003e\u003e 8);\n\t*buf++ \u003d (uint8_t)n;\n\t*buf++ \u003d (uint8_t)(wsi-\u003eh2.h2n-\u003eour_set.s[n] \u003e\u003e 24);\n\t*buf++ \u003d (uint8_t)(wsi-\u003eh2.h2n-\u003eour_set.s[n] \u003e\u003e 16);\n\t*buf++ \u003d (uint8_t)(wsi-\u003eh2.h2n-\u003eour_set.s[n] \u003e\u003e 8);\n\t*buf \u003d (uint8_t)wsi-\u003eh2.h2n-\u003eour_set.s[n];\n}\n\n/* we get called on the network connection */\n\nint lws_h2_do_pps_send(struct lws *wsi)\n{\n\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eh2.h2n;\n\tstruct lws_h2_protocol_send *pps \u003d NULL;\n\tstruct lws *cwsi;\n\tuint8_t set[LWS_PRE + 64], *p \u003d \u0026set[LWS_PRE], *q;\n\tint n, m \u003d 0, flags \u003d 0;\n\n\tif (!h2n)\n\t\treturn 1;\n\n\t/* get the oldest pps */\n\n\tlws_start_foreach_llp(struct lws_h2_protocol_send **, pps1, h2n-\u003epps) {\n\t\tif ((*pps1)-\u003enext \u003d\u003d NULL) { /* we are the oldest in the list */\n\t\t\tpps \u003d *pps1; /* remove us from the list */\n\t\t\t*pps1 \u003d NULL;\n\t\t\tcontinue;\n\t\t}\n\t} lws_end_foreach_llp(pps1, next);\n\n\tif (!pps)\n\t\treturn 1;\n\n\tlwsl_info(\u0022%s: %s: %d\u005cn\u0022, __func__, lws_wsi_tag(wsi), pps-\u003etype);\n\n\tswitch (pps-\u003etype) {\n\n\tcase LWS_H2_PPS_MY_SETTINGS:\n\n\t\t/*\n\t\t * if any of our settings varies from h2 \u0022default defaults\u0022\n\t\t * then we must inform the peer\n\t\t */\n\t\tfor (n \u003d 1; n \u003c H2SET_COUNT; n++)\n\t\t\tif (h2n-\u003eour_set.s[n] !\u003d lws_h2_defaults.s[n]) {\n\t\t\t\tlwsl_debug(\u0022sending SETTING %d 0x%x\u005cn\u0022, n,\n\t\t\t\t\t (unsigned int)\n\t\t\t\t\t\t wsi-\u003eh2.h2n-\u003eour_set.s[n]);\n\n\t\t\t\tlws_h2_set_bin(wsi, n, \u0026set[LWS_PRE + m]);\n\t\t\t\tm +\u003d (int)sizeof(h2n-\u003eone_setting);\n\t\t\t}\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,\n\t\t\t\t flags, LWS_H2_STREAM_ID_MASTER, (unsigned int)m,\n\t\t \t\t \u0026set[LWS_PRE]);\n\t\tif (n !\u003d m) {\n\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n\t\t\tgoto bail;\n\t\t}\n\t\tbreak;\n\n\tcase LWS_H2_PPS_SETTINGS_INITIAL_UPDATE_WINDOW:\n\t\tq \u003d \u0026set[LWS_PRE];\n\t\t*q++ \u003d (uint8_t)(H2SET_INITIAL_WINDOW_SIZE \u003e\u003e 8);\n\t\t*q++ \u003d (uint8_t)(H2SET_INITIAL_WINDOW_SIZE);\n\t\t*q++ \u003d (uint8_t)(pps-\u003eu.update_window.credit \u003e\u003e 24);\n\t\t*q++ \u003d (uint8_t)(pps-\u003eu.update_window.credit \u003e\u003e 16);\n\t\t*q++ \u003d (uint8_t)(pps-\u003eu.update_window.credit \u003e\u003e 8);\n\t\t*q \u003d (uint8_t)(pps-\u003eu.update_window.credit);\n\n\t\tlwsl_debug(\u0022%s: resetting initial window to %d\u005cn\u0022, __func__,\n\t\t\t\t(int)pps-\u003eu.update_window.credit);\n\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS,\n\t\t\t\t flags, LWS_H2_STREAM_ID_MASTER, 6,\n\t\t \t\t \u0026set[LWS_PRE]);\n\t\tif (n !\u003d 6) {\n\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n\t\t\tgoto bail;\n\t\t}\n\t\tbreak;\n\n\tcase LWS_H2_PPS_ACK_SETTINGS:\n\t\t/* send ack ... always empty */\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1,\n\t\t\t\t LWS_H2_STREAM_ID_MASTER, 0,\n\t\t\t\t \u0026set[LWS_PRE]);\n\t\tif (n) {\n\t\t\tlwsl_err(\u0022%s: writing settings ack frame failed %d\u005cn\u0022, __func__, n);\n\t\t\tgoto bail;\n\t\t}\n\t\twsi-\u003eh2_acked_settings \u003d 0;\n\t\t/* this is the end of the preface dance then? */\n\t\tif (lwsi_state(wsi) \u003d\u003d LRS_H2_AWAIT_SETTINGS) {\n\t\t\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n#if defined(LWS_WITH_FILE_OPS)\n\t\t\twsi-\u003ehttp.fop_fd \u003d NULL;\n#endif\n\t\t\tif (lws_is_ssl(lws_get_network_wsi(wsi)))\n\t\t\t\tbreak;\n\n\t\t\tif (wsi-\u003ea.vhost-\u003eoptions \u0026\n\t\t\t\tLWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)\n\t\t\t\tbreak;\n\n\t\t\t/*\n\t\t\t * we need to treat the headers from the upgrade as the\n\t\t\t * first job. So these need to get shifted to sid 1.\n\t\t\t */\n\n\t\t\tlws_context_lock(wsi-\u003ea.context, \u0022h2 mig\u0022);\n\t\t\tlws_vhost_lock(wsi-\u003ea.vhost);\n\n\t\t\th2n-\u003eswsi \u003d __lws_wsi_server_new(wsi-\u003ea.vhost, wsi, 1);\n\n\t\t\tlws_vhost_unlock(wsi-\u003ea.vhost);\n\t\t\tlws_context_unlock(wsi-\u003ea.context);\n\n\t\t\tif (!h2n-\u003eswsi)\n\t\t\t\tgoto bail;\n\n\t\t\t/* pass on the initial headers to SID 1 */\n\t\t\th2n-\u003eswsi-\u003ehttp.ah \u003d wsi-\u003ehttp.ah;\n\t\t\twsi-\u003ehttp.ah \u003d NULL;\n\n\t\t\tlwsl_info(\u0022%s: inherited headers %p\u005cn\u0022, __func__,\n\t\t\t\t h2n-\u003eswsi-\u003ehttp.ah);\n\t\t\th2n-\u003eswsi-\u003etxc.tx_cr \u003d (int32_t)\n\t\t\t\th2n-\u003eour_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\t\t\tlwsl_info(\u0022initial tx credit on %s: %d\u005cn\u0022,\n\t\t\t\t lws_wsi_tag(h2n-\u003eswsi),\n\t\t\t\t (int)h2n-\u003eswsi-\u003etxc.tx_cr);\n\t\t\th2n-\u003eswsi-\u003eh2.initialized \u003d 1;\n\t\t\t/* demanded by HTTP2 */\n\t\t\th2n-\u003eswsi-\u003eh2.END_STREAM \u003d 1;\n\t\t\tlwsl_info(\u0022servicing initial http request\u005cn\u0022);\n\n#if defined(LWS_WITH_SERVER)\n\t\t\tif (lws_http_action(h2n-\u003eswsi))\n\t\t\t\tgoto bail;\n#endif\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\t/*\n\t * h2 only has PING... ACK \u003d 0 \u003d ping, ACK \u003d 1 \u003d pong\n\t */\n\n\tcase LWS_H2_PPS_PING:\n\tcase LWS_H2_PPS_PONG:\n\t\tif (pps-\u003etype \u003d\u003d LWS_H2_PPS_PING)\n\t\t\tlwsl_info(\u0022sending PING\u005cn\u0022);\n\t\telse {\n\t\t\tlwsl_info(\u0022sending PONG\u005cn\u0022);\n\t\t\tflags \u003d LWS_H2_FLAG_SETTINGS_ACK;\n\t\t}\n\n\t\tmemcpy(\u0026set[LWS_PRE], pps-\u003eu.ping.ping_payload, 8);\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING, flags,\n\t\t\t\t LWS_H2_STREAM_ID_MASTER, 8,\n\t\t\t\t \u0026set[LWS_PRE]);\n\t\tif (n !\u003d 8)\n\t\t\tgoto bail;\n\n\t\tbreak;\n\n\tcase LWS_H2_PPS_GOAWAY:\n\t\tlwsl_info(\u0022LWS_H2_PPS_GOAWAY\u005cn\u0022);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.highest_sid \u003e\u003e 24);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.highest_sid \u003e\u003e 16);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.highest_sid \u003e\u003e 8);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.highest_sid);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.err \u003e\u003e 24);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.err \u003e\u003e 16);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.err \u003e\u003e 8);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.ga.err);\n\t\tq \u003d (unsigned char *)pps-\u003eu.ga.str;\n\t\tn \u003d 0;\n\t\twhile (*q \u0026\u0026 n++ \u003c (int)sizeof(pps-\u003eu.ga.str))\n\t\t\t*p++ \u003d *q++;\n\t\th2n-\u003ewe_told_goaway \u003d 1;\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0,\n\t\t\t\t LWS_H2_STREAM_ID_MASTER,\n\t\t\t\t (unsigned int)lws_ptr_diff(p, \u0026set[LWS_PRE]),\n\t\t\t\t \u0026set[LWS_PRE]);\n\t\tif (n !\u003d 4) {\n\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n\t\t\tgoto bail;\n\t\t}\n\t\tgoto bail;\n\n\tcase LWS_H2_PPS_RST_STREAM:\n\t\tlwsl_info(\u0022LWS_H2_PPS_RST_STREAM\u005cn\u0022);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.rs.err \u003e\u003e 24);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.rs.err \u003e\u003e 16);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.rs.err \u003e\u003e 8);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.rs.err);\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM,\n\t\t\t\t 0, pps-\u003eu.rs.sid, 4, \u0026set[LWS_PRE]);\n\t\tif (n !\u003d 4) {\n\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n\t\t\tgoto bail;\n\t\t}\n\t\tcwsi \u003d lws_wsi_mux_from_id(wsi, pps-\u003eu.rs.sid);\n\t\tif (cwsi) {\n\t\t\tlwsl_debug(\u0022%s: closing cwsi %s %s %s (wsi %s)\u005cn\u0022,\n\t\t\t\t __func__, lws_wsi_tag(cwsi),\n\t\t\t\t cwsi-\u003erole_ops-\u003ename,\n\t\t\t\t cwsi-\u003ea.protocol-\u003ename, lws_wsi_tag(wsi));\n\t\t\tlws_close_free_wsi(cwsi, 0, \u0022reset stream\u0022);\n\t\t}\n\t\tbreak;\n\n\tcase LWS_H2_PPS_UPDATE_WINDOW:\n\t\tlwsl_info(\u0022Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\u005cn\u0022,\n\t\t\t (int)pps-\u003eu.update_window.sid,\n\t\t\t (int)pps-\u003eu.update_window.credit);\n\t\t*p++ \u003d (uint8_t)((pps-\u003eu.update_window.credit \u003e\u003e 24) \u0026 0x7f); /* 31b */\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.update_window.credit \u003e\u003e 16);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.update_window.credit \u003e\u003e 8);\n\t\t*p++ \u003d (uint8_t)(pps-\u003eu.update_window.credit);\n\t\tn \u003d lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE,\n\t\t\t\t 0, pps-\u003eu.update_window.sid, 4,\n\t\t\t\t \u0026set[LWS_PRE]);\n\t\tif (n !\u003d 4) {\n\t\t\tlwsl_info(\u0022send %d %d\u005cn\u0022, n, m);\n\t\t\tgoto bail;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\tlws_free(pps);\n\n\treturn 0;\n\nbail:\n\tlws_free(pps);\n\n\treturn 1;\n}\n\nstatic int\nlws_h2_parse_end_of_frame(struct lws *wsi);\n\n/*\n * The frame header part has just completely arrived.\n * Perform actions for header completion.\n */\nstatic int\nlws_h2_parse_frame_header(struct lws *wsi)\n{\n\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eh2.h2n;\n\tstruct lws_h2_protocol_send *pps;\n\tint n;\n\n\t/*\n\t * We just got the frame header\n\t */\n\th2n-\u003ecount \u003d 0;\n\th2n-\u003eswsi \u003d wsi;\n\t/* b31 is a reserved bit */\n\th2n-\u003esid \u003d h2n-\u003esid \u0026 0x7fffffff;\n\n\tif (h2n-\u003esid \u0026\u0026 !(h2n-\u003esid \u0026 1)) {\n\t\tchar pes[32];\n\t\tlws_snprintf(pes, sizeof(pes), \u0022Even Stream ID 0x%x\u0022, (unsigned int)h2n-\u003esid);\n\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, pes);\n\n\t\treturn 0;\n\t}\n\n\t/* let the network wsi live a bit longer if subs are active */\n\n\tif (!wsi-\u003eimmortal_substream_count)\n\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,\n\t\t\t\twsi-\u003ea.vhost-\u003ekeepalive_timeout ?\n\t\t\t\t\twsi-\u003ea.vhost-\u003ekeepalive_timeout : 31);\n\n\tif (h2n-\u003esid)\n\t\th2n-\u003eswsi \u003d lws_wsi_mux_from_id(wsi, h2n-\u003esid);\n\n\tlwsl_debug(\u0022%s (%s): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\u005cn\u0022,\n\t\t lws_wsi_tag(wsi), lws_wsi_tag(h2n-\u003eswsi), h2n-\u003etype,\n\t\t h2n-\u003eflags, (unsigned int)h2n-\u003esid, (unsigned int)h2n-\u003elength);\n\n\tif (h2n-\u003ewe_told_goaway \u0026\u0026 h2n-\u003esid \u003e h2n-\u003ehighest_sid)\n\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n\n\tif (h2n-\u003etype \u003e\u003d LWS_H2_FRAME_TYPE_COUNT) {\n\t\tlwsl_info(\u0022%s: ignoring unknown frame type %d (len %d)\u005cn\u0022, __func__, h2n-\u003etype, (unsigned int)h2n-\u003elength);\n\t\t/* we MUST ignore frames we don't understand */\n\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT;\n\t}\n\n\t/*\n\t * Even if we have decided to logically ignore this frame, we must\n\t * consume the correct \u0022frame length\u0022 amount of data to retain sync\n\t */\n\n\tif (h2n-\u003elength \u003e h2n-\u003eour_set.s[H2SET_MAX_FRAME_SIZE]) {\n\t\t/*\n\t\t * peer sent us something bigger than we told\n\t\t * it we would allow\n\t\t */\n\t\tlwsl_info(\u0022%s: received oversize frame %d\u005cn\u0022, __func__,\n\t\t\t (unsigned int)h2n-\u003elength);\n\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t \u0022Peer ignored our frame size setting\u0022);\n\t\treturn 1;\n\t}\n\n\tif (h2n-\u003eswsi)\n\t\tlwsl_info(\u0022%s: %s, State: %s, received cmd %d\u005cn\u0022,\n\t\t __func__, lws_wsi_tag(h2n-\u003eswsi),\n\t\t h2_state_names[h2n-\u003eswsi-\u003eh2.h2_state], h2n-\u003etype);\n\telse {\n\t\t/* if it's data, either way no swsi means CLOSED state */\n\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_DATA) {\n\t\t\tif (h2n-\u003esid \u003c\u003d h2n-\u003ehighest_sid_opened\n#if defined(LWS_WITH_CLIENT)\n\t\t\t\t\t\u0026\u0026 wsi-\u003eclient_h2_alpn\n#endif\n\t\t\t) {\n\t\t\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_END_STREAM)\n\t\t\t\t\tlwsl_notice(\u0022%s: stragging EOS\u005cn\u0022, __func__);\n\t\t\t\telse {\n\t\t\t\t\tlwsl_wsi_notice(wsi, \u0022ignoring straggling \u0022\n\t\t\t\t\t\t\u0022DATA (flags 0x%x, length %d)\u0022,\n\t\t\t\t\t\t\th2n-\u003eflags, (int)h2n-\u003elength);\n\t\t\t\t\t/* ie, IGNORE */\n\t\t\t\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlwsl_info(\u0022%s: received %d bytes data for unknown sid %d, highest known %d\u005cn\u0022,\n\t\t\t\t\t\t__func__, (int)h2n-\u003elength, (int)h2n-\u003esid, (int)h2n-\u003ehighest_sid_opened);\n\n//\t\t\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened) {\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n\t\t\t\t \u0022Data for nonexistent sid\u0022);\n\t\t\t\treturn 0;\n//\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t/* if the sid is credible, treat as wsi for it closed */\n\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened \u0026\u0026\n\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_HEADERS \u0026\u0026\n\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_PRIORITY) {\n\t\t\t/* if not credible, reject it */\n\t\t\tlwsl_info(\u0022%s: %s, No child for sid %d, rxcmd %d\u005cn\u0022,\n\t\t\t __func__, lws_wsi_tag(h2n-\u003eswsi), (unsigned int)h2n-\u003esid, h2n-\u003etype);\n\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n\t\t\t\t \u0022Data for nonexistent sid\u0022);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif (h2n-\u003eswsi \u0026\u0026 h2n-\u003esid \u0026\u0026 h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_COUNT \u0026\u0026\n\t !(http2_rx_validity[h2n-\u003eswsi-\u003eh2.h2_state] \u0026 (1 \u003c\u003c h2n-\u003etype))) {\n\t\tlwsl_info(\u0022%s: %s, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\u005cn\u0022,\n\t\t\t __func__, lws_wsi_tag(h2n-\u003eswsi),\n\t\t\t h2_state_names[h2n-\u003eswsi-\u003eh2.h2_state], h2n-\u003etype,\n\t\t\t http2_rx_validity[h2n-\u003eswsi-\u003eh2.h2_state]);\n\n\t\tif (h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED ||\n\t\t h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE)\n\t\t\tn \u003d H2_ERR_STREAM_CLOSED;\n\t\telse\n\t\t\tn \u003d H2_ERR_PROTOCOL_ERROR;\n\t\tlws_h2_goaway(wsi, (unsigned int)n, \u0022invalid rx for state\u0022);\n\n\t\treturn 0;\n\t}\n\n\tif (h2n-\u003econt_exp \u0026\u0026 h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_COUNT \u0026\u0026\n\t (h2n-\u003econt_exp_sid !\u003d h2n-\u003esid ||\n\t\t\t h2n-\u003etype !\u003d LWS_H2_FRAME_TYPE_CONTINUATION)) {\n\t\tlwsl_info(\u0022%s: expected cont on sid %u (got %d on sid %u)\u005cn\u0022,\n\t\t\t __func__, (unsigned int)h2n-\u003econt_exp_sid, h2n-\u003etype,\n\t\t\t (unsigned int)h2n-\u003esid);\n\t\th2n-\u003econt_exp \u003d 0;\n\t\tif (h2n-\u003econt_exp_headers)\n\t\t\tn \u003d H2_ERR_COMPRESSION_ERROR;\n\t\telse\n\t\t\tn \u003d H2_ERR_PROTOCOL_ERROR;\n\t\tlws_h2_goaway(wsi, (unsigned int)n, \u0022Continuation hdrs State\u0022);\n\n\t\treturn 0;\n\t}\n\n\tswitch (h2n-\u003etype) {\n\tcase LWS_H2_FRAME_TYPE_DATA:\n\t\tlwsl_info(\u0022seen incoming LWS_H2_FRAME_TYPE_DATA start\u005cn\u0022);\n\t\tif (!h2n-\u003esid) {\n\t\t\tlwsl_info(\u0022DATA: 0 sid\u005cn\u0022);\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022DATA 0 sid\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tlwsl_info(\u0022Frame header DATA: sid %u, flags 0x%x, len %u\u005cn\u0022,\n\t\t\t\t(unsigned int)h2n-\u003esid, h2n-\u003eflags,\n\t\t\t\t(unsigned int)h2n-\u003elength);\n\n\t\tif (!h2n-\u003eswsi) {\n\t\t\tlwsl_notice(\u0022DATA: NULL swsi\u005cn\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tlwsl_info(\u0022DATA rx on state %d\u005cn\u0022, h2n-\u003eswsi-\u003eh2.h2_state);\n\n\t\tif (\n\t\t h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE ||\n\t\t h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, \u0022conn closed\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (h2n-\u003elength \u003d\u003d 0)\n\t\t\tlws_h2_parse_end_of_frame(wsi);\n\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_PRIORITY:\n\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_PRIORITY complete frame\u005cn\u0022);\n\t\tif (!h2n-\u003esid) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022Priority has 0 sid\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tif (h2n-\u003elength !\u003d 5) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t\t \u0022Priority has length other than 5\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase LWS_H2_FRAME_TYPE_PUSH_PROMISE:\n\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_PUSH_PROMISE complete frame\u005cn\u0022);\n\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022Server only\u0022);\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n\t\tlwsl_debug(\u0022LWS_H2_FRAME_TYPE_GOAWAY received\u005cn\u0022);\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n\t\tif (!h2n-\u003esid)\n\t\t\treturn 1;\n\t\tif (!h2n-\u003eswsi) {\n\t\t\tif (h2n-\u003esid \u003c\u003d h2n-\u003ehighest_sid_opened)\n\t\t\t\tbreak;\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022crazy sid on RST_STREAM\u0022);\n\t\t\treturn 1;\n\t\t}\n\t\tif (h2n-\u003elength !\u003d 4) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t\t \u0022RST_STREAM can only be length 4\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_SETTINGS complete frame\u005cn\u0022);\n\t\t/* nonzero sid on settings is illegal */\n\t\tif (h2n-\u003esid) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022Settings has nonzero sid\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!(h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK)) {\n\t\t\tif (h2n-\u003elength % 6) {\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t\t\t\t \u0022Settings length error\u0022);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT)\n\t\t\t\treturn 0;\n\n\t\t\tif (wsi-\u003eupgraded_to_http2 \u0026\u0026\n#if defined(LWS_WITH_CLIENT)\n\t\t\t (!(wsi-\u003eflags \u0026 LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) ||\n#else\n\t\t\t (\n#endif\n\t\t\t\t\t !wsi-\u003eh2_acked_settings)) {\n\n\t\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);\n\t\t\t\tif (!pps)\n\t\t\t\t\treturn 1;\n\t\t\t\tlws_pps_schedule(wsi, pps);\n\t\t\t\twsi-\u003eh2_acked_settings \u003d 1;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\t/* came to us with ACK set... not allowed to have payload */\n\n\t\tif (h2n-\u003elength) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t\t \u0022Settings with ACK not allowed payload\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase LWS_H2_FRAME_TYPE_PING:\n\t\tif (h2n-\u003esid) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022Ping has nonzero sid\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tif (h2n-\u003elength !\u003d 8) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t\t \u0022Ping payload can only be 8\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_CONTINUATION: sid \u003d %u %d %d\u005cn\u0022,\n\t\t\t (unsigned int)h2n-\u003esid, (int)h2n-\u003econt_exp,\n\t\t\t (int)h2n-\u003econt_exp_sid);\n\n\t\tif (!h2n-\u003econt_exp ||\n\t\t h2n-\u003econt_exp_sid !\u003d h2n-\u003esid ||\n\t\t !h2n-\u003esid ||\n\t\t !h2n-\u003eswsi) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022unexpected CONTINUATION\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (h2n-\u003eswsi-\u003eh2.END_HEADERS) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022END_HEADERS already seen\u0022);\n\t\t\tbreak;\n\t\t}\n\t\t/* END_STREAM is in HEADERS, skip resetting it */\n\t\tgoto update_end_headers;\n\n\tcase LWS_H2_FRAME_TYPE_HEADERS:\n\t\tlwsl_info(\u0022HEADERS: frame header: sid \u003d %u\u005cn\u0022,\n\t\t\t\t(unsigned int)h2n-\u003esid);\n\t\tif (!h2n-\u003esid) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022sid 0\u0022);\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (h2n-\u003eswsi \u0026\u0026 !h2n-\u003eswsi-\u003eh2.END_STREAM \u0026\u0026\n\t\t h2n-\u003eswsi-\u003eh2.END_HEADERS \u0026\u0026\n\t\t !(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_STREAM)) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022extra HEADERS together\u0022);\n\t\t\treturn 1;\n\t\t}\n\n#if defined(LWS_WITH_CLIENT)\n\t\tif (wsi-\u003eclient_h2_alpn) {\n\t\t\tif (h2n-\u003esid) {\n\t\t\t\th2n-\u003eswsi \u003d lws_wsi_mux_from_id(wsi, h2n-\u003esid);\n\t\t\t\tlwsl_info(\u0022HEADERS: nwsi %s: sid %u mapped \u0022\n\t\t\t\t\t \u0022to wsi %s\u005cn\u0022, lws_wsi_tag(wsi),\n\t\t\t\t\t (unsigned int)h2n-\u003esid,\n\t\t\t\t\t lws_wsi_tag(h2n-\u003eswsi));\n\t\t\t\tif (!h2n-\u003eswsi)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tgoto update_end_headers;\n\t\t}\n#endif\n\n\t\tif (!h2n-\u003eswsi) {\n\t\t\t/* no more children allowed by parent */\n\t\t\tif (wsi-\u003emux.child_count + 1 \u003e\n\t\t\t wsi-\u003eh2.h2n-\u003eour_set.s[H2SET_MAX_CONCURRENT_STREAMS]) {\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\u0022Another stream not allowed\u0022);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * The peer has sent us a HEADERS implying the creation\n\t\t\t * of a new stream\n\t\t\t */\n\n\t\t\tlws_context_lock(wsi-\u003ea.context, \u0022h2 new str\u0022);\n\t\t\tlws_vhost_lock(wsi-\u003ea.vhost);\n\n\t\t\th2n-\u003eswsi \u003d __lws_wsi_server_new(wsi-\u003ea.vhost, wsi,\n\t\t\t\t\t\t h2n-\u003esid);\n\n\t\t\tlws_vhost_unlock(wsi-\u003ea.vhost);\n\t\t\tlws_context_unlock(wsi-\u003ea.context);\n\n\t\t\tif (!h2n-\u003eswsi) {\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022OOM\u0022);\n\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif (h2n-\u003esid \u003e\u003d h2n-\u003ehighest_sid)\n\t\t\t\th2n-\u003ehighest_sid \u003d h2n-\u003esid + 2;\n\n\t\t\th2n-\u003eswsi-\u003eh2.initialized \u003d 1;\n\n\t\t\tif (lws_h2_update_peer_txcredit(h2n-\u003eswsi,\n\t\t\t\t\th2n-\u003eswsi-\u003emux.my_sid, 4 * 65536))\n\t\t\t\tgoto cleanup_wsi;\n\t\t}\n\n\t\t/*\n\t\t * ah needs attaching to child wsi, even though\n\t\t * we only fill it from network wsi\n\t\t */\n\t\tif (!h2n-\u003eswsi-\u003ehttp.ah)\n\t\t\tif (lws_header_table_attach(h2n-\u003eswsi, 0)) {\n\t\t\t\tlwsl_err(\u0022%s: Failed to get ah\u005cn\u0022, __func__);\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t/*\n\t\t * The first use of a new stream identifier implicitly closes\n\t\t * all streams in the \u0022idle\u0022 state that might have been\n\t\t * initiated by that peer with a lower-valued stream identifier.\n\t\t *\n\t\t * For example, if a client sends a HEADERS frame on stream 7\n\t\t * without ever sending a frame on stream 5, then stream 5\n\t\t * transitions to the \u0022closed\u0022 state when the first frame for\n\t\t * stream 7 is sent or received.\n\t\t */\n\t\tlws_start_foreach_ll(struct lws *, w, wsi-\u003emux.child_list) {\n\t\t\tif (w-\u003emux.my_sid \u003c h2n-\u003esid \u0026\u0026\n\t\t\t w-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_IDLE)\n\t\t\t\tlws_close_free_wsi(w, 0, \u0022h2 sid close\u0022);\n\t\t\tassert(w-\u003emux.sibling_list !\u003d w);\n\t\t} lws_end_foreach_ll(w, mux.sibling_list);\n\n\t\th2n-\u003econt_exp \u003d !(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_HEADERS);\n\t\th2n-\u003econt_exp_sid \u003d h2n-\u003esid;\n\t\th2n-\u003econt_exp_headers \u003d 1;\n\t//\tlws_header_table_reset(h2n-\u003eswsi, 0);\n\nupdate_end_headers:\n\t\tif (lws_check_opt(h2n-\u003eswsi-\u003ea.vhost-\u003eoptions,\n\t\t\t LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) {\n\n\t\t\t/*\n\t\t\t * We don't directly timeout streams that enter the\n\t\t\t * half-closed remote state, allowing immortal long\n\t\t\t * poll\n\t\t\t */\n\t\t\tlws_mux_mark_immortal(h2n-\u003eswsi);\n\t\t\tlwsl_info(\u0022%s: %s: h2 stream entering long poll\u005cn\u0022,\n\t\t\t\t\t__func__, lws_wsi_tag(h2n-\u003eswsi));\n\n\t\t} else {\n\t\t\th2n-\u003eswsi-\u003eh2.END_STREAM \u003d\n\t\t\t\t\t!!(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_STREAM);\n\t\t\tlwsl_debug(\u0022%s: hdr END_STREAM \u003d %d\u005cn\u0022,__func__,\n\t\t\t h2n-\u003eswsi-\u003eh2.END_STREAM);\n\t\t}\n\n\t\t/* no END_HEADERS means CONTINUATION must come */\n\t\th2n-\u003eswsi-\u003eh2.END_HEADERS \u003d\n\t\t\t\t!!(h2n-\u003eflags \u0026 LWS_H2_FLAG_END_HEADERS);\n\t\tlwsl_info(\u0022%s: %s: END_HEADERS %d\u005cn\u0022, __func__, lws_wsi_tag(h2n-\u003eswsi),\n\t\t\t h2n-\u003eswsi-\u003eh2.END_HEADERS);\n\t\tif (h2n-\u003eswsi-\u003eh2.END_HEADERS)\n\t\t\th2n-\u003econt_exp \u003d 0;\n\t\tlwsl_debug(\u0022END_HEADERS %d\u005cn\u0022, h2n-\u003eswsi-\u003eh2.END_HEADERS);\n\t\tbreak;\n\ncleanup_wsi:\n\n\t\treturn 1;\n\n\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n\t\tif (h2n-\u003elength !\u003d 4) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,\n\t\t\t\t \u0022window update frame not 4\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_WINDOW_UPDATE\u005cn\u0022);\n\t\tbreak;\n\tcase LWS_H2_FRAME_TYPE_COUNT:\n\t\tif (h2n-\u003elength \u003d\u003d 0)\n\t\t\tlws_h2_parse_end_of_frame(wsi);\n\t\telse\n\t\t\tlwsl_debug(\u0022%s: going on to deal with unknown frame remaining len %d\u005cn\u0022, __func__, (unsigned int)h2n-\u003elength);\n\t\tbreak;\n\tdefault:\n\t\tlwsl_info(\u0022%s: ILLEGAL FRAME TYPE %d\u005cn\u0022, __func__, h2n-\u003etype);\n\t\th2n-\u003etype \u003d LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */\n\t\tbreak;\n\t}\n\tif (h2n-\u003elength \u003d\u003d 0)\n\t\th2n-\u003eframe_state \u003d 0;\n\n\treturn 0;\n}\n\nstatic const char * const method_names[] \u003d {\n\t\u0022GET\u0022, \u0022POST\u0022,\n#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)\n\t\u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022,\n#endif\n\t\u0022CONNECT\u0022, \u0022HEAD\u0022\n};\nstatic unsigned char method_index[] \u003d {\n\tWSI_TOKEN_GET_URI,\n\tWSI_TOKEN_POST_URI,\n#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)\n\tWSI_TOKEN_OPTIONS_URI,\n\tWSI_TOKEN_PUT_URI,\n\tWSI_TOKEN_PATCH_URI,\n\tWSI_TOKEN_DELETE_URI,\n#endif\n\tWSI_TOKEN_CONNECT,\n\tWSI_TOKEN_HEAD_URI,\n};\n\n/*\n * The last byte of the whole frame has been handled.\n * Perform actions for frame completion.\n *\n * This is the crunch time for parsing that may have occured on a network\n * wsi with a pending partial send... we may call lws_http_action() to send\n * a response, conflicting with the partial.\n *\n * So in that case we change the wsi state and do the lws_http_action() in the\n * WRITABLE handler as a priority.\n */\nstatic int\nlws_h2_parse_end_of_frame(struct lws *wsi)\n{\n\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eh2.h2n;\n\tstruct lws *eff_wsi \u003d wsi;\n\tconst char *p;\n\tint n;\n\n\th2n-\u003eframe_state \u003d 0;\n\th2n-\u003ecount \u003d 0;\n\n\tif (h2n-\u003esid)\n\t\th2n-\u003eswsi \u003d lws_wsi_mux_from_id(wsi, h2n-\u003esid);\n\n\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid)\n\t\th2n-\u003ehighest_sid \u003d h2n-\u003esid;\n\n\tif (h2n-\u003ecollected_priority \u0026\u0026 (h2n-\u003edep \u0026 ~(1u \u003c\u003c 31)) \u003d\u003d h2n-\u003esid) {\n\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, \u0022depends on own sid\u0022);\n\t\treturn 0;\n\t}\n\n\tswitch (h2n-\u003etype) {\n\n\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n\n#if defined(LWS_WITH_CLIENT)\n\t\tif (wsi-\u003eclient_h2_alpn \u0026\u0026 !wsi-\u003eclient_mux_migrated \u0026\u0026\n\t\t !(h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK)) {\n\t\t\tstruct lws_h2_protocol_send *pps;\n\n\t\t\t/* migrate original client ask on to substream 1 */\n#if defined(LWS_WITH_FILE_OPS)\n\t\t\twsi-\u003ehttp.fop_fd \u003d NULL;\n#endif\n\t\t\tlwsl_info(\u0022%s: migrating\u005cn\u0022, __func__);\n\t\t\twsi-\u003eclient_mux_migrated \u003d 1;\n\t\t\t/*\n\t\t\t * we need to treat the headers from the upgrade as the\n\t\t\t * first job. So these need to get shifted to sid 1.\n\t\t\t */\n\t\t\tlws_context_lock(wsi-\u003ea.context, \u0022h2 mig\u0022);\n\t\t\tlws_vhost_lock(wsi-\u003ea.vhost);\n\n\t\t\th2n-\u003eswsi \u003d __lws_wsi_server_new(wsi-\u003ea.vhost, wsi, 1);\n\n\t\t\tlws_vhost_unlock(wsi-\u003ea.vhost);\n\t\t\tlws_context_unlock(wsi-\u003ea.context);\n\n\t\t\tif (!h2n-\u003eswsi)\n\t\t\t\treturn 1;\n\t\t\th2n-\u003esid \u003d 1;\n\n\t\t\tassert(lws_wsi_mux_from_id(wsi, 1) \u003d\u003d h2n-\u003eswsi);\n\n\t\t//\tlws_role_transition(wsi, LWSIFR_CLIENT,\n\t\t//\t\t\t LRS_H2_WAITING_TO_SEND_HEADERS,\n\t\t//\t\t\t \u0026role_ops_h2);\n\n\t\t\tlws_role_transition(h2n-\u003eswsi, LWSIFR_CLIENT,\n\t\t\t\t\t LRS_H2_WAITING_TO_SEND_HEADERS,\n\t\t\t\t\t \u0026role_ops_h2);\n\n\t\t\t/* pass on the initial headers to SID 1 */\n\t\t\th2n-\u003eswsi-\u003ehttp.ah \u003d wsi-\u003ehttp.ah;\n#if defined(LWS_WITH_SYS_FAULT_INJECTION)\n\t\t\tlws_fi_import(\u0026h2n-\u003eswsi-\u003efic, \u0026wsi-\u003efic);\n#endif\n\t\t\th2n-\u003eswsi-\u003eclient_mux_substream \u003d 1;\n\t\t\th2n-\u003eswsi-\u003eclient_h2_alpn \u003d 1;\n#if defined(LWS_WITH_CLIENT)\n\t\t\th2n-\u003eswsi-\u003eflags \u003d wsi-\u003eflags;\n#if defined(LWS_WITH_CONMON)\n\t\t\t/* sid1 needs to represent the connection experience\n\t\t\t * ... we take over responsibility for the DNS list\n\t\t\t * copy as well\n\t\t\t */\n\t\t\th2n-\u003eswsi-\u003econmon \u003d wsi-\u003econmon;\n\t\t\th2n-\u003eswsi-\u003econmon_datum \u003d wsi-\u003econmon_datum;\n\t\t\th2n-\u003eswsi-\u003esa46_peer \u003d wsi-\u003esa46_peer;\n\t\t\twsi-\u003econmon.dns_results_copy \u003d NULL;\n#endif\n#endif /* CLIENT */\n\n#if defined(LWS_WITH_SECURE_STREAMS)\n\t\t\tif (wsi-\u003efor_ss) {\n\t\t\t\tlws_ss_handle_t *h \u003d (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);\n\n\t\t\t\th2n-\u003eswsi-\u003efor_ss \u003d 1;\n\t\t\t\twsi-\u003efor_ss \u003d 0;\n\n\t\t\t\tif (h-\u003ewsi \u003d\u003d wsi)\n\t\t\t\t\th-\u003ewsi \u003d h2n-\u003eswsi;\n\t\t\t}\n#endif\n\n\t\t\th2n-\u003eswsi-\u003ea.protocol \u003d wsi-\u003ea.protocol;\n\t\t\tif (h2n-\u003eswsi-\u003euser_space \u0026\u0026\n\t\t\t !h2n-\u003eswsi-\u003euser_space_externally_allocated)\n\t\t\t\tlws_free(h2n-\u003eswsi-\u003euser_space);\n\t\t\th2n-\u003eswsi-\u003euser_space \u003d wsi-\u003euser_space;\n\t\t\th2n-\u003eswsi-\u003euser_space_externally_allocated \u003d\n\t\t\t\t\twsi-\u003euser_space_externally_allocated;\n\t\t\th2n-\u003eswsi-\u003ea.opaque_user_data \u003d wsi-\u003ea.opaque_user_data;\n\t\t\twsi-\u003ea.opaque_user_data \u003d NULL;\n\t\t\th2n-\u003eswsi-\u003etxc.manual_initial_tx_credit \u003d\n\t\t\t\t\twsi-\u003etxc.manual_initial_tx_credit;\n\n#if defined(LWS_WITH_TLS)\n\t\t\tlws_strncpy(h2n-\u003eswsi-\u003ealpn, wsi-\u003ealpn,\n\t\t\t\t\tsizeof(wsi-\u003ealpn));\n#endif\n\n\t\t\twsi-\u003euser_space \u003d NULL;\n\n\t\t\tif (h2n-\u003eswsi-\u003ehttp.ah)\n\t\t\t\th2n-\u003eswsi-\u003ehttp.ah-\u003ewsi \u003d h2n-\u003eswsi;\n\t\t\twsi-\u003ehttp.ah \u003d NULL;\n\n\t\t\tlwsl_info(\u0022%s: MIGRATING nwsi %s -\u003e swsi %s\u005cn\u0022, __func__,\n\t\t\t\t lws_wsi_tag(wsi), lws_wsi_tag(h2n-\u003eswsi));\n\t\t\th2n-\u003eswsi-\u003etxc.tx_cr \u003d (int32_t)\n\t\t\t\th2n-\u003epeer_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\t\t\tlwsl_info(\u0022%s: initial tx credit on %s: %d\u005cn\u0022,\n\t\t\t\t __func__, lws_wsi_tag(h2n-\u003eswsi),\n\t\t\t\t (int)h2n-\u003eswsi-\u003etxc.tx_cr);\n\t\t\th2n-\u003eswsi-\u003eh2.initialized \u003d 1;\n\n\t\t\t/* set our initial window size */\n\t\t\tif (!wsi-\u003eh2.initialized) {\n\t\t\t\twsi-\u003etxc.tx_cr \u003d (int32_t)\n\t\t\t\t h2n-\u003epeer_set.s[H2SET_INITIAL_WINDOW_SIZE];\n\n\t\t\t\tlwsl_info(\u0022%s: initial tx credit for us to \u0022\n\t\t\t\t\t \u0022write on nwsi %s: %d\u005cn\u0022, __func__,\n\t\t\t\t\t lws_wsi_tag(wsi), (int)wsi-\u003etxc.tx_cr);\n\t\t\t\twsi-\u003eh2.initialized \u003d 1;\n\t\t\t}\n\n\t\t\tlws_callback_on_writable(h2n-\u003eswsi);\n\n\t\t\tif (!wsi-\u003eh2_acked_settings ||\n\t\t\t !(wsi-\u003eflags \u0026 LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM)\n\t\t\t) {\n\t\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS);\n\t\t\t\tif (!pps)\n\t\t\t\t\treturn 1;\n\t\t\t\tlws_pps_schedule(wsi, pps);\n\t\t\t\tlwsl_info(\u0022%s: SETTINGS ack PPS\u005cn\u0022, __func__);\n\t\t\t\twsi-\u003eh2_acked_settings \u003d 1;\n\t\t\t}\n\n\t\t\t/* also attach any queued guys */\n\n\t\t\tlws_wsi_mux_apply_queue(wsi);\n\t\t}\n#endif\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n\tcase LWS_H2_FRAME_TYPE_HEADERS:\n\n\t\tif (!h2n-\u003eswsi)\n\t\t\tbreak;\n\n\t\t/* service the http request itself */\n\n\t\tif (h2n-\u003elast_action_dyntable_resize) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n\t\t\t\t\u0022dyntable resize last in headers\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!h2n-\u003eswsi-\u003eh2.END_HEADERS) {\n\t\t\t/* we are not finished yet */\n\t\t\tlwsl_info(\u0022withholding http action for continuation\u005cn\u0022);\n\t\t\th2n-\u003econt_exp_sid \u003d h2n-\u003esid;\n\t\t\th2n-\u003econt_exp \u003d 1;\n\t\t\tbreak;\n\t\t}\n\n\t\t/* confirm the hpack stream state is reasonable for finishing */\n\n\t\tif (h2n-\u003ehpack !\u003d HPKS_TYPE) {\n\t\t\t/* hpack incomplete */\n\t\t\tlwsl_info(\u0022hpack incomplete %d (type %d, len %u)\u005cn\u0022,\n\t\t\t\t h2n-\u003ehpack, h2n-\u003etype,\n\t\t\t\t (unsigned int)h2n-\u003ehpack_len);\n\t\t\tlws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,\n\t\t\t\t \u0022hpack incomplete\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\t/* this is the last part of HEADERS */\n\t\tswitch (h2n-\u003eswsi-\u003eh2.h2_state) {\n\t\tcase LWS_H2_STATE_IDLE:\n\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_OPEN);\n\t\t\tbreak;\n\t\tcase LWS_H2_STATE_RESERVED_REMOTE:\n\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_HALF_CLOSED_LOCAL);\n\t\t\tbreak;\n\t\t}\n\n\t\tlwsl_info(\u0022http req, %s, h2n-\u003eswsi\u003d%s\u005cn\u0022, lws_wsi_tag(wsi),\n\t\t\t\tlws_wsi_tag(h2n-\u003eswsi));\n\t\th2n-\u003eswsi-\u003ehdr_parsing_completed \u003d 1;\n\n#if defined(LWS_WITH_CLIENT)\n\t\tif (h2n-\u003eswsi-\u003eclient_mux_substream \u0026\u0026\n\t\t lws_client_interpret_server_handshake(h2n-\u003eswsi)) {\n\t\t\t/*\n\t\t\t * This is more complicated than it looks, one exit from\n\t\t\t * interpret_server_handshake() is to do a close that\n\t\t\t * turns into a redirect.\n\t\t\t *\n\t\t\t * In that case, the wsi survives having being reset\n\t\t\t * and detached from any h2 identity. We need to get\n\t\t\t * our parents out from touching it any more\n\t\t\t */\n\t\t\tlwsl_info(\u0022%s: cli int serv hs closed, or redir\u005cn\u0022, __func__);\n\t\t\treturn 2;\n\t\t}\n#endif\n\n\t\tif (lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n\t\t\tconst char *simp \u003d lws_hdr_simple_ptr(h2n-\u003eswsi,\n\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH);\n\n\t\t\tif (!simp) /* coverity */\n\t\t\t\treturn 1;\n\t\t\th2n-\u003eswsi-\u003ehttp.rx_content_length \u003d (unsigned long long)atoll(simp);\n\t\t\th2n-\u003eswsi-\u003ehttp.rx_content_remain \u003d\n\t\t\t\t\th2n-\u003eswsi-\u003ehttp.rx_content_length;\n\t\t\th2n-\u003eswsi-\u003ehttp.content_length_given \u003d 1;\n\t\t\tlwsl_info(\u0022setting rx_content_length %lld\u005cn\u0022,\n\t\t\t\t (long long)h2n-\u003eswsi-\u003ehttp.rx_content_length);\n\t\t}\n\n\t\t{\n\t\t\tint n \u003d 0, len;\n\t\t\tchar buf[256];\n\t\t\tconst unsigned char *c;\n\n\t\t\tdo {\n\t\t\t\tc \u003d lws_token_to_string((enum lws_token_indexes)n);\n\t\t\t\tif (!c) {\n\t\t\t\t\tn++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlen \u003d lws_hdr_total_length(h2n-\u003eswsi, (enum lws_token_indexes)n);\n\t\t\t\tif (!len || len \u003e (int)sizeof(buf) - 1) {\n\t\t\t\t\tn++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (lws_hdr_copy(h2n-\u003eswsi, buf, sizeof buf,\n\t\t\t\t\t\t(enum lws_token_indexes)n) \u003c 0) {\n\t\t\t\t\tlwsl_info(\u0022 %s !oversize!\u005cn\u0022,\n\t\t\t\t\t\t (char *)c);\n\t\t\t\t} else {\n\t\t\t\t\tbuf[sizeof(buf) - 1] \u003d '\u005c0';\n\n\t\t\t\t\tlwsl_info(\u0022 %s \u003d %s\u005cn\u0022,\n\t\t\t\t\t\t (char *)c, buf);\n\t\t\t\t}\n\t\t\t\tn++;\n\t\t\t} while (c);\n\t\t}\n\n\t\tif (h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_REMOTE ||\n\t\t h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,\n\t\t\t\t \u0022Banning service on CLOSED_REMOTE\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tswitch (h2n-\u003eswsi-\u003eh2.h2_state) {\n\t\tcase LWS_H2_STATE_IDLE:\n\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_OPEN);\n\t\t\tbreak;\n\t\tcase LWS_H2_STATE_OPEN:\n\t\t\tif (h2n-\u003eswsi-\u003eh2.END_STREAM)\n\t\t\t\tlws_h2_state(h2n-\u003eswsi,\n\t\t\t\t\t LWS_H2_STATE_HALF_CLOSED_REMOTE);\n\t\t\tbreak;\n\t\tcase LWS_H2_STATE_HALF_CLOSED_LOCAL:\n\t\t\tif (h2n-\u003eswsi-\u003eh2.END_STREAM)\n\t\t\t\t/*\n\t\t\t\t * action the END_STREAM\n\t\t\t\t */\n\t\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n\t\t\tbreak;\n\t\t}\n\n#if defined(LWS_WITH_CLIENT)\n\n\t\t/*\n\t\t * If we already had the END_STREAM along with the END_HEADERS,\n\t\t * we have already transitioned to STATE_CLOSED and we are not\n\t\t * going to be doing anything further on this stream.\n\t\t *\n\t\t * In that case handle the transaction completion and\n\t\t * finalize the stream for the peer\n\t\t */\n\n\t\tif (h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_CLOSED \u0026\u0026\n\t\t\th2n-\u003eswsi-\u003eclient_mux_substream) {\n\n\t\t\tlws_h2_rst_stream(h2n-\u003eswsi, H2_ERR_NO_ERROR,\n\t\t\t\t\u0022client done\u0022);\n\n\t\t\tif (lws_http_transaction_completed_client(h2n-\u003eswsi))\n\t\t\t\tlwsl_debug(\u0022tx completed returned close\u005cn\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (h2n-\u003eswsi-\u003eclient_mux_substream) {\n\t\t\tlwsl_info(\u0022%s: %s: headers: client path (h2 state %s)\u005cn\u0022,\n\t\t\t\t __func__, lws_wsi_tag(wsi),\n\t\t\t\t h2_state_names[h2n-\u003eswsi-\u003eh2.h2_state]);\n\t\t\tbreak;\n\t\t}\n#endif\n\n\t\tif (!lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_PATH) ||\n\t\t !lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_METHOD) ||\n\t\t !lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_SCHEME) ||\n\t\t lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_STATUS) ||\n\t\t lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_CONNECTION)) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022Pseudoheader checks\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (lws_hdr_extant(h2n-\u003eswsi, WSI_TOKEN_TE)) {\n\t\t\tn \u003d lws_hdr_total_length(h2n-\u003eswsi, WSI_TOKEN_TE);\n\n\t\t\tif (n !\u003d 8 ||\n\t\t\t !lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_TE) ||\n\t\t\t strncmp(lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_TE),\n\t\t\t\t \u0022trailers\u0022, (unsigned int)n)) {\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022Illegal transfer-encoding\u0022);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)\n\t\tlws_http_compression_validate(h2n-\u003eswsi);\n#endif\n\n\t\tp \u003d lws_hdr_simple_ptr(h2n-\u003eswsi, WSI_TOKEN_HTTP_COLON_METHOD);\n\t\t/*\n\t\t * duplicate :path into the individual method uri header\n\t\t * index, so that it looks the same as h1 in the ah\n\t\t */\n\t\tfor (n \u003d 0; n \u003c (int)LWS_ARRAY_SIZE(method_names); n++)\n\t\t\tif (p \u0026\u0026 !strcasecmp(p, method_names[n])) {\n\t\t\t\th2n-\u003eswsi-\u003ehttp.ah-\u003efrag_index[method_index[n]] \u003d\n\t\t\t\t\t\th2n-\u003eswsi-\u003ehttp.ah-\u003efrag_index[\n\t\t\t\t WSI_TOKEN_HTTP_COLON_PATH];\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t{\n\t\t\tlwsl_debug(\u0022%s: setting DEF_ACT from 0x%x\u005cn\u0022, __func__,\n\t\t\t\t (unsigned int)h2n-\u003eswsi-\u003ewsistate);\n\t\t\tlwsi_set_state(h2n-\u003eswsi, LRS_DEFERRING_ACTION);\n\t\t\tlws_callback_on_writable(h2n-\u003eswsi);\n\t\t}\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_DATA:\n\t\tlwsl_info(\u0022%s: DATA flags 0x%x\u005cn\u0022, __func__, h2n-\u003eflags);\n\t\tif (!h2n-\u003eswsi)\n\t\t\tbreak;\n\n\t\tif (lws_hdr_total_length(h2n-\u003eswsi,\n\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH) \u0026\u0026\n\t\t h2n-\u003eswsi-\u003eh2.END_STREAM \u0026\u0026\n\t\t h2n-\u003eswsi-\u003ehttp.rx_content_length \u0026\u0026\n\t\t h2n-\u003eswsi-\u003ehttp.rx_content_remain) {\n\t\t\tlws_h2_rst_stream(h2n-\u003eswsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022Not enough rx content\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (h2n-\u003eswsi-\u003eh2.END_STREAM \u0026\u0026\n\t\t h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_OPEN)\n\t\t\tlws_h2_state(h2n-\u003eswsi,\n\t\t\t\t LWS_H2_STATE_HALF_CLOSED_REMOTE);\n\n\t\tif (h2n-\u003eswsi-\u003eh2.END_STREAM \u0026\u0026\n\t\t h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_LOCAL)\n\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n\n#if defined(LWS_WITH_CLIENT)\n\t\t/*\n\t\t * client... remote END_STREAM implies we weren't going to\n\t\t * send anything else anyway.\n\t\t */\n\n\t\tif (h2n-\u003eswsi-\u003eclient_mux_substream \u0026\u0026\n\t\t (h2n-\u003eflags \u0026 LWS_H2_FLAG_END_STREAM)) {\n\t\t\tlwsl_info(\u0022%s: %s: DATA: end stream\u005cn\u0022,\n\t\t\t\t __func__, lws_wsi_tag(h2n-\u003eswsi));\n\n\t\t\tif (h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_OPEN) {\n\t\t\t\tlws_h2_state(h2n-\u003eswsi,\n\t\t\t\t\t LWS_H2_STATE_HALF_CLOSED_REMOTE);\n\t\t//\t\tlws_h2_rst_stream(h2n-\u003eswsi, H2_ERR_NO_ERROR,\n\t\t//\t\t\t\t \u0022client done\u0022);\n\n\t\t//\t\tif (lws_http_transaction_completed_client(h2n-\u003eswsi))\n\t\t//\t\t\tlwsl_debug(\u0022tx completed returned close\u005cn\u0022);\n\t\t\t}\n\n\t\t\t//if (h2n-\u003eswsi-\u003eh2.h2_state \u003d\u003d LWS_H2_STATE_HALF_CLOSED_LOCAL)\n\t\t\t{\n\t\t\t\tlws_h2_state(h2n-\u003eswsi, LWS_H2_STATE_CLOSED);\n\n\t\t\t\tlws_h2_rst_stream(h2n-\u003eswsi, H2_ERR_NO_ERROR,\n\t\t\t\t\t\t \u0022client done\u0022);\n\n\t\t\t\tif (lws_http_transaction_completed_client(h2n-\u003eswsi))\n\t\t\t\t\tlwsl_debug(\u0022tx completed returned close\u005cn\u0022);\n\t\t\t}\n\t\t}\n#endif\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_PING:\n\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK)\n\t\t\tlws_validity_confirmed(wsi);\n\t\telse {\n\t\t\t/* they're sending us a ping request */\n\t\t\tstruct lws_h2_protocol_send *pps \u003d\n\t\t\t\t\tlws_h2_new_pps(LWS_H2_PPS_PONG);\n\t\t\tif (!pps)\n\t\t\t\treturn 1;\n\n\t\t\tlwsl_info(\u0022rx ping, preparing pong\u005cn\u0022);\n\n\t\t\tmemcpy(pps-\u003eu.ping.ping_payload, h2n-\u003eping_payload, 8);\n\t\t\tlws_pps_schedule(wsi, pps);\n\t\t}\n\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n\t\t/*\n\t\t * We only have an unsigned 31-bit (positive) increment possible\n\t\t */\n\t\th2n-\u003ehpack_e_dep \u0026\u003d ~(1u \u003c\u003c 31);\n\t\tlwsl_info(\u0022WINDOW_UPDATE: sid %u %u (0x%x)\u005cn\u0022,\n\t\t\t (unsigned int)h2n-\u003esid,\n\t\t\t (unsigned int)h2n-\u003ehpack_e_dep,\n\t\t\t (unsigned int)h2n-\u003ehpack_e_dep);\n\n\t\tif (h2n-\u003esid)\n\t\t\teff_wsi \u003d h2n-\u003eswsi;\n\n\t\tif (!eff_wsi) {\n\t\t\tif (h2n-\u003esid \u003e h2n-\u003ehighest_sid_opened)\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022alien sid\u0022);\n\t\t\tbreak; /* ignore */\n\t\t}\n\n\t\tif (eff_wsi-\u003ea.vhost-\u003eoptions \u0026\n\t\t LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW \u0026\u0026\n\t\t (uint64_t)eff_wsi-\u003etxc.tx_cr + (uint64_t)h2n-\u003ehpack_e_dep \u003e\n\t\t (uint64_t)0x7fffffff)\n\t\t\th2n-\u003ehpack_e_dep \u003d (uint32_t)(0x7fffffff - eff_wsi-\u003etxc.tx_cr);\n\n\t\tif ((uint64_t)eff_wsi-\u003etxc.tx_cr + (uint64_t)h2n-\u003ehpack_e_dep \u003e\n\t\t (uint64_t)0x7fffffff) {\n\t\t\tlwsl_warn(\u0022%s: WINDOW_UPDATE 0x%llx + 0x%llx \u003d 0x%llx, too high\u005cn\u0022,\n\t\t\t\t\t__func__, (unsigned long long)eff_wsi-\u003etxc.tx_cr,\n\t\t\t\t\t(unsigned long long)h2n-\u003ehpack_e_dep,\n\t\t\t\t\t(unsigned long long)eff_wsi-\u003etxc.tx_cr + (unsigned long long)h2n-\u003ehpack_e_dep);\n\t\t\tif (h2n-\u003esid)\n\t\t\t\tlws_h2_rst_stream(h2n-\u003eswsi,\n\t\t\t\t\t\t H2_ERR_FLOW_CONTROL_ERROR,\n\t\t\t\t\t\t \u0022Flow control exceeded max\u0022);\n\t\t\telse\n\t\t\t\tlws_h2_goaway(wsi, H2_ERR_FLOW_CONTROL_ERROR,\n\t\t\t\t\t \u0022Flow control exceeded max\u0022);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!h2n-\u003ehpack_e_dep) {\n\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t \u0022Zero length window update\u0022);\n\t\t\tbreak;\n\t\t}\n\t\tn \u003d eff_wsi-\u003etxc.tx_cr;\n\t\teff_wsi-\u003etxc.tx_cr +\u003d (int32_t)h2n-\u003ehpack_e_dep;\n\n\t\tlws_wsi_txc_report_manual_txcr_in(eff_wsi,\n\t\t\t\t\t\t (int32_t)h2n-\u003ehpack_e_dep);\n\n\t\tlws_wsi_txc_describe(\u0026eff_wsi-\u003etxc, \u0022WINDOW_UPDATE in\u0022,\n\t\t\t\t eff_wsi-\u003emux.my_sid);\n\n\t\tif (n \u003c\u003d 0 \u0026\u0026 eff_wsi-\u003etxc.tx_cr \u003c\u003d 0)\n\t\t\t/* it helps, but won't change sendability for anyone */\n\t\t\tbreak;\n\n\t\t/*\n\t\t * It may have changed sendability (depends on SID 0 tx credit\n\t\t * too)... for us and any children waiting on us... reassess\n\t\t * blockage for all children first\n\t\t */\n\t\tlws_start_foreach_ll(struct lws *, w, wsi-\u003emux.child_list) {\n\t\t\tlws_callback_on_writable(w);\n\t\t} lws_end_foreach_ll(w, mux.sibling_list);\n\n\t\tif (eff_wsi-\u003etxc.skint \u0026\u0026\n\t\t !lws_wsi_txc_check_skint(\u0026eff_wsi-\u003etxc,\n\t\t\t\t\t lws_h2_tx_cr_get(eff_wsi)))\n\t\t\t/*\n\t\t\t * This one became un-skint, schedule a writeable\n\t\t\t * callback\n\t\t\t */\n\t\t\tlws_callback_on_writable(eff_wsi);\n\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n\t\tlwsl_notice(\u0022GOAWAY: last sid %u, error 0x%08X, string '%s'\u005cn\u0022,\n\t\t\t (unsigned int)h2n-\u003egoaway_last_sid,\n\t\t\t (unsigned int)h2n-\u003egoaway_err, h2n-\u003egoaway_str);\n\n\t\treturn 1;\n\n\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n\t\tlwsl_info(\u0022LWS_H2_FRAME_TYPE_RST_STREAM: sid %u: reason 0x%x\u005cn\u0022,\n\t\t\t (unsigned int)h2n-\u003esid,\n\t\t\t (unsigned int)h2n-\u003ehpack_e_dep);\n\t\tbreak;\n\n\tcase LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\n/*\n * This may want to send something on the network wsi, which may be in the\n * middle of a partial send. PPS sends are OK because they are queued to\n * go through the WRITABLE handler already.\n *\n * The read parser for the network wsi has no choice but to parse its stream\n * anyway, because otherwise it will not be able to get tx credit window\n * messages.\n *\n * Therefore if we will send non-PPS, ie, lws_http_action() for a stream\n * wsi, we must change its state and handle it as a priority in the\n * POLLOUT handler instead of writing it here.\n *\n * About closing... for the main network wsi, it should return nonzero to\n * close it all. If it needs to close an swsi, it can do it here.\n */\nint\nlws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t _inlen,\n\t lws_filepos_t *inused)\n{\n\tstruct lws_h2_netconn *h2n \u003d wsi-\u003eh2.h2n;\n\tstruct lws_h2_protocol_send *pps;\n\tunsigned char c, *oldin \u003d in, *iend \u003d in + (size_t)_inlen;\n\tint n, m;\n\n\tif (!h2n)\n\t\tgoto fail;\n\n\twhile (in \u003c iend) {\n\n\t\tc \u003d *in++;\n\n\t\tswitch (lwsi_state(wsi)) {\n\t\tcase LRS_H2_AWAIT_PREFACE:\n\t\t\tif (preface[h2n-\u003ecount++] !\u003d c)\n\t\t\t\tgoto fail;\n\n\t\t\tif (preface[h2n-\u003ecount])\n\t\t\t\tbreak;\n\n\t\t\tlwsl_info(\u0022http2: %s: established\u005cn\u0022, lws_wsi_tag(wsi));\n\t\t\tlwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS);\n\t\t\tlws_validity_confirmed(wsi);\n\t\t\th2n-\u003ecount \u003d 0;\n\t\t\twsi-\u003etxc.tx_cr \u003d 65535;\n\n\t\t\t/*\n\t\t\t * we must send a settings frame -- empty one is OK...\n\t\t\t * that must be the first thing sent by server\n\t\t\t * and the peer must send a SETTINGS with ACK flag...\n\t\t\t */\n\t\t\tpps \u003d lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS);\n\t\t\tif (!pps)\n\t\t\t\tgoto fail;\n\t\t\tlws_pps_schedule(wsi, pps);\n\t\t\tbreak;\n\n\t\tcase LRS_H2_WAITING_TO_SEND_HEADERS:\n\t\tcase LRS_ESTABLISHED:\n\t\tcase LRS_H2_AWAIT_SETTINGS:\n\n\t\t\tif (h2n-\u003eframe_state !\u003d LWS_H2_FRAME_HEADER_LENGTH)\n\t\t\t\tgoto try_frame_start;\n\n\t\t\t/*\n\t\t\t * post-header, preamble / payload / padding part\n\t\t\t */\n\t\t\th2n-\u003ecount++;\n\n\t\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */\n\t\t\t\t//lwsl_debug(\u0022%s: consuming for ignored %u %u\u005cn\u0022, __func__, (unsigned int)h2n-\u003ecount, (unsigned int)h2n-\u003elength);\n\t\t\t\tgoto frame_end;\n\t\t\t}\n\n\n\t\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_PADDED \u0026\u0026\n\t\t\t !h2n-\u003epad_length) {\n\t\t\t\t/*\n\t\t\t\t * Get the padding count... actual padding is\n\t\t\t\t * at the end of the frame.\n\t\t\t\t */\n\t\t\t\th2n-\u003epadding \u003d c;\n\t\t\t\th2n-\u003epad_length \u003d 1;\n\t\t\t\th2n-\u003epreamble++;\n\n\t\t\t\tif (h2n-\u003epadding \u003e h2n-\u003elength - 1)\n\t\t\t\t\tlws_h2_goaway(wsi,\n\t\t\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t\t \u0022execssive padding\u0022);\n\t\t\t\tbreak; /* we consumed this */\n\t\t\t}\n\n\t\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_PRIORITY \u0026\u0026\n\t\t\t !h2n-\u003ecollected_priority) {\n\t\t\t\t/* going to be 5 preamble bytes */\n\n\t\t\t\tlwsl_debug(\u0022PRIORITY FLAG: 0x%x\u005cn\u0022, c);\n\n\t\t\t\tif (h2n-\u003epreamble++ - h2n-\u003epad_length \u003c 4) {\n\t\t\t\t\th2n-\u003edep \u003d ((h2n-\u003edep) \u003c\u003c 8) | c;\n\t\t\t\t\tbreak; /* we consumed this */\n\t\t\t\t}\n\t\t\t\th2n-\u003eweight_temp \u003d c;\n\t\t\t\th2n-\u003ecollected_priority \u003d 1;\n\t\t\t\tlwsl_debug(\u0022PRI FL: dep 0x%x, weight 0x%02X\u005cn\u0022,\n\t\t\t\t\t (unsigned int)h2n-\u003edep,\n\t\t\t\t\t h2n-\u003eweight_temp);\n\t\t\t\tbreak; /* we consumed this */\n\t\t\t}\n\t\t\tif (h2n-\u003epadding \u0026\u0026 h2n-\u003ecount \u003e\n\t\t\t (h2n-\u003elength - h2n-\u003epadding)) {\n\t\t\t\tif (c) {\n\t\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t\t \u0022nonzero padding\u0022);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tgoto frame_end;\n\t\t\t}\n\n\t\t\t/* applies to wsi-\u003eh2.swsi which may be wsi */\n\t\t\tswitch(h2n-\u003etype) {\n\n\t\t\tcase LWS_H2_FRAME_TYPE_SETTINGS:\n\t\t\t\tn \u003d (int)(h2n-\u003ecount - 1u - h2n-\u003epreamble) %\n\t\t\t\t LWS_H2_SETTINGS_LEN;\n\t\t\t\th2n-\u003eone_setting[n] \u003d c;\n\t\t\t\tif (n !\u003d LWS_H2_SETTINGS_LEN - 1)\n\t\t\t\t\tbreak;\n\t\t\t\tlws_h2_settings(wsi, \u0026h2n-\u003epeer_set,\n\t\t\t\t\t\th2n-\u003eone_setting,\n\t\t\t\t\t\tLWS_H2_SETTINGS_LEN);\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_CONTINUATION:\n\t\t\tcase LWS_H2_FRAME_TYPE_HEADERS:\n\t\t\t\tif (!h2n-\u003eswsi)\n\t\t\t\t\tbreak;\n\t\t\t\tif (lws_hpack_interpret(h2n-\u003eswsi, c)) {\n\t\t\t\t\tlwsl_info(\u0022%s: hpack failed\u005cn\u0022,\n\t\t\t\t\t\t __func__);\n\t\t\t\t\tgoto fail;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_GOAWAY:\n\t\t\t\tswitch (h2n-\u003einside++) {\n\t\t\t\tcase 0:\n\t\t\t\tcase 1:\n\t\t\t\tcase 2:\n\t\t\t\tcase 3:\n\t\t\t\t\th2n-\u003egoaway_last_sid \u003c\u003c\u003d 8;\n\t\t\t\t\th2n-\u003egoaway_last_sid |\u003d c;\n\t\t\t\t\th2n-\u003egoaway_str[0] \u003d '\u005c0';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 4:\n\t\t\t\tcase 5:\n\t\t\t\tcase 6:\n\t\t\t\tcase 7:\n\t\t\t\t\th2n-\u003egoaway_err \u003c\u003c\u003d 8;\n\t\t\t\t\th2n-\u003egoaway_err |\u003d c;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif (h2n-\u003einside - 9 \u003c\n\t\t\t\t\t sizeof(h2n-\u003egoaway_str) - 1)\n\t\t\t\t\t\th2n-\u003egoaway_str[\n\t\t\t\t\t\t h2n-\u003einside - 9] \u003d (char)c;\n\t\t\t\t\th2n-\u003egoaway_str[\n\t\t\t\t\t sizeof(h2n-\u003egoaway_str) - 1] \u003d '\u005c0';\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_DATA:\n\n\t\t\t//\tlwsl_info(\u0022%s: LWS_H2_FRAME_TYPE_DATA: fl 0x%x\u005cn\u0022,\n\t\t\t//\t\t __func__, h2n-\u003eflags);\n\n\t\t\t\t/*\n\t\t\t\t * let the network wsi live a bit longer if\n\t\t\t\t * subs are active... our frame may take a long\n\t\t\t\t * time to chew through\n\t\t\t\t */\n\t\t\t\tif (!wsi-\u003eimmortal_substream_count)\n\t\t\t\t\tlws_set_timeout(wsi,\n\t\t\t\t\tPENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE,\n\t\t\t\t\t\twsi-\u003ea.vhost-\u003ekeepalive_timeout ?\n\t\t\t\t\t wsi-\u003ea.vhost-\u003ekeepalive_timeout : 31);\n\n\t\t\t\tif (!h2n-\u003eswsi)\n\t\t\t\t\tbreak;\n\n\t\t\t\tif (lws_buflist_next_segment_len(\n\t\t\t\t\t\t\u0026h2n-\u003eswsi-\u003ebuflist, NULL))\n\t\t\t\t\tlwsl_info(\u0022%s: substream has pending\u005cn\u0022,\n\t\t\t\t\t\t __func__);\n\n\t\t\t\tif (lwsi_role_http(h2n-\u003eswsi) \u0026\u0026\n\t\t\t\t lwsi_state(h2n-\u003eswsi) \u003d\u003d LRS_ESTABLISHED) {\n\t\t\t\t\tlwsi_set_state(h2n-\u003eswsi, LRS_BODY);\n\t\t\t\t\tlwsl_info(\u0022%s: %s to LRS_BODY\u005cn\u0022,\n\t\t\t\t\t\t\t__func__, lws_wsi_tag(h2n-\u003eswsi));\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t * in + length may cover multiple frames, we\n\t\t\t\t * can only consider the length of the DATA\n\t\t\t\t * in front of us\n\t\t\t\t */\n\n\t\t\t\tif (lws_hdr_total_length(h2n-\u003eswsi,\n\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH) \u0026\u0026\n\t\t\t\t h2n-\u003eswsi-\u003ehttp.rx_content_length \u0026\u0026\n\t\t\t\t h2n-\u003eswsi-\u003ehttp.rx_content_remain \u003c\n\t\t\t\t\t\t h2n-\u003elength - h2n-\u003einside \u0026\u0026 /* last */\n\t\t\t\t h2n-\u003einside \u003c h2n-\u003elength) {\n\n\t\t\t\t\tlwsl_warn(\u0022%s: rx.cl: %lu, rx.content_remain: %lu, buf left: %lu, \u0022\n\t\t\t\t\t\t \u0022h2-\u003einside: %lu, h2-\u003elength: %lu\u005cn\u0022, __func__,\n\t\t\t\t\t\t (unsigned long)h2n-\u003eswsi-\u003ehttp.rx_content_length,\n\t\t\t\t\t\t (unsigned long)h2n-\u003eswsi-\u003ehttp.rx_content_remain,\n\t\t\t\t\t\t (unsigned long)(lws_ptr_diff_size_t(iend, in) + 1),\n\t\t\t\t\t\t (unsigned long)h2n-\u003einside, (unsigned long)h2n-\u003elength);\n\n\t\t\t\t\t/* unread data in frame */\n\t\t\t\t\tlws_h2_goaway(wsi,\n\t\t\t\t\t\t H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t \u0022More rx than content_length told\u0022);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t/*\n\t\t\t\t * We operate on a frame. The RX we have at\n\t\t\t\t * hand may exceed the current frame.\n\t\t\t\t */\n\n\t\t\t\tn \u003d (int)lws_ptr_diff_size_t(iend, in) + 1;\n\t\t\t\tif (n \u003e (int)(h2n-\u003elength - h2n-\u003ecount + 1)) {\n\t\t\t\t\tif (h2n-\u003ecount \u003e h2n-\u003elength)\n\t\t\t\t\t\tgoto close_swsi_and_return;\n\t\t\t\t\tn \u003d (int)(h2n-\u003elength - h2n-\u003ecount) + 1;\n\t\t\t\t\tlwsl_debug(\u0022---- restricting len to %d \u0022\n\t\t\t\t\t\t \u0022\u005cn\u0022, n);\n\t\t\t\t}\n#if defined(LWS_WITH_CLIENT)\n\t\t\t\tif (h2n-\u003eswsi-\u003eclient_mux_substream) {\n\t\t\t\t\tif (!h2n-\u003eswsi-\u003ea.protocol) {\n\t\t\t\t\t\tlwsl_err(\u0022%s: %p doesn't have protocol\u005cn\u0022,\n\t\t\t\t\t\t\t __func__, lws_wsi_tag(h2n-\u003eswsi));\n\t\t\t\t\t\tm \u003d 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\th2n-\u003eswsi-\u003etxc.peer_tx_cr_est -\u003d n;\n\t\t\t\t\t\twsi-\u003etxc.peer_tx_cr_est -\u003d n;\n\t\t\t\t\t\tlws_wsi_txc_describe(\u0026h2n-\u003eswsi-\u003etxc,\n\t\t\t\t\t\t\t__func__,\n\t\t\t\t\t\t\th2n-\u003eswsi-\u003emux.my_sid);\n\t\t\t\t\tm \u003d user_callback_handle_rxflow(\n\t\t\t\t\t\th2n-\u003eswsi-\u003ea.protocol-\u003ecallback,\n\t\t\t\t\t\th2n-\u003eswsi,\n\t\t\t\t\t LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,\n\t\t\t\t\t\th2n-\u003eswsi-\u003euser_space,\n\t\t\t\t\t\tin - 1, (unsigned int)n);\n\t\t\t\t\t}\n\n\t\t\t\t\tin +\u003d n - 1;\n\t\t\t\t\th2n-\u003einside +\u003d (unsigned int)n;\n\t\t\t\t\th2n-\u003ecount +\u003d (unsigned int)n - 1;\n\n\t\t\t\t\tif (m) {\n\t\t\t\t\t\tlwsl_info(\u0022RECEIVE_CLIENT_HTTP \u0022\n\t\t\t\t\t\t\t \u0022closed it\u005cn\u0022);\n\t\t\t\t\t\tgoto close_swsi_and_return;\n\t\t\t\t\t}\n\n\t\t\t\t\tgoto do_windows;\n\t\t\t\t}\n#endif\n\t\t\t\tif (lwsi_state(h2n-\u003eswsi) \u003d\u003d LRS_DEFERRING_ACTION) {\n\t\t\t\t\tm \u003d lws_buflist_append_segment(\n\t\t\t\t\t\t\u0026h2n-\u003eswsi-\u003ebuflist, in - 1, (unsigned int)n);\n\t\t\t\t\tif (m \u003c 0)\n\t\t\t\t\t\treturn -1;\n\n\t\t\t\t\t/*\n\t\t\t\t\t * Since we're in an open-ended\n\t\t\t\t\t * DEFERRING_ACTION, don't add this swsi\n\t\t\t\t\t * to the pt list of wsi holding buflist\n\t\t\t\t\t * content yet, we are not in a position\n\t\t\t\t\t * to consume it until we get out of\n\t\t\t\t\t * DEFERRING_ACTION.\n\t\t\t\t\t */\n\n\t\t\t\t\tin +\u003d n - 1;\n\t\t\t\t\th2n-\u003einside +\u003d (unsigned int)n;\n\t\t\t\t\th2n-\u003ecount +\u003d (unsigned int)n - 1;\n\n\t\t\t\t\tlwsl_debug(\u0022%s: deferred %d\u005cn\u0022, __func__, n);\n\t\t\t\t\tgoto do_windows;\n\t\t\t\t}\n\n\t\t\t\th2n-\u003eswsi-\u003eouter_will_close \u003d 1;\n\t\t\t\t/*\n\t\t\t\t * choose the length for this go so that we end at\n\t\t\t\t * the frame boundary, in the case there is already\n\t\t\t\t * more waiting leave it for next time around\n\t\t\t\t */\n\n\t\t\t\tn \u003d lws_read_h1(h2n-\u003eswsi, in - 1, (unsigned int)n);\n\t\t\t\t// lwsl_notice(\u0022%s: lws_read_h1 %d\u005cn\u0022, __func__, n);\n\t\t\t\th2n-\u003eswsi-\u003eouter_will_close \u003d 0;\n\t\t\t\t/*\n\t\t\t\t * can return 0 in POST body with\n\t\t\t\t * content len exhausted somehow.\n\t\t\t\t */\n\t\t\t\tif (n \u003c 0 ||\n\t\t\t\t (!n \u0026\u0026 h2n-\u003eswsi-\u003ehttp.content_length_given \u0026\u0026 !lws_buflist_next_segment_len(\n\t\t\t\t\t\t \u0026wsi-\u003ebuflist, NULL))) {\n\t\t\t\t\tlwsl_info(\u0022%s: lws_read_h1 told %d %u / %u\u005cn\u0022,\n\t\t\t\t\t\t__func__, n,\n\t\t\t\t\t\t(unsigned int)h2n-\u003ecount,\n\t\t\t\t\t\t(unsigned int)h2n-\u003elength);\n\t\t\t\t\tin +\u003d h2n-\u003elength - h2n-\u003ecount;\n\t\t\t\t\th2n-\u003einside \u003d h2n-\u003elength;\n\t\t\t\t\th2n-\u003ecount \u003d h2n-\u003elength - 1;\n\n\t\t\t\t\t//if (n \u003c 0)\n\t\t\t\t\t//\tgoto already_closed_swsi;\n\t\t\t\t\tgoto close_swsi_and_return;\n\t\t\t\t}\n\n\t\t\t\tlwsl_info(\u0022%s: lws_read_h1 telling %d %u / %u\u005cn\u0022,\n\t\t\t\t\t\t__func__, n,\n\t\t\t\t\t\t(unsigned int)h2n-\u003ecount,\n\t\t\t\t\t\t(unsigned int)h2n-\u003elength);\n\n\t\t\t\tin +\u003d (unsigned int)n - 1;\n\t\t\t\th2n-\u003einside +\u003d (unsigned int)n;\n\t\t\t\th2n-\u003ecount +\u003d (unsigned int)n - 1;\n\n\t\t\t\th2n-\u003eswsi-\u003etxc.peer_tx_cr_est -\u003d n;\n\t\t\t\twsi-\u003etxc.peer_tx_cr_est -\u003d n;\n\ndo_windows:\n\n#if defined(LWS_WITH_CLIENT)\n\t\t\t\tif (!(h2n-\u003eswsi-\u003eflags \u0026 LCCSCF_H2_MANUAL_RXFLOW))\n#endif\n\t\t\t\t{\n\t\t\t\t\t/*\n\t\t\t\t\t * The default behaviour is we just keep\n\t\t\t\t\t * cranking the other side's tx credit\n\t\t\t\t\t * back up, for simple bulk transfer as\n\t\t\t\t\t * fast as we can take it\n\t\t\t\t\t */\n\n\t\t\t\t\tm \u003d n + 65536;\n\n\t\t\t\t\t/* update both the stream and nwsi */\n\n\t\t\t\t\tlws_h2_update_peer_txcredit_thresh(h2n-\u003eswsi,\n\t\t\t\t\t\t\t\t h2n-\u003esid, m, m);\n\t\t\t\t}\n#if defined(LWS_WITH_CLIENT)\n\t\t\t\telse {\n\t\t\t\t\t/*\n\t\t\t\t\t * If he's handling it himself, only\n\t\t\t\t\t * repair the nwsi credit but allow the\n\t\t\t\t\t * stream credit to run down until the\n\t\t\t\t\t * user code deals with it\n\t\t\t\t\t */\n\t\t\t\t\tlws_h2_update_peer_txcredit(wsi, (unsigned int)0, n);\n\t\t\t\t\th2n-\u003eswsi-\u003etxc.manual \u003d 1;\n\t\t\t\t}\n#endif\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_PRIORITY:\n\t\t\t\tif (h2n-\u003ecount \u003c\u003d 4) {\n\t\t\t\t\th2n-\u003edep \u003c\u003c\u003d 8;\n\t\t\t\t\th2n-\u003edep |\u003d c;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\th2n-\u003eweight_temp \u003d c;\n\t\t\t\tlwsl_info(\u0022PRIORITY: dep 0x%x, weight 0x%02X\u005cn\u0022,\n\t\t\t\t\t (unsigned int)h2n-\u003edep, h2n-\u003eweight_temp);\n\n\t\t\t\tif ((h2n-\u003edep \u0026 ~(1u \u003c\u003c 31)) \u003d\u003d h2n-\u003esid) {\n\t\t\t\t\tlws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR,\n\t\t\t\t\t\t \u0022cant depend on own sid\u0022);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_RST_STREAM:\n\t\t\t\th2n-\u003ehpack_e_dep \u003c\u003c\u003d 8;\n\t\t\t\th2n-\u003ehpack_e_dep |\u003d c;\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_PUSH_PROMISE:\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_PING:\n\t\t\t\tif (h2n-\u003eflags \u0026 LWS_H2_FLAG_SETTINGS_ACK) { // ack\n\t\t\t\t} else { /* they're sending us a ping request */\n\t\t\t\t\tif (h2n-\u003ecount \u003e 8)\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\th2n-\u003eping_payload[h2n-\u003ecount - 1] \u003d c;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_WINDOW_UPDATE:\n\t\t\t\th2n-\u003ehpack_e_dep \u003c\u003c\u003d 8;\n\t\t\t\th2n-\u003ehpack_e_dep |\u003d c;\n\t\t\t\tbreak;\n\n\t\t\tcase LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */\n\t\t\t\t//lwsl_debug(\u0022%s: consuming for ignored %u %u\u005cn\u0022, __func__, (unsigned int)h2n-\u003ecount, (unsigned int)h2n-\u003elength);\n\t\t\t\th2n-\u003ecount++;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tlwsl_notice(\u0022%s: unhandled frame type %d\u005cn\u0022,\n\t\t\t\t\t __func__, h2n-\u003etype);\n\n\t\t\t\tgoto fail;\n\t\t\t}\n\nframe_end:\n\t\t\tif (h2n-\u003ecount \u003e h2n-\u003elength) {\n\t\t\t\tlwsl_notice(\u0022%s: count \u003e length %u %u (type %d)\u005cn\u0022,\n\t\t\t\t\t __func__, (unsigned int)h2n-\u003ecount,\n\t\t\t\t\t (unsigned int)h2n-\u003elength, h2n-\u003etype);\n\n\t\t\t} else\n\t\t\t\tif (h2n-\u003ecount !\u003d h2n-\u003elength)\n\t\t\t\t\tbreak;\n\n\t\t\t/*\n\t\t\t * end of frame just happened\n\t\t\t */\n\t\t\tn \u003d lws_h2_parse_end_of_frame(wsi);\n\t\t\tif (n \u003d\u003d 2) {\n\t\t\t\t*inused \u003d (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);\n\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\tif (n)\n\t\t\t\tgoto fail;\n\n\t\t\tbreak;\n\ntry_frame_start:\n\t\t\tif (h2n-\u003eframe_state \u003c\u003d 8) {\n\n\t\t\t\tswitch (h2n-\u003eframe_state++) {\n\t\t\t\tcase 0:\n\t\t\t\t\th2n-\u003epad_length \u003d 0;\n\t\t\t\t\th2n-\u003ecollected_priority \u003d 0;\n\t\t\t\t\th2n-\u003epadding \u003d 0;\n\t\t\t\t\th2n-\u003epreamble \u003d 0;\n\t\t\t\t\th2n-\u003elength \u003d c;\n\t\t\t\t\th2n-\u003einside \u003d 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\tcase 2:\n\t\t\t\t\th2n-\u003elength \u003c\u003c\u003d 8;\n\t\t\t\t\th2n-\u003elength |\u003d c;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\th2n-\u003etype \u003d c;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\th2n-\u003eflags \u003d c;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 5:\n\t\t\t\tcase 6:\n\t\t\t\tcase 7:\n\t\t\t\tcase 8:\n\t\t\t\t\th2n-\u003esid \u003c\u003c\u003d 8;\n\t\t\t\t\th2n-\u003esid |\u003d c;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (h2n-\u003eframe_state \u003d\u003d LWS_H2_FRAME_HEADER_LENGTH \u0026\u0026\n\t\t\t lws_h2_parse_frame_header(wsi))\n\t\t\t\tgoto fail;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tif (h2n-\u003etype \u003d\u003d LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */\n\t\t\t\t//lwsl_debug(\u0022%s: consuming for ignored %u %u\u005cn\u0022, __func__, (unsigned int)h2n-\u003ecount, (unsigned int)h2n-\u003elength);\n\t\t\t\th2n-\u003ecount++;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t*inused \u003d (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);\n\n\treturn 0;\n\nclose_swsi_and_return:\n\n\tlws_close_free_wsi(h2n-\u003eswsi, 0, \u0022close_swsi_and_return\u0022);\n\th2n-\u003eswsi \u003d NULL;\n\th2n-\u003eframe_state \u003d 0;\n\th2n-\u003ecount \u003d 0;\n\n// already_closed_swsi:\n\t*inused \u003d (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);\n\n\treturn 2;\n\nfail:\n\t*inused \u003d (lws_filepos_t)lws_ptr_diff_size_t(in, oldin);\n\n\treturn 1;\n}\n\n#if defined(LWS_WITH_CLIENT)\nint\nlws_h2_client_handshake(struct lws *wsi)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003ea.context-\u003ept[(int)wsi-\u003etsi];\n\tuint8_t *buf, *start, *p, *p1, *end;\n\tchar *meth \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD),\n\t *uri \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), *simp;\n\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\tconst char *path \u003d \u0022/\u0022;\n\tint n, m;\n\t/*\n\t * The identifier of a newly established stream MUST be numerically\n\t * greater than all streams that the initiating endpoint has opened or\n\t * reserved. This governs streams that are opened using a HEADERS frame\n\t * and streams that are reserved using PUSH_PROMISE. An endpoint that\n\t * receives an unexpected stream identifier MUST respond with a\n\t * connection error (Section 5.4.1) of type PROTOCOL_ERROR.\n\t */\n\tunsigned int sid \u003d nwsi-\u003eh2.h2n-\u003ehighest_sid_opened + 2;\n\n\tlwsl_debug(\u0022%s\u005cn\u0022, __func__);\n\n\t/*\n\t * We MUST allocate our sid here at the point we're about to send the\n\t * stream open. It's because we don't know the order in which multiple\n\t * open streams will send their headers... in h2, sending the headers\n\t * is the point the stream is opened. The peer requires that we only\n\t * open streams in ascending sid order\n\t */\n\n\twsi-\u003emux.my_sid \u003d nwsi-\u003eh2.h2n-\u003ehighest_sid_opened \u003d sid;\n\tlwsl_info(\u0022%s: %s: assigning SID %d at header send\u005cn\u0022, __func__,\n\t\t\tlws_wsi_tag(wsi), sid);\n\n\n\tlwsl_info(\u0022%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\u005cn\u0022,\n\t\t\t__func__, wsi-\u003emux.my_sid);\n\n\tp \u003d start \u003d buf \u003d pt-\u003eserv_buf + LWS_PRE;\n\tend \u003d start + (wsi-\u003ea.context-\u003ept_serv_buf_size / 2) - LWS_PRE - 1;\n\n\t/* it's time for us to send our client stream headers */\n\n\tif (!meth)\n\t\tmeth \u003d \u0022GET\u0022;\n\n\t/* h2 pseudoheaders must be in a bunch at the start */\n\n\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\tWSI_TOKEN_HTTP_COLON_METHOD,\n\t\t\t\t(unsigned char *)meth,\n\t\t\t\t(int)strlen(meth), \u0026p, end))\n\t\tgoto fail_length;\n\n\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\tWSI_TOKEN_HTTP_COLON_SCHEME,\n\t\t\t\t(unsigned char *)\u0022https\u0022, 5,\n\t\t\t\t\u0026p, end))\n\t\tgoto fail_length;\n\n\n\tn \u003d lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI);\n\tif (n)\n\t\tpath \u003d uri;\n\telse\n\t\tif (wsi-\u003estash \u0026\u0026 wsi-\u003estash-\u003ecis[CIS_PATH]) {\n\t\t\tpath \u003d wsi-\u003estash-\u003ecis[CIS_PATH];\n\t\t\tn \u003d (int)strlen(path);\n\t\t} else\n\t\t\tn \u003d 1;\n\n\tif (n \u003e 1 \u0026\u0026 path[0] \u003d\u003d '/' \u0026\u0026 path[1] \u003d\u003d '/') {\n\t\tpath++;\n\t\tn--;\n\t}\n\n\tif (n \u0026\u0026 lws_add_http_header_by_token(wsi,\n\t\t\t\tWSI_TOKEN_HTTP_COLON_PATH,\n\t\t\t\t(unsigned char *)path, n, \u0026p, end))\n\t\tgoto fail_length;\n\n\tn \u003d lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_HOST);\n\tsimp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST);\n\tif (!n \u0026\u0026 wsi-\u003estash \u0026\u0026 wsi-\u003estash-\u003ecis[CIS_ADDRESS]) {\n\t\tn \u003d (int)strlen(wsi-\u003estash-\u003ecis[CIS_ADDRESS]);\n\t\tsimp \u003d wsi-\u003estash-\u003ecis[CIS_ADDRESS];\n\t}\n\n//\tn \u003d lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN);\n//\tsimp \u003d lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);\n#if 0\n\tif (n \u0026\u0026 simp \u0026\u0026 lws_add_http_header_by_token(wsi,\n\t\t\t\tWSI_TOKEN_HTTP_COLON_AUTHORITY,\n\t\t\t\t(unsigned char *)simp, n, \u0026p, end))\n\t\tgoto fail_length;\n#endif\n\n\n\tif (/*!wsi-\u003eclient_h2_alpn \u0026\u0026 */n \u0026\u0026 simp \u0026\u0026\n\t lws_add_http_header_by_token(wsi, WSI_TOKEN_HOST,\n\t\t\t\t(unsigned char *)simp, n, \u0026p, end))\n\t\tgoto fail_length;\n\n\n\tif (wsi-\u003eflags \u0026 LCCSCF_HTTP_MULTIPART_MIME) {\n\t\tp1 \u003d lws_http_multipart_headers(wsi, p);\n\t\tif (!p1)\n\t\t\tgoto fail_length;\n\t\tp \u003d p1;\n\t}\n\n\tif (wsi-\u003eflags \u0026 LCCSCF_HTTP_X_WWW_FORM_URLENCODED) {\n\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,\n\t\t\t (unsigned char *)\u0022application/x-www-form-urlencoded\u0022,\n\t\t\t 33, \u0026p, end))\n\t\t\tgoto fail_length;\n\t\tlws_client_http_body_pending(wsi, 1);\n\t}\n\n\t/* give userland a chance to append, eg, cookies */\n\n#if defined(LWS_WITH_CACHE_NSCOOKIEJAR) \u0026\u0026 defined(LWS_WITH_CLIENT)\n\tif (wsi-\u003eflags \u0026 LCCSCF_CACHE_COOKIES)\n\t\tlws_cookie_send_cookies(wsi, (char **)\u0026p, (char *)end);\n#endif\n\n\tif (wsi-\u003ea.protocol-\u003ecallback(wsi,\n\t\t\t\tLWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,\n\t\t\t\twsi-\u003euser_space, \u0026p, lws_ptr_diff_size_t(end, p) - 12))\n\t\tgoto fail_length;\n\n\tif (lws_finalize_http_header(wsi, \u0026p, end))\n\t\tgoto fail_length;\n\n\tm \u003d LWS_WRITE_HTTP_HEADERS;\n#if defined(LWS_WITH_CLIENT)\n\t/* below is not needed in spec, indeed it destroys the long poll\n\t * feature, but required by nghttp2 */\n\tif ((wsi-\u003eflags \u0026 LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) \u0026\u0026\n\t !(wsi-\u003eclient_http_body_pending || lws_has_buffered_out(wsi)))\n\t\tm |\u003d LWS_WRITE_H2_STREAM_END;\n#endif\n\n\t// lwsl_hexdump_notice(start, p - start);\n\n\tn \u003d lws_write(wsi, start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)m);\n\n\tif (n !\u003d lws_ptr_diff(p, start)) {\n\t\tlwsl_err(\u0022_write returned %d from %ld\u005cn\u0022, n,\n\t\t\t (long)(p - start));\n\t\treturn -1;\n\t}\n\n\t/*\n\t * Normally let's charge up the peer tx credit a bit. But if\n\t * MANUAL_REFLOW is set, just set it to the initial credit given in\n\t * the client create info\n\t */\n\n\tn \u003d 4 * 65536;\n\tif (wsi-\u003eflags \u0026 LCCSCF_H2_MANUAL_RXFLOW) {\n\t\tn \u003d wsi-\u003etxc.manual_initial_tx_credit;\n\t\twsi-\u003etxc.manual \u003d 1;\n\t}\n\n\tif (lws_h2_update_peer_txcredit(wsi, wsi-\u003emux.my_sid, n))\n\t\treturn 1;\n\n\tlws_h2_state(wsi, LWS_H2_STATE_OPEN);\n\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n\n\tif (wsi-\u003eflags \u0026 LCCSCF_HTTP_MULTIPART_MIME)\n\t\tlws_callback_on_writable(wsi);\n\n\treturn 0;\n\nfail_length:\n\tlwsl_err(\u0022Client hdrs too long: incr context info.pt_serv_buf_size\u005cn\u0022);\n\n\treturn -1;\n}\n#endif\n\n#if defined(LWS_ROLE_WS) \u0026\u0026 defined(LWS_WITH_SERVER)\nint\nlws_h2_ws_handshake(struct lws *wsi)\n{\n\tuint8_t buf[LWS_PRE + 2048], *p \u003d buf + LWS_PRE, *start \u003d p,\n\t\t*end \u003d \u0026buf[sizeof(buf) - 1];\n\tconst struct lws_http_mount *hit;\n\tconst char * uri_ptr;\n\tsize_t m;\n\tint n;\n\n\tif (lws_add_http_header_status(wsi, HTTP_STATUS_OK, \u0026p, end))\n\t\treturn -1;\n\n\tif (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) \u003e 64)\n\t\treturn -1;\n\n\tif (wsi-\u003eproxied_ws_parent \u0026\u0026 wsi-\u003echild_list) {\n\t\tif (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {\n\t\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,\n\t\t\t\t(uint8_t *)lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\t\t WSI_TOKEN_PROTOCOL),\n\t\t\t\t(int)strlen(lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\t\t WSI_TOKEN_PROTOCOL)),\n\t\t\t\t\t\t \u0026p, end))\n\t\t\treturn -1;\n\t\t}\n\t} else {\n\n\t\t/* we can only return the protocol header if:\n\t\t * - one came in, and ... */\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) \u0026\u0026\n\t\t /* - it is not an empty string */\n\t\t wsi-\u003ea.protocol-\u003ename \u0026\u0026 wsi-\u003ea.protocol-\u003ename[0]) {\n\n#if defined(LWS_WITH_SECURE_STREAMS) \u0026\u0026 defined(LWS_WITH_SERVER)\n\n\t\t/*\n\t\t * This is the h2 version of server-ws.c understanding that it\n\t\t * did the ws upgrade on a ss server object, therefore it needs\n\t\t * to pass back to the peer the policy ws-protocol name, not\n\t\t * the generic ss-ws.c protocol name\n\t\t */\n\n\t\tif (wsi-\u003ea.vhost \u0026\u0026 wsi-\u003ea.vhost-\u003ess_handle \u0026\u0026\n\t\t wsi-\u003ea.vhost-\u003ess_handle-\u003epolicy-\u003eu.http.u.ws.subprotocol) {\n\t\t\tlws_ss_handle_t *h \u003d\n\t\t\t\t(lws_ss_handle_t *)wsi-\u003ea.opaque_user_data;\n\n\t\t\tlwsl_notice(\u0022%s: Server SS %s .wsi %s switching to ws protocol\u005cn\u0022,\n\t\t\t\t\t__func__, lws_ss_tag(h), lws_wsi_tag(h-\u003ewsi));\n\n\t\t\twsi-\u003ea.protocol \u003d \u0026protocol_secstream_ws;\n\n\t\t\t/*\n\t\t\t * inform the SS user code that this has done a one-way\n\t\t\t * upgrade to some other protocol... it will likely\n\t\t\t * want to treat subsequent payloads differently\n\t\t\t */\n\n\t\t\tlws_ss_event_helper(h, LWSSSCS_SERVER_UPGRADE);\n\n\t\t\tlws_mux_mark_immortal(wsi);\n\n\t\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,\n\t\t\t\t(unsigned char *)wsi-\u003ea.vhost-\u003ess_handle-\u003epolicy-\u003e\n\t\t\t\t\t\tu.http.u.ws.subprotocol,\n\t\t\t\t(int)strlen(wsi-\u003ea.vhost-\u003ess_handle-\u003epolicy-\u003e\n\t\t\t\t\t\tu.http.u.ws.subprotocol), \u0026p, end))\n\t\t\t\t\treturn -1;\n\t\t} else\n#endif\n\n\t\t\tif (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,\n\t\t\t\t(unsigned char *)wsi-\u003ea.protocol-\u003ename,\n\t\t\t\t(int)strlen(wsi-\u003ea.protocol-\u003ename), \u0026p, end))\n\t\t\t\t\treturn -1;\n\t\t}\n\t}\n\n#if !defined(LWS_WITHOUT_EXTENSIONS)\n /*\n * Figure out which extensions the client has that we want to\n * enable on this connection, and give him back the list.\n *\n * Give him a limited write bugdet\n */\n if (lws_extension_server_handshake(wsi, (char **)\u0026p, 192))\n return -1;\n#endif\n\n\tif (lws_finalize_http_header(wsi, \u0026p, end))\n\t\treturn -1;\n\n\tm \u003d lws_ptr_diff_size_t(p, start);\n\t// lwsl_hexdump_notice(start, m);\n\tn \u003d lws_write(wsi, start, m, LWS_WRITE_HTTP_HEADERS);\n\tif (n !\u003d (int)m) {\n\t\tlwsl_err(\u0022_write returned %d from %d\u005cn\u0022, n, (int)m);\n\n\t\treturn -1;\n\t}\n\n\t/*\n\t * alright clean up, set our state to generic ws established, the\n\t * mode / state of the nwsi will get the h2 processing done.\n\t */\n\n\tlwsi_set_state(wsi, LRS_ESTABLISHED);\n\twsi-\u003elws_rx_parse_state \u003d 0; // \u003d\u003dLWS_RXPS_NEW;\n\n\turi_ptr \u003d lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH);\n\tn \u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH);\n\thit \u003d lws_find_mount(wsi, uri_ptr, n);\n\n\tif (hit \u0026\u0026 hit-\u003ecgienv \u0026\u0026\n\t wsi-\u003ea.protocol-\u003ecallback(wsi, LWS_CALLBACK_HTTP_PMO, wsi-\u003euser_space,\n\t\t\t\t (void *)hit-\u003ecgienv, 0))\n\t\treturn 1;\n\n\tlws_validity_confirmed(wsi);\n\n\treturn 0;\n}\n#endif\n\nint\nlws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len)\n{\n\tunsigned char *oldbuf \u003d buf;\n\n\t// lwsl_notice(\u0022%s: h2 path: wsistate 0x%x len %d\u005cn\u0022, __func__,\n\t//\t\twsi-\u003ewsistate, (int)len);\n\n\t/*\n\t * wsi here is always the network connection wsi, not a stream\n\t * wsi. Once we unpicked the framing we will find the right\n\t * swsi and make it the target of the frame.\n\t *\n\t * If it's ws over h2, the nwsi will get us here to do the h2\n\t * processing, and that will call us back with the swsi +\n\t * ESTABLISHED state for the inner payload, handled in a later\n\t * case.\n\t */\n\twhile (len) {\n\t\tlws_filepos_t body_chunk_len \u003d 0;\n\t\tint m;\n\n\t\t/*\n\t\t * we were accepting input but now we stopped doing so\n\t\t */\n\t\tif (lws_is_flowcontrolled(wsi)) {\n\t\t\tlws_rxflow_cache(wsi, buf, 0, (size_t)len);\n\t\t\tbuf +\u003d len;\n\t\t\tbreak;\n\t\t}\n\n\t\t/*\n\t\t * lws_h2_parser() may send something; when it gets the\n\t\t * whole frame, it will want to perform some action\n\t\t * involving a reply. But we may be in a partial send\n\t\t * situation on the network wsi...\n\t\t *\n\t\t * Even though we may be in a partial send and unable to\n\t\t * send anything new, we still have to parse the network\n\t\t * wsi in order to gain tx credit to send, which is\n\t\t * potentially necessary to clear the old partial send.\n\t\t *\n\t\t * ALL network wsi-specific frames are sent by PPS\n\t\t * already, these are sent as a priority on the writable\n\t\t * handler, and so respect partial sends. The only\n\t\t * problem is when a stream wsi wants to send an, eg,\n\t\t * reply headers frame in response to the parsing\n\t\t * we will do now... the *stream wsi* must stall in a\n\t\t * different state until it is able to do so from a\n\t\t * priority on the WRITABLE callback, same way that\n\t\t * file transfers operate.\n\t\t */\n\n\t\tm \u003d lws_h2_parser(wsi, buf, len, \u0026body_chunk_len);\n\t\tif (m \u0026\u0026 m !\u003d 2) {\n\t\t\tlwsl_debug(\u0022%s: http2_parser bail: %d\u005cn\u0022, __func__, m);\n\t\t\tlws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,\n\t\t\t\t\t \u0022lws_read_h2 bail\u0022);\n\n\t\t\treturn -1;\n\t\t}\n\t\tif (m \u003d\u003d 2) {\n\t\t\t/* swsi has been closed */\n\t\t\tbuf +\u003d body_chunk_len;\n\t\t\tbreak;\n\t\t}\n\n\t\tbuf +\u003d body_chunk_len;\n\t\tlen -\u003d body_chunk_len;\n\t}\n\n\treturn lws_ptr_diff(buf, oldbuf);\n}\n\nint\nlws_h2_client_stream_long_poll_rxonly(struct lws *wsi)\n{\n\n\tif (!wsi-\u003emux_substream)\n\t\treturn 1;\n\n\t/*\n\t * Elect to send an empty DATA with END_STREAM, to force the stream\n\t * into HALF_CLOSED LOCAL\n\t */\n\twsi-\u003eh2.long_poll \u003d 1;\n\twsi-\u003eh2.send_END_STREAM \u003d 1;\n\n\t// lws_header_table_detach(wsi, 0);\n\n\tlws_callback_on_writable(wsi);\n\n\treturn 0;\n}\n","s":{"c":1713871857,"u": 4315}} ],"g": 102712,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}