{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1711666692,
"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":"75141b0c4e55b6087a5246ab210c5884",
"oid":{ "oid": "e4be3317ee421f951fb16a85c7edacc9b8a0e6aa", "alias": [ "refs/heads/main"]},"blobname": "lib/roles/cgi/cgi-server.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#if !defined(_GNU_SOURCE)\n#define _GNU_SOURCE\n#endif\n\n#include \u0022private-lib-core.h\u0022\n\n#if defined(WIN32) || defined(_WIN32)\n#else\n#include \u003csys/wait.h\u003e\n#endif\n\nstatic const char *hex \u003d \u00220123456789ABCDEF\u0022;\n\nvoid\nlws_cgi_sul_cb(lws_sorted_usec_list_t *sul);\n\nstatic int\nurlencode(const char *in, int inlen, char *out, int outlen)\n{\n\tchar *start \u003d out, *end \u003d out + outlen;\n\n\twhile (inlen-- \u0026\u0026 out \u003c end - 4) {\n\t\tif ((*in \u003e\u003d 'A' \u0026\u0026 *in \u003c\u003d 'Z') ||\n\t\t (*in \u003e\u003d 'a' \u0026\u0026 *in \u003c\u003d 'z') ||\n\t\t (*in \u003e\u003d '0' \u0026\u0026 *in \u003c\u003d '9') ||\n\t\t *in \u003d\u003d '-' ||\n\t\t *in \u003d\u003d '_' ||\n\t\t *in \u003d\u003d '.' ||\n\t\t *in \u003d\u003d '~') {\n\t\t\t*out++ \u003d *in++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (*in \u003d\u003d ' ') {\n\t\t\t*out++ \u003d '+';\n\t\t\tin++;\n\t\t\tcontinue;\n\t\t}\n\t\t*out++ \u003d '%';\n\t\t*out++ \u003d hex[(*in) \u003e\u003e 4];\n\t\t*out++ \u003d hex[(*in++) \u0026 15];\n\t}\n\t*out \u003d '\u005c0';\n\n\tif (out \u003e\u003d end - 4)\n\t\treturn -1;\n\n\treturn lws_ptr_diff(out, start);\n}\n\nstatic void\nlws_cgi_grace(lws_sorted_usec_list_t *sul)\n{\n\tstruct lws_cgi *cgi \u003d lws_container_of(sul, struct lws_cgi, sul_grace);\n\n\t/* act on the reap cb from earlier */\n\n\tif (!cgi-\u003ewsi-\u003ehttp.cgi-\u003epost_in_expected)\n\t\tcgi-\u003ewsi-\u003ehttp.cgi-\u003ecgi_transaction_over \u003d 1;\n\n\tlws_callback_on_writable(cgi-\u003ewsi);\n}\n\n\nstatic void\nlws_cgi_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si,\n\t\t int we_killed_him)\n{\n\tstruct lws *wsi \u003d (struct lws *)opaque;\n\tstruct lws_cgi_args args;\n\n\tif (wsi-\u003ehttp.cgi \u0026\u0026\n\t user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback, wsi,\n\t\t\t\t\tLWS_CALLBACK_CGI_TERMINATED,\n\t\t\t\t\twsi-\u003euser_space, (void *)\u0026args,\n\t\t\t\t\t(unsigned int)wsi-\u003ehttp.cgi-\u003epi))\n\t\tlwsl_notice(\u0022\u005cn\u0022);\n\n\t/*\n\t * The cgi has come to an end, by itself or with a signal...\n\t */\n\n\tif (wsi-\u003ehttp.cgi)\n\t\tlwsl_wsi_info(wsi, \u0022post_in_expected %d\u0022,\n\t\t\t (int)wsi-\u003ehttp.cgi-\u003epost_in_expected);\n\n\t/*\n\t * Grace period to handle the incoming stdout\n\t */\n\n\tif (wsi-\u003ehttp.cgi)\n\t\tlws_sul_schedule(wsi-\u003ea.context, wsi-\u003etsi, \u0026wsi-\u003ehttp.cgi-\u003esul_grace,\n\t\t\t lws_cgi_grace, 1 * LWS_US_PER_SEC);\n}\n\nint\nlws_cgi(struct lws *wsi, const char * const *exec_array,\n\tint script_uri_path_len, int timeout_secs,\n\tconst struct lws_protocol_vhost_options *mp_cgienv)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003ea.context-\u003ept[(int)wsi-\u003etsi];\n\tstruct lws_spawn_piped_info info;\n\tchar *env_array[30], cgi_path[500], e[1024], *p \u003d e,\n\t *end \u003d p + sizeof(e) - 1, tok[256], *t, *sum, *sumend;\n\tstruct lws_cgi *cgi;\n\tint n, m \u003d 0, i, uritok \u003d -1, c;\n\n\t/*\n\t * give the cgi stream wsi a cgi struct\n\t */\n\n\twsi-\u003ehttp.cgi \u003d lws_zalloc(sizeof(*wsi-\u003ehttp.cgi), \u0022new cgi\u0022);\n\tif (!wsi-\u003ehttp.cgi) {\n\t\tlwsl_wsi_err(wsi, \u0022OOM\u0022);\n\t\treturn -1;\n\t}\n\n\twsi-\u003ehttp.cgi-\u003eresponse_code \u003d HTTP_STATUS_OK;\n\n\tcgi \u003d wsi-\u003ehttp.cgi;\n\tcgi-\u003ewsi \u003d wsi; /* set cgi's owning wsi */\n\tsum \u003d cgi-\u003esummary;\n\tsumend \u003d sum + strlen(cgi-\u003esummary) - 1;\n\n\tif (timeout_secs)\n\t\tlws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);\n\n\t/* the cgi stdout is always sending us http1.x header data first */\n\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n\n\t/* add us to the pt list of active cgis */\n\tlwsl_wsi_debug(wsi, \u0022adding cgi %p to list\u0022, wsi-\u003ehttp.cgi);\n\tcgi-\u003ecgi_list \u003d pt-\u003ehttp.cgi_list;\n\tpt-\u003ehttp.cgi_list \u003d cgi;\n\n\t/* if it's not already running, start the cleanup timer */\n\tif (!pt-\u003esul_cgi.list.owner)\n\t\tlws_sul_schedule(pt-\u003econtext, (int)(pt - pt-\u003econtext-\u003ept), \u0026pt-\u003esul_cgi,\n\t\t\t\t lws_cgi_sul_cb, 3 * LWS_US_PER_SEC);\n\n\tsum +\u003d lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), \u0022%s \u0022, exec_array[0]);\n\n\tif (0) {\n\t\tchar *pct \u003d lws_hdr_simple_ptr(wsi,\n\t\t\t\tWSI_TOKEN_HTTP_CONTENT_ENCODING);\n\n\t\tif (pct \u0026\u0026 !strcmp(pct, \u0022gzip\u0022))\n\t\t\twsi-\u003ehttp.cgi-\u003egzip_inflate \u003d 1;\n\t}\n\n\t/* prepare his CGI env */\n\n\tn \u003d 0;\n\n\tif (lws_is_ssl(wsi)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTPS\u003dON\u0022);\n\t\tp++;\n\t}\n\n\tif (wsi-\u003ehttp.ah) {\n\t\tstatic const unsigned char meths[] \u003d {\n\t\t\tWSI_TOKEN_GET_URI,\n\t\t\tWSI_TOKEN_POST_URI,\n#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)\n\t\t\tWSI_TOKEN_OPTIONS_URI,\n\t\t\tWSI_TOKEN_PUT_URI,\n\t\t\tWSI_TOKEN_PATCH_URI,\n\t\t\tWSI_TOKEN_DELETE_URI,\n#endif\n\t\t\tWSI_TOKEN_CONNECT,\n\t\t\tWSI_TOKEN_HEAD_URI,\n\t\t#ifdef LWS_WITH_HTTP2\n\t\t\tWSI_TOKEN_HTTP_COLON_PATH,\n\t\t#endif\n\t\t};\n\t\tstatic const char * const meth_names[] \u003d {\n\t\t\t\u0022GET\u0022, \u0022POST\u0022,\n#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)\n\t\t\t\u0022OPTIONS\u0022, \u0022PUT\u0022, \u0022PATCH\u0022, \u0022DELETE\u0022,\n#endif\n\t\t\t\u0022CONNECT\u0022, \u0022HEAD\u0022, \u0022:path\u0022\n\t\t};\n\n\t\tif (script_uri_path_len \u003e\u003d 0)\n\t\t\tfor (m \u003d 0; m \u003c (int)LWS_ARRAY_SIZE(meths); m++)\n\t\t\t\tif (lws_hdr_total_length(wsi, meths[m]) \u003e\u003d\n\t\t\t\t\t\tscript_uri_path_len) {\n\t\t\t\t\turitok \u003d meths[m];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\tif (script_uri_path_len \u003c 0 \u0026\u0026 uritok \u003c 0)\n\t\t\tgoto bail;\n//\t\tif (script_uri_path_len \u003c 0)\n//\t\t\turitok \u003d 0;\n\n\t\tif (m \u003e\u003d 0) {\n\t\t\tenv_array[n++] \u003d p;\n\t\t\tif (m \u003c (int)LWS_ARRAY_SIZE(meths) - 1) {\n\t\t\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p),\n\t\t\t\t\t\t \u0022REQUEST_METHOD\u003d%s\u0022,\n\t\t\t\t\t\t meth_names[m]);\n\t\t\t\tsum +\u003d lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), \u0022%s \u0022,\n\t\t\t\t\t\t meth_names[m]);\n#if defined(LWS_ROLE_H2)\n\t\t\t} else {\n\t\t\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p),\n\t\t\t\t\t\t \u0022REQUEST_METHOD\u003d%s\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD));\n\t\t\t\tsum +\u003d lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), \u0022%s \u0022,\n\t\t\t\t\tlws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\t WSI_TOKEN_HTTP_COLON_METHOD));\n#endif\n\t\t\t}\n\t\t\tp++;\n\t\t}\n\n\t\tif (uritok \u003e\u003d 0)\n\t\t\tsum +\u003d lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), \u0022%s \u0022,\n\t\t\t\t\t lws_hdr_simple_ptr(wsi, (enum lws_token_indexes)uritok));\n\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022QUERY_STRING\u003d\u0022);\n\t\t/* dump the individual URI Arg parameters */\n\t\tm \u003d 0;\n\t\twhile (script_uri_path_len \u003e\u003d 0) {\n\t\t\ti \u003d lws_hdr_copy_fragment(wsi, tok, sizeof(tok),\n\t\t\t\t\t WSI_TOKEN_HTTP_URI_ARGS, m);\n\t\t\tif (i \u003c 0)\n\t\t\t\tbreak;\n\t\t\tt \u003d tok;\n\t\t\twhile (*t \u0026\u0026 *t !\u003d '\u003d' \u0026\u0026 p \u003c end - 4)\n\t\t\t\t*p++ \u003d *t++;\n\t\t\tif (*t \u003d\u003d '\u003d')\n\t\t\t\t*p++ \u003d *t++;\n\t\t\ti \u003d urlencode(t, i - lws_ptr_diff(t, tok), p, lws_ptr_diff(end, p));\n\t\t\tif (i \u003e 0) {\n\t\t\t\tp +\u003d i;\n\t\t\t\t*p++ \u003d '\u0026';\n\t\t\t}\n\t\t\tm++;\n\t\t}\n\t\tif (m)\n\t\t\tp--;\n\t\t*p++ \u003d '\u005c0';\n\n\t\tif (uritok \u003e\u003d 0) {\n\t\t\tstrcpy(cgi_path, \u0022REQUEST_URI\u003d\u0022);\n\t\t\tc \u003d lws_hdr_copy(wsi, cgi_path + 12,\n\t\t\t\t\t sizeof(cgi_path) - 12, (enum lws_token_indexes)uritok);\n\t\t\tif (c \u003c 0)\n\t\t\t\tgoto bail;\n\n\t\t\tcgi_path[sizeof(cgi_path) - 1] \u003d '\u005c0';\n\t\t\tenv_array[n++] \u003d cgi_path;\n\t\t}\n\n\t\tsum +\u003d lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), \u0022%s\u0022, env_array[n - 1]);\n\n\t\tif (script_uri_path_len \u003e\u003d 0) {\n\t\t\tenv_array[n++] \u003d p;\n\t\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022PATH_INFO\u003d%s\u0022,\n\t\t\t\t cgi_path + 12 + script_uri_path_len);\n\t\t\tp++;\n\t\t}\n\t}\n#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_REFERER\u003d%s\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER));\n\t\tp++;\n\t}\n#endif\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_HOST\u003d%s\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));\n\t\tp++;\n\t}\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_COOKIE\u003d\u0022);\n\t\tm \u003d lws_hdr_copy(wsi, p, lws_ptr_diff(end, p), WSI_TOKEN_HTTP_COOKIE);\n\t\tif (m \u003e 0)\n\t\t\tp +\u003d lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE);\n\t\t*p++ \u003d '\u005c0';\n\t}\n#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS)\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_USER_AGENT\u003d%s\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT));\n\t\tp++;\n\t}\n#endif\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_CONTENT_ENCODING\u003d%s\u0022,\n\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING));\n\t\tp++;\n\t}\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_ACCEPT\u003d%s\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT));\n\t\tp++;\n\t}\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022HTTP_ACCEPT_ENCODING\u003d%s\u0022,\n\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING));\n\t\tp++;\n\t}\n\tif (script_uri_path_len \u003e\u003d 0 \u0026\u0026\n\t uritok \u003d\u003d WSI_TOKEN_POST_URI) {\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {\n\t\t\tenv_array[n++] \u003d p;\n\t\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022CONTENT_TYPE\u003d%s\u0022,\n\t\t\t lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE));\n\t\t\tp++;\n\t\t}\n\t\tif (!wsi-\u003ehttp.cgi-\u003egzip_inflate \u0026\u0026\n\t\t lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {\n\t\t\tenv_array[n++] \u003d p;\n\t\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022CONTENT_LENGTH\u003d%s\u0022,\n\t\t\t\t\t lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t WSI_TOKEN_HTTP_CONTENT_LENGTH));\n\t\t\tp++;\n\t\t}\n\n\t\tif (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))\n\t\t\twsi-\u003ehttp.cgi-\u003epost_in_expected \u003d (lws_filepos_t)\n\t\t\t\tatoll(lws_hdr_simple_ptr(wsi,\n\t\t\t\t\t\tWSI_TOKEN_HTTP_CONTENT_LENGTH));\n\t}\n\n\n\tenv_array[n++] \u003d p;\n\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022PATH\u003d/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin\u0022);\n\tp++;\n\n\tenv_array[n++] \u003d p;\n\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022SCRIPT_PATH\u003d%s\u0022, exec_array[0]);\n\tp++;\n\n\twhile (mp_cgienv) {\n\t\tenv_array[n++] \u003d p;\n\t\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022%s\u003d%s\u0022, mp_cgienv-\u003ename,\n\t\t\t mp_cgienv-\u003evalue);\n\t\tif (!strcmp(mp_cgienv-\u003ename, \u0022GIT_PROJECT_ROOT\u0022)) {\n\t\t\twsi-\u003ehttp.cgi-\u003eimplied_chunked \u003d 1;\n\t\t\twsi-\u003ehttp.cgi-\u003eexplicitly_chunked \u003d 1;\n\t\t}\n\t\tlwsl_info(\u0022 Applying mount-specific cgi env '%s'\u005cn\u0022,\n\t\t\t env_array[n - 1]);\n\t\tp++;\n\t\tmp_cgienv \u003d mp_cgienv-\u003enext;\n\t}\n\n\tenv_array[n++] \u003d p;\n\tp +\u003d lws_snprintf(p, lws_ptr_diff_size_t(end, p), \u0022SERVER_SOFTWARE\u003dlws\u0022);\n\tp++;\n\n\tenv_array[n] \u003d NULL;\n\n#if 0\n\tfor (m \u003d 0; m \u003c n; m++)\n\t\tlwsl_notice(\u0022 %s\u005cn\u0022, env_array[m]);\n#endif\n\n\tmemset(\u0026info, 0, sizeof(info));\n\tinfo.env_array \u003d (const char **)env_array;\n\tinfo.exec_array \u003d exec_array;\n\tinfo.max_log_lines \u003d 20000;\n\tinfo.opt_parent \u003d wsi;\n\tinfo.timeout_us \u003d 5 * 60 * LWS_US_PER_SEC;\n\tinfo.tsi \u003d wsi-\u003etsi;\n\tinfo.vh \u003d wsi-\u003ea.vhost;\n\tinfo.ops \u003d \u0026role_ops_cgi;\n\tinfo.plsp \u003d \u0026wsi-\u003ehttp.cgi-\u003elsp;\n\tinfo.opaque \u003d wsi;\n\tinfo.reap_cb \u003d lws_cgi_reap_cb;\n\n\t/*\n\t * Actually having made the env, as a cgi we don't need the ah\n\t * any more\n\t */\n\tif (script_uri_path_len \u003e\u003d 0) {\n\t\tlws_header_table_detach(wsi, 0);\n\t\tinfo.disable_ctrlc \u003d 1;\n\t}\n\n\twsi-\u003ehttp.cgi-\u003elsp \u003d lws_spawn_piped(\u0026info);\n\tif (!wsi-\u003ehttp.cgi-\u003elsp) {\n\t\tlwsl_err(\u0022%s: spawn failed\u005cn\u0022, __func__);\n\t\tgoto bail;\n\t}\n\n\twsi-\u003ehttp.cgi-\u003epi \u003d wsi-\u003ehttp.cgi-\u003elsp-\u003echild_pid;\n\n\t/* we are the parent process */\n\n\twsi-\u003ea.context-\u003ecount_cgi_spawned++;\n\n\t/* inform cgi owner of the child PID */\n\tn \u003d user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback, wsi,\n\t\t\t\t LWS_CALLBACK_CGI_PROCESS_ATTACH,\n\t\t\t\t wsi-\u003euser_space, NULL, (unsigned int)cgi-\u003elsp-\u003echild_pid);\n\t(void)n;\n\n\treturn 0;\n\nbail:\n\tlws_sul_cancel(\u0026wsi-\u003ehttp.cgi-\u003esul_grace);\n\tlws_free_set_NULL(wsi-\u003ehttp.cgi);\n\n\tlwsl_err(\u0022%s: failed\u005cn\u0022, __func__);\n\n\treturn -1;\n}\n\n/* we have to parse out these headers in the CGI output */\n\nstatic const char * const significant_hdr[SIGNIFICANT_HDR_COUNT] \u003d {\n\t\u0022content-length: \u0022,\n\t\u0022location: \u0022,\n\t\u0022status: \u0022,\n\t\u0022transfer-encoding: chunked\u0022,\n\t\u0022content-encoding: gzip\u0022,\n};\n\nenum header_recode {\n\tHR_NAME,\n\tHR_WHITESPACE,\n\tHR_ARG,\n\tHR_CRLF,\n};\n\nint\nlws_cgi_write_split_stdout_headers(struct lws *wsi)\n{\n\tint n, m, cmd;\n\tunsigned char buf[LWS_PRE + 4096], *start \u003d \u0026buf[LWS_PRE], *p \u003d start,\n\t\t\t*end \u003d \u0026buf[sizeof(buf) - 1 - LWS_PRE], *name,\n\t\t\t*value \u003d NULL;\n\tchar c, hrs;\n\n\tif (!wsi-\u003ehttp.cgi)\n\t\treturn -1;\n\n\twhile (wsi-\u003ehdr_state !\u003d LHCS_PAYLOAD) {\n\t\t/*\n\t\t * We have to separate header / finalize and payload chunks,\n\t\t * since they need to be handled separately\n\t\t */\n\t\tswitch (wsi-\u003ehdr_state) {\n\t\tcase LHCS_RESPONSE:\n\t\t\tlwsl_wsi_debug(wsi, \u0022LHCS_RESPONSE: iss response %d\u0022,\n\t\t\t\t\t wsi-\u003ehttp.cgi-\u003eresponse_code);\n\t\t\tif (lws_add_http_header_status(wsi,\n\t\t\t\t\t\t (unsigned int)wsi-\u003ehttp.cgi-\u003eresponse_code,\n\t\t\t\t\t\t \u0026p, end))\n\t\t\t\treturn 1;\n\t\t\tif (!wsi-\u003ehttp.cgi-\u003eexplicitly_chunked \u0026\u0026\n\t\t\t !wsi-\u003ehttp.cgi-\u003econtent_length \u0026\u0026\n\t\t\t\tlws_add_http_header_by_token(wsi,\n\t\t\t\t\tWSI_TOKEN_HTTP_TRANSFER_ENCODING,\n\t\t\t\t\t(unsigned char *)\u0022chunked\u0022, 7, \u0026p, end))\n\t\t\t\treturn 1;\n\t\t\tif (!(wsi-\u003emux_substream))\n\t\t\t\tif (lws_add_http_header_by_token(wsi,\n\t\t\t\t\t\tWSI_TOKEN_CONNECTION,\n\t\t\t\t\t\t(unsigned char *)\u0022close\u0022, 5,\n\t\t\t\t\t\t\u0026p, end))\n\t\t\t\t\treturn 1;\n\t\t\tn \u003d lws_write(wsi, start, lws_ptr_diff_size_t(p, start),\n\t\t\t\t LWS_WRITE_HTTP_HEADERS | LWS_WRITE_NO_FIN);\n\n\t\t\t/*\n\t\t\t * so we have a bunch of http/1 style ascii headers\n\t\t\t * starting from wsi-\u003ehttp.cgi-\u003eheaders_buf through\n\t\t\t * wsi-\u003ehttp.cgi-\u003eheaders_pos. These are OK for http/1\n\t\t\t * connections, but they're no good for http/2 conns.\n\t\t\t *\n\t\t\t * Let's redo them at headers_pos forward using the\n\t\t\t * correct coding for http/1 or http/2\n\t\t\t */\n\t\t\tif (!wsi-\u003emux_substream)\n\t\t\t\tgoto post_hpack_recode;\n\n\t\t\tp \u003d wsi-\u003ehttp.cgi-\u003eheaders_start;\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_start \u003d\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003eheaders_pos;\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_dumped \u003d\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003eheaders_start;\n\t\t\thrs \u003d HR_NAME;\n\t\t\tname \u003d buf;\n\n\t\t\twhile (p \u003c wsi-\u003ehttp.cgi-\u003eheaders_start) {\n\t\t\t\tswitch (hrs) {\n\t\t\t\tcase HR_NAME:\n\t\t\t\t\t/*\n\t\t\t\t\t * in http/2 upper-case header names\n\t\t\t\t\t * are illegal. So convert to lower-\n\t\t\t\t\t * case.\n\t\t\t\t\t */\n\t\t\t\t\tif (name - buf \u003e 64)\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\tif (*p !\u003d ':') {\n\t\t\t\t\t\tif (*p \u003e\u003d 'A' \u0026\u0026 *p \u003c\u003d 'Z')\n\t\t\t\t\t\t\t*name++ \u003d (unsigned char)((*p++) +\n\t\t\t\t\t\t\t\t ('a' - 'A'));\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t*name++ \u003d *p++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp++;\n\t\t\t\t\t\t*name++ \u003d '\u005c0';\n\t\t\t\t\t\tvalue \u003d name;\n\t\t\t\t\t\thrs \u003d HR_WHITESPACE;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase HR_WHITESPACE:\n\t\t\t\t\tif (*p \u003d\u003d ' ') {\n\t\t\t\t\t\tp++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\thrs \u003d HR_ARG;\n\t\t\t\t\t/* fallthru */\n\t\t\t\tcase HR_ARG:\n\t\t\t\t\tif (name \u003e end - 64)\n\t\t\t\t\t\treturn -1;\n\n\t\t\t\t\tif (*p !\u003d '\u005cx0a' \u0026\u0026 *p !\u003d '\u005cx0d') {\n\t\t\t\t\t\t*name++ \u003d *p++;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\thrs \u003d HR_CRLF;\n\t\t\t\t\t/* fallthru */\n\t\t\t\tcase HR_CRLF:\n\t\t\t\t\tif ((*p !\u003d '\u005cx0a' \u0026\u0026 *p !\u003d '\u005cx0d') ||\n\t\t\t\t\t p + 1 \u003d\u003d wsi-\u003ehttp.cgi-\u003eheaders_start) {\n\t\t\t\t\t\t*name \u003d '\u005c0';\n\t\t\t\t\t\tif ((strcmp((const char *)buf,\n\t\t\t\t\t\t\t \u0022transfer-encoding\u0022)\n\t\t\t\t\t\t)) {\n\t\t\t\t\t\t\tlwsl_debug(\u0022+ %s: %s\u005cn\u0022,\n\t\t\t\t\t\t\t\t buf, value);\n\t\t\t\t\t\t\tif (\n\t\t\t\t\tlws_add_http_header_by_name(wsi, buf,\n\t\t\t\t\t(unsigned char *)value, lws_ptr_diff(name, value),\n\t\t\t\t\t(unsigned char **)\u0026wsi-\u003ehttp.cgi-\u003eheaders_pos,\n\t\t\t\t\t(unsigned char *)wsi-\u003ehttp.cgi-\u003eheaders_end))\n\t\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t\thrs \u003d HR_NAME;\n\t\t\t\t\t\t\tname \u003d buf;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tp++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\npost_hpack_recode:\n\t\t\t/* finalize cached headers before dumping them */\n\t\t\tif (lws_finalize_http_header(wsi,\n\t\t\t (unsigned char **)\u0026wsi-\u003ehttp.cgi-\u003eheaders_pos,\n\t\t\t (unsigned char *)wsi-\u003ehttp.cgi-\u003eheaders_end)) {\n\n\t\t\t\tlwsl_notice(\u0022finalize failed\u005cn\u0022);\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\twsi-\u003ehdr_state \u003d LHCS_DUMP_HEADERS;\n\t\t\twsi-\u003ereason_bf |\u003d LWS_CB_REASON_AUX_BF__CGI_HEADERS;\n\t\t\tlws_callback_on_writable(wsi);\n\t\t\t/* back to the loop for writeability again */\n\t\t\treturn 0;\n\n\t\tcase LHCS_DUMP_HEADERS:\n\n\t\t\tn \u003d (int)(wsi-\u003ehttp.cgi-\u003eheaders_pos -\n\t\t\t wsi-\u003ehttp.cgi-\u003eheaders_dumped);\n\t\t\tif (n \u003e 512)\n\t\t\t\tn \u003d 512;\n\n\t\t\tlwsl_wsi_debug(wsi, \u0022LHCS_DUMP_HEADERS: %d\u0022, n);\n\n\t\t\tcmd \u003d LWS_WRITE_HTTP_HEADERS_CONTINUATION;\n\t\t\tif (wsi-\u003ehttp.cgi-\u003eheaders_dumped + n !\u003d\n\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003eheaders_pos) {\n\t\t\t\tlwsl_notice(\u0022adding no fin flag\u005cn\u0022);\n\t\t\t\tcmd |\u003d LWS_WRITE_NO_FIN;\n\t\t\t}\n\n\t\t\tm \u003d lws_write(wsi,\n\t\t\t\t (unsigned char *)wsi-\u003ehttp.cgi-\u003eheaders_dumped,\n\t\t\t\t (unsigned int)n, (enum lws_write_protocol)cmd);\n\t\t\tif (m \u003c 0) {\n\t\t\t\tlwsl_wsi_debug(wsi, \u0022write says %d\u0022, m);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_dumped +\u003d n;\n\t\t\tif (wsi-\u003ehttp.cgi-\u003eheaders_dumped \u003d\u003d\n\t\t\t wsi-\u003ehttp.cgi-\u003eheaders_pos) {\n\t\t\t\twsi-\u003ehdr_state \u003d LHCS_PAYLOAD;\n\t\t\t\tlws_free_set_NULL(wsi-\u003ehttp.cgi-\u003eheaders_buf);\n\t\t\t\tlwsl_wsi_debug(wsi, \u0022freed cgi headers\u0022);\n\n\t\t\t\tif (wsi-\u003ehttp.cgi-\u003epost_in_expected) {\n\t\t\t\t\tlwsl_wsi_info(wsi, \u0022post data still \u0022\n\t\t\t\t\t\t\t \u0022expected, asking \u0022\n\t\t\t\t\t\t\t \u0022for writeable\u0022);\n\t\t\t\t\tlws_callback_on_writable(wsi);\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\twsi-\u003ereason_bf |\u003d\n\t\t\t\t\tLWS_CB_REASON_AUX_BF__CGI_HEADERS;\n\t\t\t\tlws_callback_on_writable(wsi);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * writeability becomes uncertain now we wrote\n\t\t\t * something, we must return to the event loop\n\t\t\t */\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (!wsi-\u003ehttp.cgi-\u003eheaders_buf) {\n\t\t\t/* if we don't already have a headers buf, cook one */\n\t\t\tn \u003d 2048;\n\t\t\tif (wsi-\u003emux_substream)\n\t\t\t\tn \u003d 4096;\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_buf \u003d lws_malloc((unsigned int)n + LWS_PRE,\n\t\t\t\t\t\t\t \u0022cgi hdr buf\u0022);\n\t\t\tif (!wsi-\u003ehttp.cgi-\u003eheaders_buf) {\n\t\t\t\tlwsl_wsi_err(wsi, \u0022OOM\u0022);\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tlwsl_wsi_debug(wsi, \u0022allocated cgi hdrs\u0022);\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_start \u003d\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003eheaders_buf + LWS_PRE;\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_pos \u003d wsi-\u003ehttp.cgi-\u003eheaders_start;\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_dumped \u003d wsi-\u003ehttp.cgi-\u003eheaders_pos;\n\t\t\twsi-\u003ehttp.cgi-\u003eheaders_end \u003d\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003eheaders_buf + n - 1;\n\n\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++) {\n\t\t\t\twsi-\u003ehttp.cgi-\u003ematch[n] \u003d 0;\n\t\t\t\twsi-\u003ehttp.cgi-\u003elp \u003d 0;\n\t\t\t}\n\t\t}\n\n\t\tn \u003d lws_get_socket_fd(wsi-\u003ehttp.cgi-\u003elsp-\u003estdwsi[LWS_STDOUT]);\n\t\tif (n \u003c 0)\n\t\t\treturn -1;\n\t\tn \u003d (int)read(n, \u0026c, 1);\n\t\tif (n \u003c 0) {\n\t\t\tif (errno !\u003d EAGAIN) {\n\t\t\t\tlwsl_wsi_debug(wsi, \u0022read says %d\u0022, n);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tn \u003d 0;\n\n\t\t\tif (wsi-\u003ehttp.cgi-\u003eheaders_pos \u003e\u003d\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003eheaders_end - 4) {\n\t\t\t\tlwsl_wsi_notice(wsi, \u0022CGI hdrs \u003e buf size\u0022);\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\tif (!n)\n\t\t\tgoto agin;\n\n\t\tlwsl_wsi_debug(wsi, \u0022-- 0x%02X %c %d %d\u0022, (unsigned char)c, c,\n\t\t\t\t wsi-\u003ehttp.cgi-\u003ematch[1], wsi-\u003ehdr_state);\n\t\tif (!c)\n\t\t\treturn -1;\n\t\tswitch (wsi-\u003ehdr_state) {\n\t\tcase LCHS_HEADER:\n\t\t\thdr:\n\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++) {\n\t\t\t\t/*\n\t\t\t\t * significant headers with\n\t\t\t\t * numeric decimal payloads\n\t\t\t\t */\n\t\t\t\tif (!significant_hdr[n][wsi-\u003ehttp.cgi-\u003ematch[n]] \u0026\u0026\n\t\t\t\t (c \u003e\u003d '0' \u0026\u0026 c \u003c\u003d '9') \u0026\u0026\n\t\t\t\t wsi-\u003ehttp.cgi-\u003elp \u003c (int)sizeof(wsi-\u003ehttp.cgi-\u003el) - 1) {\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003el[wsi-\u003ehttp.cgi-\u003elp++] \u003d c;\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003el[wsi-\u003ehttp.cgi-\u003elp] \u003d '\u005c0';\n\t\t\t\t\tswitch (n) {\n\t\t\t\t\tcase SIGNIFICANT_HDR_CONTENT_LENGTH:\n\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003econtent_length \u003d\n\t\t\t\t\t\t\t(lws_filepos_t)atoll(wsi-\u003ehttp.cgi-\u003el);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SIGNIFICANT_HDR_STATUS:\n\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003eresponse_code \u003d\n\t\t\t\t\t\t\tatoi(wsi-\u003ehttp.cgi-\u003el);\n\t\t\t\t\t\tlwsl_wsi_debug(wsi, \u0022Status set to %d\u0022,\n\t\t\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003eresponse_code);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t/* hits up to the NUL are sticky until next hdr */\n\t\t\t\tif (significant_hdr[n][wsi-\u003ehttp.cgi-\u003ematch[n]]) {\n\t\t\t\t\tif (tolower(c) \u003d\u003d\n\t\t\t\t\t significant_hdr[n][wsi-\u003ehttp.cgi-\u003ematch[n]])\n\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003ematch[n]++;\n\t\t\t\t\telse\n\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003ematch[n] \u003d 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* some cgi only send us \u005cx0a for EOL */\n\t\t\tif (c \u003d\u003d '\u005cx0a') {\n\t\t\t\twsi-\u003ehdr_state \u003d LCHS_SINGLE_0A;\n\t\t\t\t*wsi-\u003ehttp.cgi-\u003eheaders_pos++ \u003d '\u005cx0d';\n\t\t\t}\n\t\t\t*wsi-\u003ehttp.cgi-\u003eheaders_pos++ \u003d (unsigned char)c;\n\t\t\tif (c \u003d\u003d '\u005cx0d')\n\t\t\t\twsi-\u003ehdr_state \u003d LCHS_LF1;\n\n\t\t\tif (wsi-\u003ehdr_state !\u003d LCHS_HEADER \u0026\u0026\n\t\t\t !significant_hdr[SIGNIFICANT_HDR_TRANSFER_ENCODING]\n\t\t\t\t [wsi-\u003ehttp.cgi-\u003ematch[\n\t\t\t\t\t SIGNIFICANT_HDR_TRANSFER_ENCODING]]) {\n\t\t\t\tlwsl_wsi_info(wsi, \u0022cgi produced chunked\u0022);\n\t\t\t\twsi-\u003ehttp.cgi-\u003eexplicitly_chunked \u003d 1;\n\t\t\t}\n\n\t\t\t/* presence of Location: mandates 302 retcode */\n\t\t\tif (wsi-\u003ehdr_state !\u003d LCHS_HEADER \u0026\u0026\n\t\t\t !significant_hdr[SIGNIFICANT_HDR_LOCATION][\n\t\t\t wsi-\u003ehttp.cgi-\u003ematch[SIGNIFICANT_HDR_LOCATION]]) {\n\t\t\t\tlwsl_wsi_debug(wsi, \u0022CGI: Location hdr seen\u0022);\n\t\t\t\twsi-\u003ehttp.cgi-\u003eresponse_code \u003d 302;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase LCHS_LF1:\n\t\t\t*wsi-\u003ehttp.cgi-\u003eheaders_pos++ \u003d (unsigned char)c;\n\t\t\tif (c \u003d\u003d '\u005cx0a') {\n\t\t\t\twsi-\u003ehdr_state \u003d LCHS_CR2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* we got \u005cr[^\u005cn]... it's unreasonable */\n\t\t\tlwsl_wsi_debug(wsi, \u0022funny CRLF 0x%02X\u0022,\n\t\t\t\t\t (unsigned char)c);\n\t\t\treturn -1;\n\n\t\tcase LCHS_CR2:\n\t\t\tif (c \u003d\u003d '\u005cx0d') {\n\t\t\t\t/* drop the \u005cx0d */\n\t\t\t\twsi-\u003ehdr_state \u003d LCHS_LF2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++)\n\t\t\t\twsi-\u003ehttp.cgi-\u003ematch[n] \u003d 0;\n\t\t\twsi-\u003ehttp.cgi-\u003elp \u003d 0;\n\t\t\tgoto hdr;\n\n\t\tcase LCHS_LF2:\n\t\tcase LCHS_SINGLE_0A:\n\t\t\tm \u003d wsi-\u003ehdr_state;\n\t\t\tif (c \u003d\u003d '\u005cx0a') {\n\t\t\t\tlwsl_wsi_debug(wsi, \u0022Content-Length: %lld\u0022,\n\t\t\t\t\t(unsigned long long)\n\t\t\t\t\twsi-\u003ehttp.cgi-\u003econtent_length);\n\t\t\t\twsi-\u003ehdr_state \u003d LHCS_RESPONSE;\n\t\t\t\t/*\n\t\t\t\t * drop the \u005c0xa ... finalize\n\t\t\t\t * will add it if needed (HTTP/1)\n\t\t\t\t */\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (m \u003d\u003d LCHS_LF2)\n\t\t\t\t/* we got \u005cr\u005cn\u005cr[^\u005cn]... unreasonable */\n\t\t\t\treturn -1;\n\t\t\t/* we got \u005cx0anext header, it's reasonable */\n\t\t\t*wsi-\u003ehttp.cgi-\u003eheaders_pos++ \u003d (unsigned char)c;\n\t\t\twsi-\u003ehdr_state \u003d LCHS_HEADER;\n\t\t\tfor (n \u003d 0; n \u003c SIGNIFICANT_HDR_COUNT; n++)\n\t\t\t\twsi-\u003ehttp.cgi-\u003ematch[n] \u003d 0;\n\t\t\twsi-\u003ehttp.cgi-\u003elp \u003d 0;\n\t\t\tbreak;\n\t\tcase LHCS_PAYLOAD:\n\t\t\tbreak;\n\t\t}\n\nagin:\n\t\t/* ran out of input, ended the hdrs, or filled up the hdrs buf */\n\t\tif (!n || wsi-\u003ehdr_state \u003d\u003d LHCS_PAYLOAD)\n\t\t\treturn 0;\n\t}\n\n\t/* payload processing */\n\n\tm \u003d !wsi-\u003ehttp.cgi-\u003eimplied_chunked \u0026\u0026 !wsi-\u003emux_substream \u0026\u0026\n\t// !wsi-\u003ehttp.cgi-\u003eexplicitly_chunked \u0026\u0026\n\t !wsi-\u003ehttp.cgi-\u003econtent_length;\n\tn \u003d lws_get_socket_fd(wsi-\u003ehttp.cgi-\u003elsp-\u003estdwsi[LWS_STDOUT]);\n\tif (n \u003c 0)\n\t\treturn -1;\n\tn \u003d (int)read(n, start, sizeof(buf) - LWS_PRE);\n\n\tif (n \u003c 0 \u0026\u0026 errno !\u003d EAGAIN) {\n\t\tlwsl_wsi_debug(wsi, \u0022stdout read says %d\u0022, n);\n\t\treturn -1;\n\t}\n\tif (n \u003e 0) {\n\t\t// lwsl_hexdump_notice(buf, n);\n\n\t\tif (!wsi-\u003emux_substream \u0026\u0026 m) {\n\t\t\tchar chdr[LWS_HTTP_CHUNK_HDR_SIZE];\n\t\t\tm \u003d lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3,\n\t\t\t\t\t \u0022%X\u005cx0d\u005cx0a\u0022, n);\n\t\t\tmemmove(start + m, start, (unsigned int)n);\n\t\t\tmemcpy(start, chdr, (unsigned int)m);\n\t\t\tmemcpy(start + m + n, \u0022\u005cx0d\u005cx0a\u0022, 2);\n\t\t\tn +\u003d m + 2;\n\t\t}\n\n\n#if defined(LWS_WITH_HTTP2)\n\t\tif (wsi-\u003emux_substream) {\n\t\t\tstruct lws *nwsi \u003d lws_get_network_wsi(wsi);\n\n\t\t\t__lws_set_timeout(wsi,\n\t\t\t\tPENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);\n\n\t\t\tif (!nwsi-\u003eimmortal_substream_count)\n\t\t\t\t__lws_set_timeout(nwsi,\n\t\t\t\t\tPENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);\n\t\t}\n#endif\n\n\t\tcmd \u003d LWS_WRITE_HTTP;\n\t\tif (wsi-\u003ehttp.cgi-\u003econtent_length_seen + (unsigned int)n \u003d\u003d\n\t\t\t\t\t\twsi-\u003ehttp.cgi-\u003econtent_length)\n\t\t\tcmd \u003d LWS_WRITE_HTTP_FINAL;\n\n\t\tm \u003d lws_write(wsi, (unsigned char *)start, (unsigned int)n, (enum lws_write_protocol)cmd);\n\t\t//lwsl_notice(\u0022write %d\u005cn\u0022, m);\n\t\tif (m \u003c 0) {\n\t\t\tlwsl_wsi_debug(wsi, \u0022stdout write says %d\u005cn\u0022, m);\n\t\t\treturn -1;\n\t\t}\n\t\twsi-\u003ehttp.cgi-\u003econtent_length_seen +\u003d (unsigned int)n;\n\t} else {\n\n\t\tif (!wsi-\u003emux_substream \u0026\u0026 m) {\n\t\t\tuint8_t term[LWS_PRE + 6];\n\n\t\t\tlwsl_wsi_info(wsi, \u0022sent trailer\u0022);\n\t\t\tmemcpy(term + LWS_PRE, (uint8_t *)\u00220\u005cx0d\u005cx0a\u005cx0d\u005cx0a\u0022, 5);\n\n\t\t\tif (lws_write(wsi, term + LWS_PRE, 5,\n\t\t\t\t LWS_WRITE_HTTP_FINAL) !\u003d 5)\n\t\t\t\treturn -1;\n\n\t\t\twsi-\u003ehttp.cgi-\u003ecgi_transaction_over \u003d 1;\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (wsi-\u003ecgi_stdout_zero_length) {\n\t\t\tlwsl_wsi_debug(wsi, \u0022stdout is POLLHUP'd\u0022);\n\t\t\tif (wsi-\u003emux_substream)\n\t\t\t\tm \u003d lws_write(wsi, (unsigned char *)start, 0,\n\t\t\t\t\t LWS_WRITE_HTTP_FINAL);\n\t\t\telse\n\t\t\t\treturn -1;\n\t\t\treturn 1;\n\t\t}\n\t\twsi-\u003ecgi_stdout_zero_length \u003d 1;\n\t}\n\treturn 0;\n}\n\nint\nlws_cgi_kill(struct lws *wsi)\n{\n\tstruct lws_cgi_args args;\n\tpid_t pid;\n\tint n, m \u003d 0;\n\n\tif (!wsi-\u003ehttp.cgi || !wsi-\u003ehttp.cgi-\u003elsp)\n\t\treturn 0;\n\n\tpid \u003d wsi-\u003ehttp.cgi-\u003elsp-\u003echild_pid;\n\n\targs.stdwsi \u003d \u0026wsi-\u003ehttp.cgi-\u003elsp-\u003estdwsi[0];\n\tlws_spawn_piped_kill_child_process(wsi-\u003ehttp.cgi-\u003elsp);\n\t/* that has invalidated and NULL'd wsi-\u003ehttp.cgi-\u003elsp */\n\n\tif (pid !\u003d -1) {\n\t\tif (wsi-\u003ehttp.cgi)\n\t\t\tm \u003d wsi-\u003ehttp.cgi-\u003ebeing_closed;\n\t\tn \u003d user_callback_handle_rxflow(wsi-\u003ea.protocol-\u003ecallback, wsi,\n\t\t\t\t\t\tLWS_CALLBACK_CGI_TERMINATED,\n\t\t\t\t\t\twsi-\u003euser_space, (void *)\u0026args,\n\t\t\t\t\t\t(unsigned int)pid);\n\t\tif (n \u0026\u0026 !m)\n\t\t\tlws_close_free_wsi(wsi, 0, \u0022lws_cgi_kill\u0022);\n\t}\n\n\treturn 0;\n}\n\nint\nlws_cgi_kill_terminated(struct lws_context_per_thread *pt)\n{\n\tstruct lws_cgi **pcgi, *cgi \u003d NULL;\n\tint status, n \u003d 1;\n\n\twhile (n \u003e 0) {\n\t\t/* find finished guys but don't reap yet */\n\t\tn \u003d waitpid(-1, \u0026status, WNOHANG);\n\t\tif (n \u003c\u003d 0)\n\t\t\tcontinue;\n\t\tlwsl_cx_debug(pt-\u003econtext, \u0022observed PID %d terminated\u0022, n);\n\n\t\tpcgi \u003d \u0026pt-\u003ehttp.cgi_list;\n\n\t\t/* check all the subprocesses on the cgi list */\n\t\twhile (*pcgi) {\n\t\t\t/* get the next one first as list may change */\n\t\t\tcgi \u003d *pcgi;\n\t\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n\n\t\t\tif (cgi-\u003elsp-\u003echild_pid \u003c\u003d 0)\n\t\t\t\tcontinue;\n\n\t\t\t/* finish sending cached headers */\n\t\t\tif (cgi-\u003eheaders_buf)\n\t\t\t\tcontinue;\n\n\t\t\t/* wait for stdout to be drained */\n\t\t\tif (cgi-\u003econtent_length \u003e cgi-\u003econtent_length_seen)\n\t\t\t\tcontinue;\n\n\t\t\tif (cgi-\u003econtent_length) {\n\t\t\t\tlwsl_cx_debug(pt-\u003econtext, \u0022expected content \u0022\n\t\t\t\t\t\t\t \u0022length seen: %lld\u0022,\n\t\t\t\t(unsigned long long)cgi-\u003econtent_length_seen);\n\t\t\t}\n\n\t\t\t/* reap it */\n\t\t\twaitpid(n, \u0026status, WNOHANG);\n\t\t\t/*\n\t\t\t * he's already terminated so no need for kill()\n\t\t\t * but we should do the terminated cgi callback\n\t\t\t * and close him if he's not already closing\n\t\t\t */\n\t\t\tif (n \u003d\u003d cgi-\u003elsp-\u003echild_pid) {\n\n\t\t\t\tif (!cgi-\u003econtent_length) {\n\t\t\t\t\t/*\n\t\t\t\t\t * well, if he sends chunked...\n\t\t\t\t\t * give him 2s after the\n\t\t\t\t\t * cgi terminated to send buffered\n\t\t\t\t\t */\n\t\t\t\t\tcgi-\u003echunked_grace++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t/* defeat kill() */\n\t\t\t\tcgi-\u003elsp-\u003echild_pid \u003d 0;\n\t\t\t\tlws_cgi_kill(cgi-\u003ewsi);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcgi \u003d NULL;\n\t\t}\n\t\t/* if not found on the cgi list, as he's one of ours, reap */\n\t\tif (!cgi)\n\t\t\twaitpid(n, \u0026status, WNOHANG);\n\n\t}\n\n\tpcgi \u003d \u0026pt-\u003ehttp.cgi_list;\n\n\t/* check all the subprocesses on the cgi list */\n\twhile (*pcgi) {\n\t\t/* get the next one first as list may change */\n\t\tcgi \u003d *pcgi;\n\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n\n\t\tif (!cgi || !cgi-\u003elsp || cgi-\u003elsp-\u003echild_pid \u003c\u003d 0)\n\t\t\tcontinue;\n\n\t\t/* we deferred killing him after reaping his PID */\n\t\tif (cgi-\u003echunked_grace) {\n\t\t\tcgi-\u003echunked_grace++;\n\t\t\tif (cgi-\u003echunked_grace \u003c 2)\n\t\t\t\tcontinue;\n\t\t\tgoto finish_him;\n\t\t}\n\n\t\t/* finish sending cached headers */\n\t\tif (cgi-\u003eheaders_buf)\n\t\t\tcontinue;\n\n\t\t/* wait for stdout to be drained */\n\t\tif (cgi-\u003econtent_length \u003e cgi-\u003econtent_length_seen)\n\t\t\tcontinue;\n\n\t\tif (cgi-\u003econtent_length)\n\t\t\tlwsl_wsi_debug(cgi-\u003ewsi, \u0022expected cont len seen: %lld\u0022,\n\t\t\t\t (unsigned long long)cgi-\u003econtent_length_seen);\n\n\t\t/* reap it */\n\t\tif (waitpid(cgi-\u003elsp-\u003echild_pid, \u0026status, WNOHANG) \u003e 0) {\n\n\t\t\tif (!cgi-\u003econtent_length) {\n\t\t\t\t/*\n\t\t\t\t * well, if he sends chunked...\n\t\t\t\t * give him 2s after the\n\t\t\t\t * cgi terminated to send buffered\n\t\t\t\t */\n\t\t\t\tcgi-\u003echunked_grace++;\n\t\t\t\tcontinue;\n\t\t\t}\nfinish_him:\n\t\t\tlwsl_cx_debug(pt-\u003econtext, \u0022found PID %d on cgi list\u0022,\n\t\t\t\t\t\t cgi-\u003elsp-\u003echild_pid);\n\n\t\t\t/* defeat kill() */\n\t\t\tcgi-\u003elsp-\u003echild_pid \u003d 0;\n\t\t\tlws_cgi_kill(cgi-\u003ewsi);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nstruct lws *\nlws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch)\n{\n\tif (!wsi-\u003ehttp.cgi || !wsi-\u003ehttp.cgi-\u003elsp)\n\t\treturn NULL;\n\n\treturn wsi-\u003ehttp.cgi-\u003elsp-\u003estdwsi[ch];\n}\n\nvoid\nlws_cgi_remove_and_kill(struct lws *wsi)\n{\n\tstruct lws_context_per_thread *pt \u003d \u0026wsi-\u003ea.context-\u003ept[(int)wsi-\u003etsi];\n\tstruct lws_cgi **pcgi \u003d \u0026pt-\u003ehttp.cgi_list;\n\n\t/* remove us from the cgi list */\n\n\twhile (*pcgi) {\n\t\tif (*pcgi \u003d\u003d wsi-\u003ehttp.cgi) {\n\t\t\t/* drop us from the pt cgi list */\n\t\t\t*pcgi \u003d (*pcgi)-\u003ecgi_list;\n\t\t\tbreak;\n\t\t}\n\t\tpcgi \u003d \u0026(*pcgi)-\u003ecgi_list;\n\t}\n\tif (wsi-\u003ehttp.cgi-\u003eheaders_buf)\n\t\tlws_free_set_NULL(wsi-\u003ehttp.cgi-\u003eheaders_buf);\n\n\t/* we have a cgi going, we must kill it */\n\twsi-\u003ehttp.cgi-\u003ebeing_closed \u003d 1;\n\tlws_cgi_kill(wsi);\n\n\tif (!pt-\u003ehttp.cgi_list)\n\t\tlws_sul_cancel(\u0026pt-\u003esul_cgi);\n}\n","s":{"c":1711666692,"u": 800}}
],"g": 3126,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}