1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_ci/* max individual proxied header payload size */ 28d4afb5ceSopenharmony_ci#define MAXHDRVAL 1024 29d4afb5ceSopenharmony_ci 30d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 31d4afb5ceSopenharmony_cistatic int 32d4afb5ceSopenharmony_ciproxy_header(struct lws *wsi, struct lws *par, unsigned char *temp, 33d4afb5ceSopenharmony_ci int temp_len, int index, unsigned char **p, unsigned char *end) 34d4afb5ceSopenharmony_ci{ 35d4afb5ceSopenharmony_ci int n = lws_hdr_total_length(par, (enum lws_token_indexes)index); 36d4afb5ceSopenharmony_ci 37d4afb5ceSopenharmony_ci if (n < 1) { 38d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "no index %d:", index); 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_ci return 0; 41d4afb5ceSopenharmony_ci } 42d4afb5ceSopenharmony_ci 43d4afb5ceSopenharmony_ci if (lws_hdr_copy(par, (char *)temp, temp_len, (enum lws_token_indexes)index) < 0) { 44d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "unable to copy par hdr idx %d (len %d)", 45d4afb5ceSopenharmony_ci index, n); 46d4afb5ceSopenharmony_ci return -1; 47d4afb5ceSopenharmony_ci } 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "index %d: %s", index, (char *)temp); 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, (enum lws_token_indexes)index, temp, n, p, end)) { 52d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "unable to append par hdr idx %d (len %d)", 53d4afb5ceSopenharmony_ci index, n); 54d4afb5ceSopenharmony_ci return -1; 55d4afb5ceSopenharmony_ci } 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci return 0; 58d4afb5ceSopenharmony_ci} 59d4afb5ceSopenharmony_ci 60d4afb5ceSopenharmony_cistatic int 61d4afb5ceSopenharmony_cistream_close(struct lws *wsi) 62d4afb5ceSopenharmony_ci{ 63d4afb5ceSopenharmony_ci char buf[LWS_PRE + 6], *out = buf + LWS_PRE; 64d4afb5ceSopenharmony_ci 65d4afb5ceSopenharmony_ci if (wsi->http.did_stream_close) 66d4afb5ceSopenharmony_ci return 0; 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_ci wsi->http.did_stream_close = 1; 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci if (wsi->mux_substream) { 71d4afb5ceSopenharmony_ci if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0, 72d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL) < 0) 73d4afb5ceSopenharmony_ci goto bail; 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_ci return 0; 76d4afb5ceSopenharmony_ci } 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci *out++ = '0'; 79d4afb5ceSopenharmony_ci *out++ = '\x0d'; 80d4afb5ceSopenharmony_ci *out++ = '\x0a'; 81d4afb5ceSopenharmony_ci *out++ = '\x0d'; 82d4afb5ceSopenharmony_ci *out++ = '\x0a'; 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5, 85d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL) < 0) 86d4afb5ceSopenharmony_ci goto bail; 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci return 0; 89d4afb5ceSopenharmony_ci 90d4afb5ceSopenharmony_cibail: 91d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "h2 fin wr failed"); 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci return -1; 94d4afb5ceSopenharmony_ci} 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci#endif 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_cistruct lws_proxy_pkt { 99d4afb5ceSopenharmony_ci struct lws_dll2 pkt_list; 100d4afb5ceSopenharmony_ci size_t len; 101d4afb5ceSopenharmony_ci char binary; 102d4afb5ceSopenharmony_ci char first; 103d4afb5ceSopenharmony_ci char final; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci /* data follows */ 106d4afb5ceSopenharmony_ci}; 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS) 109d4afb5ceSopenharmony_ciint 110d4afb5ceSopenharmony_cilws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason, 111d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 112d4afb5ceSopenharmony_ci{ 113d4afb5ceSopenharmony_ci struct lws_proxy_pkt *pkt; 114d4afb5ceSopenharmony_ci struct lws_dll2 *dll; 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci switch (reason) { 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_ci /* h1 ws proxying... child / client / onward */ 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_ESTABLISHED: 121d4afb5ceSopenharmony_ci if (!wsi->h1_ws_proxied || !wsi->parent) 122d4afb5ceSopenharmony_ci break; 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_ci if (lws_process_ws_upgrade2(wsi->parent)) 125d4afb5ceSopenharmony_ci return -1; 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 128d4afb5ceSopenharmony_ci if (wsi->parent->mux_substream) 129d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "proxied h2 -> h1 ws established"); 130d4afb5ceSopenharmony_ci#endif 131d4afb5ceSopenharmony_ci break; 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: 134d4afb5ceSopenharmony_ci return 1; 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 137d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CLOSED: 138d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "client closed: parent %s", 139d4afb5ceSopenharmony_ci lws_wsi_tag(wsi->parent)); 140d4afb5ceSopenharmony_ci if (wsi->parent) 141d4afb5ceSopenharmony_ci lws_set_timeout(wsi->parent, 1, LWS_TO_KILL_ASYNC); 142d4afb5ceSopenharmony_ci break; 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: 145d4afb5ceSopenharmony_ci { 146d4afb5ceSopenharmony_ci unsigned char **p = (unsigned char **)in, *end = (*p) + len, 147d4afb5ceSopenharmony_ci tmp[MAXHDRVAL]; 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci proxy_header(wsi, wsi->parent, tmp, sizeof(tmp), 150d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end); 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci proxy_header(wsi, wsi->parent, tmp, sizeof(tmp), 153d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COOKIE, p, end); 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci proxy_header(wsi, wsi->parent, tmp, sizeof(tmp), 156d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_SET_COOKIE, p, end); 157d4afb5ceSopenharmony_ci break; 158d4afb5ceSopenharmony_ci } 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_RECEIVE: 161d4afb5ceSopenharmony_ci wsi->parent->ws->proxy_buffered += len; 162d4afb5ceSopenharmony_ci if (wsi->parent->ws->proxy_buffered > 10 * 1024 * 1024) { 163d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "proxied ws connection " 164d4afb5ceSopenharmony_ci "excessive buffering: dropping"); 165d4afb5ceSopenharmony_ci return -1; 166d4afb5ceSopenharmony_ci } 167d4afb5ceSopenharmony_ci pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__); 168d4afb5ceSopenharmony_ci if (!pkt) 169d4afb5ceSopenharmony_ci return -1; 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci pkt->len = len; 172d4afb5ceSopenharmony_ci pkt->first = (char)lws_is_first_fragment(wsi); 173d4afb5ceSopenharmony_ci pkt->final = (char)lws_is_final_fragment(wsi); 174d4afb5ceSopenharmony_ci pkt->binary = (char)lws_frame_is_binary(wsi); 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len); 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci lws_dll2_add_tail(&pkt->pkt_list, &wsi->parent->ws->proxy_owner); 179d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi->parent); 180d4afb5ceSopenharmony_ci break; 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_WRITEABLE: 183d4afb5ceSopenharmony_ci dll = lws_dll2_get_head(&wsi->ws->proxy_owner); 184d4afb5ceSopenharmony_ci if (!dll) 185d4afb5ceSopenharmony_ci break; 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci pkt = (struct lws_proxy_pkt *)dll; 188d4afb5ceSopenharmony_ci if (lws_write(wsi, ((unsigned char *)&pkt[1]) + 189d4afb5ceSopenharmony_ci LWS_PRE, pkt->len, (enum lws_write_protocol)lws_write_ws_flags( 190d4afb5ceSopenharmony_ci pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT, 191d4afb5ceSopenharmony_ci pkt->first, pkt->final)) < 0) 192d4afb5ceSopenharmony_ci return -1; 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci lws_dll2_remove(dll); 195d4afb5ceSopenharmony_ci lws_free(pkt); 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (lws_dll2_get_head(&wsi->ws->proxy_owner)) 198d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 199d4afb5ceSopenharmony_ci break; 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci /* h1 ws proxying... parent / server / incoming */ 202d4afb5ceSopenharmony_ci 203d4afb5ceSopenharmony_ci case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: 204d4afb5ceSopenharmony_ci return 1; 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED: 207d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "closed"); 208d4afb5ceSopenharmony_ci return -1; 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE: 211d4afb5ceSopenharmony_ci pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__); 212d4afb5ceSopenharmony_ci if (!pkt) 213d4afb5ceSopenharmony_ci return -1; 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci pkt->len = len; 216d4afb5ceSopenharmony_ci pkt->first = (char)lws_is_first_fragment(wsi); 217d4afb5ceSopenharmony_ci pkt->final = (char)lws_is_final_fragment(wsi); 218d4afb5ceSopenharmony_ci pkt->binary = (char)lws_frame_is_binary(wsi); 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci lws_dll2_add_tail(&pkt->pkt_list, &wsi->child_list->ws->proxy_owner); 223d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi->child_list); 224d4afb5ceSopenharmony_ci break; 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci case LWS_CALLBACK_SERVER_WRITEABLE: 227d4afb5ceSopenharmony_ci dll = lws_dll2_get_head(&wsi->ws->proxy_owner); 228d4afb5ceSopenharmony_ci if (!dll) 229d4afb5ceSopenharmony_ci break; 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci pkt = (struct lws_proxy_pkt *)dll; 232d4afb5ceSopenharmony_ci if (lws_write(wsi, ((unsigned char *)&pkt[1]) + 233d4afb5ceSopenharmony_ci LWS_PRE, pkt->len, (enum lws_write_protocol)lws_write_ws_flags( 234d4afb5ceSopenharmony_ci pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT, 235d4afb5ceSopenharmony_ci pkt->first, pkt->final)) < 0) 236d4afb5ceSopenharmony_ci return -1; 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci wsi->ws->proxy_buffered -= pkt->len; 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_ci lws_dll2_remove(dll); 241d4afb5ceSopenharmony_ci lws_free(pkt); 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci if (lws_dll2_get_head(&wsi->ws->proxy_owner)) 244d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 245d4afb5ceSopenharmony_ci break; 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci default: 248d4afb5ceSopenharmony_ci return 0; 249d4afb5ceSopenharmony_ci } 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_ci return 0; 252d4afb5ceSopenharmony_ci} 253d4afb5ceSopenharmony_ci 254d4afb5ceSopenharmony_ciconst struct lws_protocols lws_ws_proxy = { 255d4afb5ceSopenharmony_ci "lws-ws-proxy", 256d4afb5ceSopenharmony_ci lws_callback_ws_proxy, 257d4afb5ceSopenharmony_ci 0, 258d4afb5ceSopenharmony_ci 8192, 259d4afb5ceSopenharmony_ci 8192, NULL, 0 260d4afb5ceSopenharmony_ci}; 261d4afb5ceSopenharmony_ci 262d4afb5ceSopenharmony_ci#endif 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ciint 266d4afb5ceSopenharmony_cilws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, 267d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 268d4afb5ceSopenharmony_ci{ 269d4afb5ceSopenharmony_ci struct lws_ssl_info *si; 270d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 271d4afb5ceSopenharmony_ci struct lws_cgi_args *args; 272d4afb5ceSopenharmony_ci#endif 273d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY) 274d4afb5ceSopenharmony_ci char buf[LWS_PRE + 32 + 8192]; 275d4afb5ceSopenharmony_ci int n; 276d4afb5ceSopenharmony_ci#endif 277d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 278d4afb5ceSopenharmony_ci unsigned char **p, *end; 279d4afb5ceSopenharmony_ci struct lws *parent; 280d4afb5ceSopenharmony_ci#endif 281d4afb5ceSopenharmony_ci 282d4afb5ceSopenharmony_ci switch (reason) { 283d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 284d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP: 285d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 286d4afb5ceSopenharmony_ci if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL)) 287d4afb5ceSopenharmony_ci return -1; 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 290d4afb5ceSopenharmony_ci#endif 291d4afb5ceSopenharmony_ci return -1; 292d4afb5ceSopenharmony_ci break; 293d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 294d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_BODY_COMPLETION: 295d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 296d4afb5ceSopenharmony_ci if (wsi->child_list) { 297d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "HTTP_BODY_COMPLETION: %d", 298d4afb5ceSopenharmony_ci (int)len); 299d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi->child_list); 300d4afb5ceSopenharmony_ci break; 301d4afb5ceSopenharmony_ci } 302d4afb5ceSopenharmony_ci#endif 303d4afb5ceSopenharmony_ci if (lws_return_http_status(wsi, 200, NULL)) 304d4afb5ceSopenharmony_ci return -1; 305d4afb5ceSopenharmony_ci break; 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_ci /* fallthru */ 308d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_FILE_COMPLETION: 309d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 310d4afb5ceSopenharmony_ci return -1; 311d4afb5ceSopenharmony_ci break; 312d4afb5ceSopenharmony_ci#endif 313d4afb5ceSopenharmony_ci 314d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 315d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_BODY: 316d4afb5ceSopenharmony_ci if (wsi->child_list) { 317d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "HTTP_BODY: stashing %d", (int)len); 318d4afb5ceSopenharmony_ci if (lws_buflist_append_segment( 319d4afb5ceSopenharmony_ci &wsi->http.buflist_post_body, in, len) < 0) 320d4afb5ceSopenharmony_ci return -1; 321d4afb5ceSopenharmony_ci lws_client_http_body_pending(wsi->child_list, 1); 322d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi->child_list); 323d4afb5ceSopenharmony_ci } 324d4afb5ceSopenharmony_ci break; 325d4afb5ceSopenharmony_ci#endif 326d4afb5ceSopenharmony_ci 327d4afb5ceSopenharmony_ci case LWS_CALLBACK_HTTP_WRITEABLE: 328d4afb5ceSopenharmony_ci // lwsl_err("%s: LWS_CALLBACK_HTTP_WRITEABLE\n", __func__); 329d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 330d4afb5ceSopenharmony_ci if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS | 331d4afb5ceSopenharmony_ci LWS_CB_REASON_AUX_BF__CGI)) { 332d4afb5ceSopenharmony_ci n = lws_cgi_write_split_stdout_headers(wsi); 333d4afb5ceSopenharmony_ci if (n < 0) { 334d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "AUX_BF__CGI forcing close"); 335d4afb5ceSopenharmony_ci return -1; 336d4afb5ceSopenharmony_ci } 337d4afb5ceSopenharmony_ci if (!n && wsi->http.cgi && wsi->http.cgi->lsp && 338d4afb5ceSopenharmony_ci wsi->http.cgi->lsp->stdwsi[LWS_STDOUT]) 339d4afb5ceSopenharmony_ci lws_rx_flow_control( 340d4afb5ceSopenharmony_ci wsi->http.cgi->lsp->stdwsi[LWS_STDOUT], 1); 341d4afb5ceSopenharmony_ci 342d4afb5ceSopenharmony_ci if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS) 343d4afb5ceSopenharmony_ci wsi->reason_bf &= 344d4afb5ceSopenharmony_ci (char)~LWS_CB_REASON_AUX_BF__CGI_HEADERS; 345d4afb5ceSopenharmony_ci else 346d4afb5ceSopenharmony_ci wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__CGI; 347d4afb5ceSopenharmony_ci 348d4afb5ceSopenharmony_ci if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) { 349d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "txn over"); 350d4afb5ceSopenharmony_ci return -1; 351d4afb5ceSopenharmony_ci } 352d4afb5ceSopenharmony_ci 353d4afb5ceSopenharmony_ci break; 354d4afb5ceSopenharmony_ci } 355d4afb5ceSopenharmony_ci 356d4afb5ceSopenharmony_ci if ((wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) || 357d4afb5ceSopenharmony_ci (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END)) { 358d4afb5ceSopenharmony_ci if (!wsi->mux_substream) { 359d4afb5ceSopenharmony_ci memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5); 360d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "wr chunk term and exiting"); 361d4afb5ceSopenharmony_ci lws_write(wsi, (unsigned char *)buf + 362d4afb5ceSopenharmony_ci LWS_PRE, 5, LWS_WRITE_HTTP); 363d4afb5ceSopenharmony_ci } else 364d4afb5ceSopenharmony_ci lws_write(wsi, (unsigned char *)buf + 365d4afb5ceSopenharmony_ci LWS_PRE, 0, 366d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL); 367d4afb5ceSopenharmony_ci 368d4afb5ceSopenharmony_ci /* always close after sending it */ 369d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 370d4afb5ceSopenharmony_ci return -1; 371d4afb5ceSopenharmony_ci return 0; 372d4afb5ceSopenharmony_ci } 373d4afb5ceSopenharmony_ci#endif 374d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_HEADERS) { 377d4afb5ceSopenharmony_ci 378d4afb5ceSopenharmony_ci wsi->reason_bf &= 379d4afb5ceSopenharmony_ci (char)~LWS_CB_REASON_AUX_BF__PROXY_HEADERS; 380d4afb5ceSopenharmony_ci 381d4afb5ceSopenharmony_ci n = LWS_WRITE_HTTP_HEADERS; 382d4afb5ceSopenharmony_ci if (!wsi->http.prh_content_length) 383d4afb5ceSopenharmony_ci n |= LWS_WRITE_H2_STREAM_END; 384d4afb5ceSopenharmony_ci 385d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "issuing proxy headers: clen %d", 386d4afb5ceSopenharmony_ci (int)wsi->http.prh_content_length); 387d4afb5ceSopenharmony_ci n = lws_write(wsi, wsi->http.pending_return_headers + 388d4afb5ceSopenharmony_ci LWS_PRE, 389d4afb5ceSopenharmony_ci wsi->http.pending_return_headers_len, 390d4afb5ceSopenharmony_ci (enum lws_write_protocol)n); 391d4afb5ceSopenharmony_ci 392d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.pending_return_headers); 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_ci if (n < 0) { 395d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "EST_CLIENT_HTTP: wr failed"); 396d4afb5ceSopenharmony_ci 397d4afb5ceSopenharmony_ci return -1; 398d4afb5ceSopenharmony_ci } 399d4afb5ceSopenharmony_ci 400d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 401d4afb5ceSopenharmony_ci break; 402d4afb5ceSopenharmony_ci } 403d4afb5ceSopenharmony_ci 404d4afb5ceSopenharmony_ci if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) { 405d4afb5ceSopenharmony_ci char *px = buf + LWS_PRE; 406d4afb5ceSopenharmony_ci int lenx = sizeof(buf) - LWS_PRE - 32; 407d4afb5ceSopenharmony_ci 408d4afb5ceSopenharmony_ci /* 409d4afb5ceSopenharmony_ci * our sink is writeable and our source has something 410d4afb5ceSopenharmony_ci * to read. So read a lump of source material of 411d4afb5ceSopenharmony_ci * suitable size to send or what's available, whichever 412d4afb5ceSopenharmony_ci * is the smaller. 413d4afb5ceSopenharmony_ci */ 414d4afb5ceSopenharmony_ci wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__PROXY; 415d4afb5ceSopenharmony_ci if (!lws_get_child(wsi)) 416d4afb5ceSopenharmony_ci break; 417d4afb5ceSopenharmony_ci 418d4afb5ceSopenharmony_ci /* this causes LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ */ 419d4afb5ceSopenharmony_ci if (lws_http_client_read(lws_get_child(wsi), &px, 420d4afb5ceSopenharmony_ci &lenx) < 0) { 421d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "LWS_CB_REASON_AUX_BF__PROXY: " 422d4afb5ceSopenharmony_ci "client closed"); 423d4afb5ceSopenharmony_ci 424d4afb5ceSopenharmony_ci stream_close(wsi); 425d4afb5ceSopenharmony_ci 426d4afb5ceSopenharmony_ci return -1; 427d4afb5ceSopenharmony_ci } 428d4afb5ceSopenharmony_ci break; 429d4afb5ceSopenharmony_ci } 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_TRANS_END) { 432d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "PROXY_TRANS_END"); 433d4afb5ceSopenharmony_ci 434d4afb5ceSopenharmony_ci wsi->reason_bf &= (char)~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END; 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci if (stream_close(wsi)) 437d4afb5ceSopenharmony_ci return -1; 438d4afb5ceSopenharmony_ci 439d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 440d4afb5ceSopenharmony_ci return -1; 441d4afb5ceSopenharmony_ci } 442d4afb5ceSopenharmony_ci#endif 443d4afb5ceSopenharmony_ci break; 444d4afb5ceSopenharmony_ci 445d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_PROXY) 446d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: 447d4afb5ceSopenharmony_ci assert(lws_get_parent(wsi)); 448d4afb5ceSopenharmony_ci if (!lws_get_parent(wsi)) 449d4afb5ceSopenharmony_ci break; 450d4afb5ceSopenharmony_ci lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY; 451d4afb5ceSopenharmony_ci lws_callback_on_writable(lws_get_parent(wsi)); 452d4afb5ceSopenharmony_ci break; 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_ci case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: { 455d4afb5ceSopenharmony_ci char *out = buf + LWS_PRE; 456d4afb5ceSopenharmony_ci 457d4afb5ceSopenharmony_ci assert(lws_get_parent(wsi)); 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci if (wsi->http.proxy_parent_chunked) { 460d4afb5ceSopenharmony_ci 461d4afb5ceSopenharmony_ci if (len > sizeof(buf) - LWS_PRE - 16) { 462d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "oversize buf %d %d", (int)len, 463d4afb5ceSopenharmony_ci (int)sizeof(buf) - LWS_PRE - 16); 464d4afb5ceSopenharmony_ci return -1; 465d4afb5ceSopenharmony_ci } 466d4afb5ceSopenharmony_ci 467d4afb5ceSopenharmony_ci /* 468d4afb5ceSopenharmony_ci * this only needs dealing with on http/1.1 to allow 469d4afb5ceSopenharmony_ci * pipelining 470d4afb5ceSopenharmony_ci */ 471d4afb5ceSopenharmony_ci n = lws_snprintf(out, 14, "%X\x0d\x0a", (int)len); 472d4afb5ceSopenharmony_ci out += n; 473d4afb5ceSopenharmony_ci memcpy(out, in, len); 474d4afb5ceSopenharmony_ci out += len; 475d4afb5ceSopenharmony_ci *out++ = '\x0d'; 476d4afb5ceSopenharmony_ci *out++ = '\x0a'; 477d4afb5ceSopenharmony_ci 478d4afb5ceSopenharmony_ci n = lws_write(lws_get_parent(wsi), 479d4afb5ceSopenharmony_ci (unsigned char *)buf + LWS_PRE, 480d4afb5ceSopenharmony_ci (size_t)(unsigned int)(len + (unsigned int)n + 2), LWS_WRITE_HTTP); 481d4afb5ceSopenharmony_ci } else 482d4afb5ceSopenharmony_ci n = lws_write(lws_get_parent(wsi), (unsigned char *)in, 483d4afb5ceSopenharmony_ci len, LWS_WRITE_HTTP); 484d4afb5ceSopenharmony_ci if (n < 0) 485d4afb5ceSopenharmony_ci return -1; 486d4afb5ceSopenharmony_ci break; } 487d4afb5ceSopenharmony_ci 488d4afb5ceSopenharmony_ci /* h1 http proxying... */ 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_ci case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: { 491d4afb5ceSopenharmony_ci unsigned char *start, *p, *end; 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci /* 494d4afb5ceSopenharmony_ci * We want to proxy these headers, but we are being called 495d4afb5ceSopenharmony_ci * at the point the onward client was established, which is 496d4afb5ceSopenharmony_ci * unrelated to the state or writability of our proxy 497d4afb5ceSopenharmony_ci * connection. 498d4afb5ceSopenharmony_ci * 499d4afb5ceSopenharmony_ci * Therefore produce the headers using the onward client ah 500d4afb5ceSopenharmony_ci * while we have it, and stick them on the output buflist to be 501d4afb5ceSopenharmony_ci * written on the proxy connection as soon as convenient. 502d4afb5ceSopenharmony_ci */ 503d4afb5ceSopenharmony_ci 504d4afb5ceSopenharmony_ci parent = lws_get_parent(wsi); 505d4afb5ceSopenharmony_ci 506d4afb5ceSopenharmony_ci if (!parent) 507d4afb5ceSopenharmony_ci return 0; 508d4afb5ceSopenharmony_ci 509d4afb5ceSopenharmony_ci start = p = (unsigned char *)buf + LWS_PRE; 510d4afb5ceSopenharmony_ci end = p + sizeof(buf) - LWS_PRE - MAXHDRVAL; 511d4afb5ceSopenharmony_ci 512d4afb5ceSopenharmony_ci if (lws_add_http_header_status(lws_get_parent(wsi), 513d4afb5ceSopenharmony_ci lws_http_client_http_response(wsi), &p, end)) 514d4afb5ceSopenharmony_ci return 1; 515d4afb5ceSopenharmony_ci 516d4afb5ceSopenharmony_ci /* 517d4afb5ceSopenharmony_ci * copy these headers from the client connection to the parent 518d4afb5ceSopenharmony_ci */ 519d4afb5ceSopenharmony_ci 520d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 521d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end); 522d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 523d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end); 524d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 525d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ETAG, &p, end); 526d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 527d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end); 528d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 529d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end); 530d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 531d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end); 532d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 533d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_SET_COOKIE, &p, end); 534d4afb5ceSopenharmony_ci proxy_header(parent, wsi, end, MAXHDRVAL, 535d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_LOCATION, &p, end); 536d4afb5ceSopenharmony_ci 537d4afb5ceSopenharmony_ci if (!parent->mux_substream) 538d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(parent, 539d4afb5ceSopenharmony_ci WSI_TOKEN_CONNECTION, (unsigned char *)"close", 540d4afb5ceSopenharmony_ci 5, &p, end)) 541d4afb5ceSopenharmony_ci return -1; 542d4afb5ceSopenharmony_ci 543d4afb5ceSopenharmony_ci /* 544d4afb5ceSopenharmony_ci * We proxy using h1 only atm, and strip any chunking so it 545d4afb5ceSopenharmony_ci * can go back out on h2 just fine. 546d4afb5ceSopenharmony_ci * 547d4afb5ceSopenharmony_ci * However if we are actually going out on h1, we need to add 548d4afb5ceSopenharmony_ci * our own chunking since we still don't know the size. 549d4afb5ceSopenharmony_ci */ 550d4afb5ceSopenharmony_ci 551d4afb5ceSopenharmony_ci if (!parent->mux_substream && 552d4afb5ceSopenharmony_ci !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { 553d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "downstream parent chunked"); 554d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(parent, 555d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_TRANSFER_ENCODING, 556d4afb5ceSopenharmony_ci (unsigned char *)"chunked", 7, &p, end)) 557d4afb5ceSopenharmony_ci return -1; 558d4afb5ceSopenharmony_ci 559d4afb5ceSopenharmony_ci wsi->http.proxy_parent_chunked = 1; 560d4afb5ceSopenharmony_ci } 561d4afb5ceSopenharmony_ci 562d4afb5ceSopenharmony_ci if (lws_finalize_http_header(parent, &p, end)) 563d4afb5ceSopenharmony_ci return 1; 564d4afb5ceSopenharmony_ci 565d4afb5ceSopenharmony_ci parent->http.prh_content_length = (size_t)-1; 566d4afb5ceSopenharmony_ci if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) 567d4afb5ceSopenharmony_ci parent->http.prh_content_length = (size_t)atoll( 568d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, 569d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_LENGTH)); 570d4afb5ceSopenharmony_ci 571d4afb5ceSopenharmony_ci parent->http.pending_return_headers_len = lws_ptr_diff_size_t(p, start); 572d4afb5ceSopenharmony_ci parent->http.pending_return_headers = 573d4afb5ceSopenharmony_ci lws_malloc(parent->http.pending_return_headers_len + 574d4afb5ceSopenharmony_ci LWS_PRE, "return proxy headers"); 575d4afb5ceSopenharmony_ci if (!parent->http.pending_return_headers) 576d4afb5ceSopenharmony_ci return -1; 577d4afb5ceSopenharmony_ci 578d4afb5ceSopenharmony_ci memcpy(parent->http.pending_return_headers + LWS_PRE, start, 579d4afb5ceSopenharmony_ci parent->http.pending_return_headers_len); 580d4afb5ceSopenharmony_ci 581d4afb5ceSopenharmony_ci parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS; 582d4afb5ceSopenharmony_ci 583d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "ESTABLISHED_CLIENT_HTTP: " 584d4afb5ceSopenharmony_ci "prepared %d headers (len %d)", 585d4afb5ceSopenharmony_ci lws_http_client_http_response(wsi), 586d4afb5ceSopenharmony_ci (int)parent->http.prh_content_length); 587d4afb5ceSopenharmony_ci 588d4afb5ceSopenharmony_ci /* 589d4afb5ceSopenharmony_ci * so at this point, the onward client connection can bear 590d4afb5ceSopenharmony_ci * traffic. We might be doing a POST and have pending cached 591d4afb5ceSopenharmony_ci * inbound stuff to send, it can go now. 592d4afb5ceSopenharmony_ci */ 593d4afb5ceSopenharmony_ci 594d4afb5ceSopenharmony_ci lws_callback_on_writable(parent); 595d4afb5ceSopenharmony_ci 596d4afb5ceSopenharmony_ci break; } 597d4afb5ceSopenharmony_ci 598d4afb5ceSopenharmony_ci case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: 599d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "COMPLETED_CLIENT_HTTP: (parent %s)", 600d4afb5ceSopenharmony_ci lws_wsi_tag(lws_get_parent(wsi))); 601d4afb5ceSopenharmony_ci if (!lws_get_parent(wsi)) 602d4afb5ceSopenharmony_ci break; 603d4afb5ceSopenharmony_ci lws_get_parent(wsi)->reason_bf |= 604d4afb5ceSopenharmony_ci LWS_CB_REASON_AUX_BF__PROXY_TRANS_END; 605d4afb5ceSopenharmony_ci lws_callback_on_writable(lws_get_parent(wsi)); 606d4afb5ceSopenharmony_ci break; 607d4afb5ceSopenharmony_ci 608d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLOSED_CLIENT_HTTP: 609d4afb5ceSopenharmony_ci if (!lws_get_parent(wsi)) 610d4afb5ceSopenharmony_ci break; 611d4afb5ceSopenharmony_ci // lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__); 612d4afb5ceSopenharmony_ci lws_set_timeout(lws_get_parent(wsi), 613d4afb5ceSopenharmony_ci (enum pending_timeout)LWS_TO_KILL_ASYNC, 614d4afb5ceSopenharmony_ci (int)PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE); 615d4afb5ceSopenharmony_ci break; 616d4afb5ceSopenharmony_ci 617d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: 618d4afb5ceSopenharmony_ci parent = lws_get_parent(wsi); 619d4afb5ceSopenharmony_ci if (!parent) 620d4afb5ceSopenharmony_ci break; 621d4afb5ceSopenharmony_ci 622d4afb5ceSopenharmony_ci p = (unsigned char **)in; 623d4afb5ceSopenharmony_ci end = (*p) + len; 624d4afb5ceSopenharmony_ci 625d4afb5ceSopenharmony_ci /* 626d4afb5ceSopenharmony_ci * copy these headers from the parent request to the client 627d4afb5ceSopenharmony_ci * connection's request 628d4afb5ceSopenharmony_ci */ 629d4afb5ceSopenharmony_ci 630d4afb5ceSopenharmony_ci proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), 631d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ETAG, p, end); 632d4afb5ceSopenharmony_ci proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), 633d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, p, end); 634d4afb5ceSopenharmony_ci proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), 635d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end); 636d4afb5ceSopenharmony_ci proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), 637d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_ACCEPT_ENCODING, p, end); 638d4afb5ceSopenharmony_ci proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), 639d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CACHE_CONTROL, p, end); 640d4afb5ceSopenharmony_ci proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf), 641d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COOKIE, p, end); 642d4afb5ceSopenharmony_ci 643d4afb5ceSopenharmony_ci buf[0] = '\0'; 644d4afb5ceSopenharmony_ci lws_get_peer_simple(parent, buf, sizeof(buf)); 645d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, WSI_TOKEN_X_FORWARDED_FOR, 646d4afb5ceSopenharmony_ci (unsigned char *)buf, (int)strlen(buf), p, end)) 647d4afb5ceSopenharmony_ci return -1; 648d4afb5ceSopenharmony_ci 649d4afb5ceSopenharmony_ci break; 650d4afb5ceSopenharmony_ci#endif 651d4afb5ceSopenharmony_ci 652d4afb5ceSopenharmony_ci#ifdef LWS_WITH_CGI 653d4afb5ceSopenharmony_ci /* CGI IO events (POLLIN/OUT) appear here, our default policy is: 654d4afb5ceSopenharmony_ci * 655d4afb5ceSopenharmony_ci * - POST data goes on subprocess stdin 656d4afb5ceSopenharmony_ci * - subprocess stdout goes on http via writeable callback 657d4afb5ceSopenharmony_ci * - subprocess stderr goes to the logs 658d4afb5ceSopenharmony_ci */ 659d4afb5ceSopenharmony_ci case LWS_CALLBACK_CGI: 660d4afb5ceSopenharmony_ci args = (struct lws_cgi_args *)in; 661d4afb5ceSopenharmony_ci switch (args->ch) { /* which of stdin/out/err ? */ 662d4afb5ceSopenharmony_ci case LWS_STDIN: 663d4afb5ceSopenharmony_ci /* TBD stdin rx flow control */ 664d4afb5ceSopenharmony_ci break; 665d4afb5ceSopenharmony_ci case LWS_STDOUT: 666d4afb5ceSopenharmony_ci if (args->stdwsi[LWS_STDOUT]) 667d4afb5ceSopenharmony_ci /* quench POLLIN on STDOUT until MASTER got writeable */ 668d4afb5ceSopenharmony_ci lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0); 669d4afb5ceSopenharmony_ci wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI; 670d4afb5ceSopenharmony_ci /* when writing to MASTER would not block */ 671d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 672d4afb5ceSopenharmony_ci break; 673d4afb5ceSopenharmony_ci case LWS_STDERR: 674d4afb5ceSopenharmony_ci n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]); 675d4afb5ceSopenharmony_ci if (n < 0) 676d4afb5ceSopenharmony_ci break; 677d4afb5ceSopenharmony_ci n = (int)read(n, buf, sizeof(buf) - 2); 678d4afb5ceSopenharmony_ci if (n > 0) { 679d4afb5ceSopenharmony_ci if (buf[n - 1] != '\n') 680d4afb5ceSopenharmony_ci buf[n++] = '\n'; 681d4afb5ceSopenharmony_ci buf[n] = '\0'; 682d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "CGI-stderr: %s", buf); 683d4afb5ceSopenharmony_ci } 684d4afb5ceSopenharmony_ci break; 685d4afb5ceSopenharmony_ci } 686d4afb5ceSopenharmony_ci break; 687d4afb5ceSopenharmony_ci 688d4afb5ceSopenharmony_ci case LWS_CALLBACK_CGI_TERMINATED: 689d4afb5ceSopenharmony_ci if (wsi->http.cgi) { 690d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "CGI_TERMINATED: %d %" PRIu64, 691d4afb5ceSopenharmony_ci wsi->http.cgi->explicitly_chunked, 692d4afb5ceSopenharmony_ci (uint64_t)wsi->http.cgi->content_length); 693d4afb5ceSopenharmony_ci if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) && 694d4afb5ceSopenharmony_ci !wsi->http.cgi->content_length) { 695d4afb5ceSopenharmony_ci /* send terminating chunk */ 696d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "LWS_CALLBACK_CGI_TERMINATED: ending"); 697d4afb5ceSopenharmony_ci wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END; 698d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 699d4afb5ceSopenharmony_ci lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3); 700d4afb5ceSopenharmony_ci break; 701d4afb5ceSopenharmony_ci } 702d4afb5ceSopenharmony_ci if (wsi->mux_substream && !wsi->cgi_stdout_zero_length) 703d4afb5ceSopenharmony_ci lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0, 704d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL); 705d4afb5ceSopenharmony_ci } 706d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER) 707d4afb5ceSopenharmony_ci if (lws_http_transaction_completed(wsi)) 708d4afb5ceSopenharmony_ci return -1; 709d4afb5ceSopenharmony_ci#endif 710d4afb5ceSopenharmony_ci return 0; 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_ci case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */ 713d4afb5ceSopenharmony_ci args = (struct lws_cgi_args *)in; 714d4afb5ceSopenharmony_ci args->data[args->len] = '\0'; 715d4afb5ceSopenharmony_ci if (!args->stdwsi[LWS_STDIN]) 716d4afb5ceSopenharmony_ci return -1; 717d4afb5ceSopenharmony_ci n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]); 718d4afb5ceSopenharmony_ci if (n < 0) 719d4afb5ceSopenharmony_ci return -1; 720d4afb5ceSopenharmony_ci 721d4afb5ceSopenharmony_ci#if defined(LWS_WITH_ZLIB) 722d4afb5ceSopenharmony_ci if (wsi->http.cgi->gzip_inflate) { 723d4afb5ceSopenharmony_ci /* gzip handling */ 724d4afb5ceSopenharmony_ci 725d4afb5ceSopenharmony_ci if (!wsi->http.cgi->gzip_init) { 726d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "inflating gzip"); 727d4afb5ceSopenharmony_ci 728d4afb5ceSopenharmony_ci memset(&wsi->http.cgi->inflate, 0, 729d4afb5ceSopenharmony_ci sizeof(wsi->http.cgi->inflate)); 730d4afb5ceSopenharmony_ci 731d4afb5ceSopenharmony_ci if (inflateInit2(&wsi->http.cgi->inflate, 732d4afb5ceSopenharmony_ci 16 + 15) != Z_OK) { 733d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "iniflateInit fail"); 734d4afb5ceSopenharmony_ci return -1; 735d4afb5ceSopenharmony_ci } 736d4afb5ceSopenharmony_ci 737d4afb5ceSopenharmony_ci wsi->http.cgi->gzip_init = 1; 738d4afb5ceSopenharmony_ci } 739d4afb5ceSopenharmony_ci 740d4afb5ceSopenharmony_ci wsi->http.cgi->inflate.next_in = args->data; 741d4afb5ceSopenharmony_ci wsi->http.cgi->inflate.avail_in = (unsigned int)args->len; 742d4afb5ceSopenharmony_ci 743d4afb5ceSopenharmony_ci do { 744d4afb5ceSopenharmony_ci 745d4afb5ceSopenharmony_ci wsi->http.cgi->inflate.next_out = 746d4afb5ceSopenharmony_ci wsi->http.cgi->inflate_buf; 747d4afb5ceSopenharmony_ci wsi->http.cgi->inflate.avail_out = 748d4afb5ceSopenharmony_ci sizeof(wsi->http.cgi->inflate_buf); 749d4afb5ceSopenharmony_ci 750d4afb5ceSopenharmony_ci n = inflate(&wsi->http.cgi->inflate, 751d4afb5ceSopenharmony_ci Z_SYNC_FLUSH); 752d4afb5ceSopenharmony_ci 753d4afb5ceSopenharmony_ci switch (n) { 754d4afb5ceSopenharmony_ci case Z_NEED_DICT: 755d4afb5ceSopenharmony_ci case Z_STREAM_ERROR: 756d4afb5ceSopenharmony_ci case Z_DATA_ERROR: 757d4afb5ceSopenharmony_ci case Z_MEM_ERROR: 758d4afb5ceSopenharmony_ci inflateEnd(&wsi->http.cgi->inflate); 759d4afb5ceSopenharmony_ci wsi->http.cgi->gzip_init = 0; 760d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "zlib err inflate %d", n); 761d4afb5ceSopenharmony_ci return -1; 762d4afb5ceSopenharmony_ci } 763d4afb5ceSopenharmony_ci 764d4afb5ceSopenharmony_ci if (wsi->http.cgi->inflate.avail_out != 765d4afb5ceSopenharmony_ci sizeof(wsi->http.cgi->inflate_buf)) { 766d4afb5ceSopenharmony_ci int written; 767d4afb5ceSopenharmony_ci 768d4afb5ceSopenharmony_ci written = (int)write(args->stdwsi[LWS_STDIN]->desc.filefd, 769d4afb5ceSopenharmony_ci wsi->http.cgi->inflate_buf, 770d4afb5ceSopenharmony_ci sizeof(wsi->http.cgi->inflate_buf) - 771d4afb5ceSopenharmony_ci wsi->http.cgi->inflate.avail_out); 772d4afb5ceSopenharmony_ci 773d4afb5ceSopenharmony_ci if (written != (int)( 774d4afb5ceSopenharmony_ci sizeof(wsi->http.cgi->inflate_buf) - 775d4afb5ceSopenharmony_ci wsi->http.cgi->inflate.avail_out)) { 776d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, 777d4afb5ceSopenharmony_ci "CGI_STDIN_DATA: " 778d4afb5ceSopenharmony_ci "sent %d only %d went", 779d4afb5ceSopenharmony_ci n, args->len); 780d4afb5ceSopenharmony_ci } 781d4afb5ceSopenharmony_ci 782d4afb5ceSopenharmony_ci if (n == Z_STREAM_END) { 783d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, 784d4afb5ceSopenharmony_ci "gzip inflate end"); 785d4afb5ceSopenharmony_ci inflateEnd(&wsi->http.cgi->inflate); 786d4afb5ceSopenharmony_ci wsi->http.cgi->gzip_init = 0; 787d4afb5ceSopenharmony_ci break; 788d4afb5ceSopenharmony_ci } 789d4afb5ceSopenharmony_ci 790d4afb5ceSopenharmony_ci } else 791d4afb5ceSopenharmony_ci break; 792d4afb5ceSopenharmony_ci 793d4afb5ceSopenharmony_ci if (wsi->http.cgi->inflate.avail_out) 794d4afb5ceSopenharmony_ci break; 795d4afb5ceSopenharmony_ci 796d4afb5ceSopenharmony_ci } while (1); 797d4afb5ceSopenharmony_ci 798d4afb5ceSopenharmony_ci return args->len; 799d4afb5ceSopenharmony_ci } 800d4afb5ceSopenharmony_ci#endif /* WITH_ZLIB */ 801d4afb5ceSopenharmony_ci 802d4afb5ceSopenharmony_ci n = (int)write(n, args->data, (unsigned int)args->len); 803d4afb5ceSopenharmony_ci// lwsl_hexdump_notice(args->data, args->len); 804d4afb5ceSopenharmony_ci if (n < args->len) 805d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "CGI_STDIN_DATA: " 806d4afb5ceSopenharmony_ci "sent %d only %d went", n, args->len); 807d4afb5ceSopenharmony_ci 808d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "proxied %d bytes", n); 809d4afb5ceSopenharmony_ci 810d4afb5ceSopenharmony_ci if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] && 811d4afb5ceSopenharmony_ci args->stdwsi[LWS_STDIN]->desc.filefd > 0) { 812d4afb5ceSopenharmony_ci wsi->http.cgi->post_in_expected -= (unsigned int)n; 813d4afb5ceSopenharmony_ci 814d4afb5ceSopenharmony_ci if (!wsi->http.cgi->post_in_expected) { 815d4afb5ceSopenharmony_ci struct lws *siwsi = args->stdwsi[LWS_STDIN]; 816d4afb5ceSopenharmony_ci 817d4afb5ceSopenharmony_ci /* 818d4afb5ceSopenharmony_ci * The situation here is that we finished 819d4afb5ceSopenharmony_ci * proxying the incoming body from the net to 820d4afb5ceSopenharmony_ci * the STDIN stdwsi... and we want to close it 821d4afb5ceSopenharmony_ci * so it can understand we are done (necessary 822d4afb5ceSopenharmony_ci * if no content-length)... 823d4afb5ceSopenharmony_ci */ 824d4afb5ceSopenharmony_ci 825d4afb5ceSopenharmony_ci lwsl_wsi_info(siwsi, "expected POST in end: " 826d4afb5ceSopenharmony_ci "closing stdin fd %d", 827d4afb5ceSopenharmony_ci siwsi->desc.sockfd); 828d4afb5ceSopenharmony_ci 829d4afb5ceSopenharmony_ci /* 830d4afb5ceSopenharmony_ci * We don't want the child / parent relationship 831d4afb5ceSopenharmony_ci * to be handled in close, since we want the 832d4afb5ceSopenharmony_ci * rest of the cgi and children to stay up 833d4afb5ceSopenharmony_ci */ 834d4afb5ceSopenharmony_ci 835d4afb5ceSopenharmony_ci lws_remove_child_from_any_parent(siwsi); 836d4afb5ceSopenharmony_ci lws_wsi_close(siwsi, LWS_TO_KILL_ASYNC); 837d4afb5ceSopenharmony_ci wsi->http.cgi->lsp->stdwsi[LWS_STDIN] = NULL; 838d4afb5ceSopenharmony_ci lws_spawn_stdwsi_closed(wsi->http.cgi->lsp, siwsi); 839d4afb5ceSopenharmony_ci } 840d4afb5ceSopenharmony_ci } 841d4afb5ceSopenharmony_ci 842d4afb5ceSopenharmony_ci return n; 843d4afb5ceSopenharmony_ci#endif /* WITH_CGI */ 844d4afb5ceSopenharmony_ci#endif /* ROLE_ H1 / H2 */ 845d4afb5ceSopenharmony_ci case LWS_CALLBACK_SSL_INFO: 846d4afb5ceSopenharmony_ci si = in; 847d4afb5ceSopenharmony_ci 848d4afb5ceSopenharmony_ci (void)si; 849d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "SSL_INFO: where: 0x%x, ret: 0x%x", 850d4afb5ceSopenharmony_ci si->where, si->ret); 851d4afb5ceSopenharmony_ci break; 852d4afb5ceSopenharmony_ci 853d4afb5ceSopenharmony_ci#if LWS_MAX_SMP > 1 854d4afb5ceSopenharmony_ci case LWS_CALLBACK_GET_THREAD_ID: 855d4afb5ceSopenharmony_ci#ifdef __PTW32_H 856d4afb5ceSopenharmony_ci /* If we use implementation of PThreads for Win that is 857d4afb5ceSopenharmony_ci * distributed by VCPKG */ 858d4afb5ceSopenharmony_ci return (int)(lws_intptr_t)(pthread_self()).p; 859d4afb5ceSopenharmony_ci#else 860d4afb5ceSopenharmony_ci return (int)(lws_intptr_t)pthread_self(); 861d4afb5ceSopenharmony_ci#endif // __PTW32_H 862d4afb5ceSopenharmony_ci#endif 863d4afb5ceSopenharmony_ci 864d4afb5ceSopenharmony_ci default: 865d4afb5ceSopenharmony_ci break; 866d4afb5ceSopenharmony_ci } 867d4afb5ceSopenharmony_ci 868d4afb5ceSopenharmony_ci return 0; 869d4afb5ceSopenharmony_ci} 870