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#if !defined(_GNU_SOURCE) 26d4afb5ceSopenharmony_ci#define _GNU_SOURCE 27d4afb5ceSopenharmony_ci#endif 28d4afb5ceSopenharmony_ci 29d4afb5ceSopenharmony_ci#include "private-lib-core.h" 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#if defined(WIN32) || defined(_WIN32) 32d4afb5ceSopenharmony_ci#else 33d4afb5ceSopenharmony_ci#include <sys/wait.h> 34d4afb5ceSopenharmony_ci#endif 35d4afb5ceSopenharmony_ci 36d4afb5ceSopenharmony_cistatic const char *hex = "0123456789ABCDEF"; 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_civoid 39d4afb5ceSopenharmony_cilws_cgi_sul_cb(lws_sorted_usec_list_t *sul); 40d4afb5ceSopenharmony_ci 41d4afb5ceSopenharmony_cistatic int 42d4afb5ceSopenharmony_ciurlencode(const char *in, int inlen, char *out, int outlen) 43d4afb5ceSopenharmony_ci{ 44d4afb5ceSopenharmony_ci char *start = out, *end = out + outlen; 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci while (inlen-- && out < end - 4) { 47d4afb5ceSopenharmony_ci if ((*in >= 'A' && *in <= 'Z') || 48d4afb5ceSopenharmony_ci (*in >= 'a' && *in <= 'z') || 49d4afb5ceSopenharmony_ci (*in >= '0' && *in <= '9') || 50d4afb5ceSopenharmony_ci *in == '-' || 51d4afb5ceSopenharmony_ci *in == '_' || 52d4afb5ceSopenharmony_ci *in == '.' || 53d4afb5ceSopenharmony_ci *in == '~') { 54d4afb5ceSopenharmony_ci *out++ = *in++; 55d4afb5ceSopenharmony_ci continue; 56d4afb5ceSopenharmony_ci } 57d4afb5ceSopenharmony_ci if (*in == ' ') { 58d4afb5ceSopenharmony_ci *out++ = '+'; 59d4afb5ceSopenharmony_ci in++; 60d4afb5ceSopenharmony_ci continue; 61d4afb5ceSopenharmony_ci } 62d4afb5ceSopenharmony_ci *out++ = '%'; 63d4afb5ceSopenharmony_ci *out++ = hex[(*in) >> 4]; 64d4afb5ceSopenharmony_ci *out++ = hex[(*in++) & 15]; 65d4afb5ceSopenharmony_ci } 66d4afb5ceSopenharmony_ci *out = '\0'; 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_ci if (out >= end - 4) 69d4afb5ceSopenharmony_ci return -1; 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_ci return lws_ptr_diff(out, start); 72d4afb5ceSopenharmony_ci} 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_cistatic void 75d4afb5ceSopenharmony_cilws_cgi_grace(lws_sorted_usec_list_t *sul) 76d4afb5ceSopenharmony_ci{ 77d4afb5ceSopenharmony_ci struct lws_cgi *cgi = lws_container_of(sul, struct lws_cgi, sul_grace); 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci /* act on the reap cb from earlier */ 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci if (!cgi->wsi->http.cgi->post_in_expected) 82d4afb5ceSopenharmony_ci cgi->wsi->http.cgi->cgi_transaction_over = 1; 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci lws_callback_on_writable(cgi->wsi); 85d4afb5ceSopenharmony_ci} 86d4afb5ceSopenharmony_ci 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_cistatic void 89d4afb5ceSopenharmony_cilws_cgi_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si, 90d4afb5ceSopenharmony_ci int we_killed_him) 91d4afb5ceSopenharmony_ci{ 92d4afb5ceSopenharmony_ci struct lws *wsi = (struct lws *)opaque; 93d4afb5ceSopenharmony_ci 94d4afb5ceSopenharmony_ci /* 95d4afb5ceSopenharmony_ci * The cgi has come to an end, by itself or with a signal... 96d4afb5ceSopenharmony_ci */ 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci if (wsi->http.cgi) 99d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "post_in_expected %d", 100d4afb5ceSopenharmony_ci (int)wsi->http.cgi->post_in_expected); 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci /* 103d4afb5ceSopenharmony_ci * Grace period to handle the incoming stdout 104d4afb5ceSopenharmony_ci */ 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_ci if (wsi->http.cgi) 107d4afb5ceSopenharmony_ci lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->http.cgi->sul_grace, 108d4afb5ceSopenharmony_ci lws_cgi_grace, 1 * LWS_US_PER_SEC); 109d4afb5ceSopenharmony_ci} 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ciint 112d4afb5ceSopenharmony_cilws_cgi(struct lws *wsi, const char * const *exec_array, 113d4afb5ceSopenharmony_ci int script_uri_path_len, int timeout_secs, 114d4afb5ceSopenharmony_ci const struct lws_protocol_vhost_options *mp_cgienv) 115d4afb5ceSopenharmony_ci{ 116d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 117d4afb5ceSopenharmony_ci struct lws_spawn_piped_info info; 118d4afb5ceSopenharmony_ci char *env_array[30], cgi_path[500], e[1024], *p = e, 119d4afb5ceSopenharmony_ci *end = p + sizeof(e) - 1, tok[256], *t, *sum, *sumend; 120d4afb5ceSopenharmony_ci struct lws_cgi *cgi; 121d4afb5ceSopenharmony_ci int n, m = 0, i, uritok = -1, c; 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci /* 124d4afb5ceSopenharmony_ci * give the cgi stream wsi a cgi struct 125d4afb5ceSopenharmony_ci */ 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_ci wsi->http.cgi = lws_zalloc(sizeof(*wsi->http.cgi), "new cgi"); 128d4afb5ceSopenharmony_ci if (!wsi->http.cgi) { 129d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "OOM"); 130d4afb5ceSopenharmony_ci return -1; 131d4afb5ceSopenharmony_ci } 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_ci wsi->http.cgi->response_code = HTTP_STATUS_OK; 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci cgi = wsi->http.cgi; 136d4afb5ceSopenharmony_ci cgi->wsi = wsi; /* set cgi's owning wsi */ 137d4afb5ceSopenharmony_ci sum = cgi->summary; 138d4afb5ceSopenharmony_ci sumend = sum + strlen(cgi->summary) - 1; 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci if (timeout_secs) 141d4afb5ceSopenharmony_ci lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs); 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci /* the cgi stdout is always sending us http1.x header data first */ 144d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_HEADER; 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci /* add us to the pt list of active cgis */ 147d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "adding cgi %p to list", wsi->http.cgi); 148d4afb5ceSopenharmony_ci cgi->cgi_list = pt->http.cgi_list; 149d4afb5ceSopenharmony_ci pt->http.cgi_list = cgi; 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_ci /* if it's not already running, start the cleanup timer */ 152d4afb5ceSopenharmony_ci if (!pt->sul_cgi.list.owner) 153d4afb5ceSopenharmony_ci lws_sul_schedule(pt->context, (int)(pt - pt->context->pt), &pt->sul_cgi, 154d4afb5ceSopenharmony_ci lws_cgi_sul_cb, 3 * LWS_US_PER_SEC); 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ", exec_array[0]); 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci if (0) { 159d4afb5ceSopenharmony_ci char *pct = lws_hdr_simple_ptr(wsi, 160d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_ENCODING); 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci if (pct && !strcmp(pct, "gzip")) 163d4afb5ceSopenharmony_ci wsi->http.cgi->gzip_inflate = 1; 164d4afb5ceSopenharmony_ci } 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci /* prepare his CGI env */ 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci n = 0; 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci if (lws_is_ssl(wsi)) { 171d4afb5ceSopenharmony_ci env_array[n++] = p; 172d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTPS=ON"); 173d4afb5ceSopenharmony_ci p++; 174d4afb5ceSopenharmony_ci } 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci if (wsi->http.ah) { 177d4afb5ceSopenharmony_ci static const unsigned char meths[] = { 178d4afb5ceSopenharmony_ci WSI_TOKEN_GET_URI, 179d4afb5ceSopenharmony_ci WSI_TOKEN_POST_URI, 180d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 181d4afb5ceSopenharmony_ci WSI_TOKEN_OPTIONS_URI, 182d4afb5ceSopenharmony_ci WSI_TOKEN_PUT_URI, 183d4afb5ceSopenharmony_ci WSI_TOKEN_PATCH_URI, 184d4afb5ceSopenharmony_ci WSI_TOKEN_DELETE_URI, 185d4afb5ceSopenharmony_ci#endif 186d4afb5ceSopenharmony_ci WSI_TOKEN_CONNECT, 187d4afb5ceSopenharmony_ci WSI_TOKEN_HEAD_URI, 188d4afb5ceSopenharmony_ci #ifdef LWS_WITH_HTTP2 189d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_PATH, 190d4afb5ceSopenharmony_ci #endif 191d4afb5ceSopenharmony_ci }; 192d4afb5ceSopenharmony_ci static const char * const meth_names[] = { 193d4afb5ceSopenharmony_ci "GET", "POST", 194d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 195d4afb5ceSopenharmony_ci "OPTIONS", "PUT", "PATCH", "DELETE", 196d4afb5ceSopenharmony_ci#endif 197d4afb5ceSopenharmony_ci "CONNECT", "HEAD", ":path" 198d4afb5ceSopenharmony_ci }; 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0) 201d4afb5ceSopenharmony_ci for (m = 0; m < (int)LWS_ARRAY_SIZE(meths); m++) 202d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, meths[m]) >= 203d4afb5ceSopenharmony_ci script_uri_path_len) { 204d4afb5ceSopenharmony_ci uritok = meths[m]; 205d4afb5ceSopenharmony_ci break; 206d4afb5ceSopenharmony_ci } 207d4afb5ceSopenharmony_ci 208d4afb5ceSopenharmony_ci if (script_uri_path_len < 0 && uritok < 0) 209d4afb5ceSopenharmony_ci goto bail; 210d4afb5ceSopenharmony_ci// if (script_uri_path_len < 0) 211d4afb5ceSopenharmony_ci// uritok = 0; 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci if (m >= 0) { 214d4afb5ceSopenharmony_ci env_array[n++] = p; 215d4afb5ceSopenharmony_ci if (m < (int)LWS_ARRAY_SIZE(meths) - 1) { 216d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 217d4afb5ceSopenharmony_ci "REQUEST_METHOD=%s", 218d4afb5ceSopenharmony_ci meth_names[m]); 219d4afb5ceSopenharmony_ci sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ", 220d4afb5ceSopenharmony_ci meth_names[m]); 221d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H2) 222d4afb5ceSopenharmony_ci } else { 223d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), 224d4afb5ceSopenharmony_ci "REQUEST_METHOD=%s", 225d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD)); 226d4afb5ceSopenharmony_ci sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ", 227d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, 228d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_COLON_METHOD)); 229d4afb5ceSopenharmony_ci#endif 230d4afb5ceSopenharmony_ci } 231d4afb5ceSopenharmony_ci p++; 232d4afb5ceSopenharmony_ci } 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci if (uritok >= 0) 235d4afb5ceSopenharmony_ci sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s ", 236d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, (enum lws_token_indexes)uritok)); 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci env_array[n++] = p; 239d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "QUERY_STRING="); 240d4afb5ceSopenharmony_ci /* dump the individual URI Arg parameters */ 241d4afb5ceSopenharmony_ci m = 0; 242d4afb5ceSopenharmony_ci while (script_uri_path_len >= 0) { 243d4afb5ceSopenharmony_ci i = lws_hdr_copy_fragment(wsi, tok, sizeof(tok), 244d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_URI_ARGS, m); 245d4afb5ceSopenharmony_ci if (i < 0) 246d4afb5ceSopenharmony_ci break; 247d4afb5ceSopenharmony_ci t = tok; 248d4afb5ceSopenharmony_ci while (*t && *t != '=' && p < end - 4) 249d4afb5ceSopenharmony_ci *p++ = *t++; 250d4afb5ceSopenharmony_ci if (*t == '=') 251d4afb5ceSopenharmony_ci *p++ = *t++; 252d4afb5ceSopenharmony_ci i = urlencode(t, i - lws_ptr_diff(t, tok), p, lws_ptr_diff(end, p)); 253d4afb5ceSopenharmony_ci if (i > 0) { 254d4afb5ceSopenharmony_ci p += i; 255d4afb5ceSopenharmony_ci *p++ = '&'; 256d4afb5ceSopenharmony_ci } 257d4afb5ceSopenharmony_ci m++; 258d4afb5ceSopenharmony_ci } 259d4afb5ceSopenharmony_ci if (m) 260d4afb5ceSopenharmony_ci p--; 261d4afb5ceSopenharmony_ci *p++ = '\0'; 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci if (uritok >= 0) { 264d4afb5ceSopenharmony_ci strcpy(cgi_path, "REQUEST_URI="); 265d4afb5ceSopenharmony_ci c = lws_hdr_copy(wsi, cgi_path + 12, 266d4afb5ceSopenharmony_ci sizeof(cgi_path) - 12, (enum lws_token_indexes)uritok); 267d4afb5ceSopenharmony_ci if (c < 0) 268d4afb5ceSopenharmony_ci goto bail; 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci cgi_path[sizeof(cgi_path) - 1] = '\0'; 271d4afb5ceSopenharmony_ci env_array[n++] = cgi_path; 272d4afb5ceSopenharmony_ci } 273d4afb5ceSopenharmony_ci 274d4afb5ceSopenharmony_ci sum += lws_snprintf(sum, lws_ptr_diff_size_t(sumend, sum), "%s", env_array[n - 1]); 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0) { 277d4afb5ceSopenharmony_ci env_array[n++] = p; 278d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "PATH_INFO=%s", 279d4afb5ceSopenharmony_ci cgi_path + 12 + script_uri_path_len); 280d4afb5ceSopenharmony_ci p++; 281d4afb5ceSopenharmony_ci } 282d4afb5ceSopenharmony_ci } 283d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 284d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 285d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) { 286d4afb5ceSopenharmony_ci env_array[n++] = p; 287d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_REFERER=%s", 288d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER)); 289d4afb5ceSopenharmony_ci p++; 290d4afb5ceSopenharmony_ci } 291d4afb5ceSopenharmony_ci#endif 292d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 293d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { 294d4afb5ceSopenharmony_ci env_array[n++] = p; 295d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_HOST=%s", 296d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); 297d4afb5ceSopenharmony_ci p++; 298d4afb5ceSopenharmony_ci } 299d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 300d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { 301d4afb5ceSopenharmony_ci env_array[n++] = p; 302d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_COOKIE="); 303d4afb5ceSopenharmony_ci m = lws_hdr_copy(wsi, p, lws_ptr_diff(end, p), WSI_TOKEN_HTTP_COOKIE); 304d4afb5ceSopenharmony_ci if (m > 0) 305d4afb5ceSopenharmony_ci p += lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE); 306d4afb5ceSopenharmony_ci *p++ = '\0'; 307d4afb5ceSopenharmony_ci } 308d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) 309d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 310d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) { 311d4afb5ceSopenharmony_ci env_array[n++] = p; 312d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_USER_AGENT=%s", 313d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT)); 314d4afb5ceSopenharmony_ci p++; 315d4afb5ceSopenharmony_ci } 316d4afb5ceSopenharmony_ci#endif 317d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 318d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING)) { 319d4afb5ceSopenharmony_ci env_array[n++] = p; 320d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_CONTENT_ENCODING=%s", 321d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_ENCODING)); 322d4afb5ceSopenharmony_ci p++; 323d4afb5ceSopenharmony_ci } 324d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 325d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT)) { 326d4afb5ceSopenharmony_ci env_array[n++] = p; 327d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_ACCEPT=%s", 328d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT)); 329d4afb5ceSopenharmony_ci p++; 330d4afb5ceSopenharmony_ci } 331d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 332d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)) { 333d4afb5ceSopenharmony_ci env_array[n++] = p; 334d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "HTTP_ACCEPT_ENCODING=%s", 335d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_ACCEPT_ENCODING)); 336d4afb5ceSopenharmony_ci p++; 337d4afb5ceSopenharmony_ci } 338d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0 && 339d4afb5ceSopenharmony_ci uritok == WSI_TOKEN_POST_URI) { 340d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) { 341d4afb5ceSopenharmony_ci env_array[n++] = p; 342d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "CONTENT_TYPE=%s", 343d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)); 344d4afb5ceSopenharmony_ci p++; 345d4afb5ceSopenharmony_ci } 346d4afb5ceSopenharmony_ci if (!wsi->http.cgi->gzip_inflate && 347d4afb5ceSopenharmony_ci lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { 348d4afb5ceSopenharmony_ci env_array[n++] = p; 349d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "CONTENT_LENGTH=%s", 350d4afb5ceSopenharmony_ci lws_hdr_simple_ptr(wsi, 351d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_LENGTH)); 352d4afb5ceSopenharmony_ci p++; 353d4afb5ceSopenharmony_ci } 354d4afb5ceSopenharmony_ci 355d4afb5ceSopenharmony_ci if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) 356d4afb5ceSopenharmony_ci wsi->http.cgi->post_in_expected = (lws_filepos_t) 357d4afb5ceSopenharmony_ci atoll(lws_hdr_simple_ptr(wsi, 358d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_CONTENT_LENGTH)); 359d4afb5ceSopenharmony_ci } 360d4afb5ceSopenharmony_ci 361d4afb5ceSopenharmony_ci 362d4afb5ceSopenharmony_ci env_array[n++] = p; 363d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "PATH=/bin:/usr/bin:/usr/local/bin:/var/www/cgi-bin"); 364d4afb5ceSopenharmony_ci p++; 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ci env_array[n++] = p; 367d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "SCRIPT_PATH=%s", exec_array[0]); 368d4afb5ceSopenharmony_ci p++; 369d4afb5ceSopenharmony_ci 370d4afb5ceSopenharmony_ci while (mp_cgienv) { 371d4afb5ceSopenharmony_ci env_array[n++] = p; 372d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s=%s", mp_cgienv->name, 373d4afb5ceSopenharmony_ci mp_cgienv->value); 374d4afb5ceSopenharmony_ci if (!strcmp(mp_cgienv->name, "GIT_PROJECT_ROOT")) { 375d4afb5ceSopenharmony_ci wsi->http.cgi->implied_chunked = 1; 376d4afb5ceSopenharmony_ci wsi->http.cgi->explicitly_chunked = 1; 377d4afb5ceSopenharmony_ci } 378d4afb5ceSopenharmony_ci lwsl_info(" Applying mount-specific cgi env '%s'\n", 379d4afb5ceSopenharmony_ci env_array[n - 1]); 380d4afb5ceSopenharmony_ci p++; 381d4afb5ceSopenharmony_ci mp_cgienv = mp_cgienv->next; 382d4afb5ceSopenharmony_ci } 383d4afb5ceSopenharmony_ci 384d4afb5ceSopenharmony_ci env_array[n++] = p; 385d4afb5ceSopenharmony_ci p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "SERVER_SOFTWARE=lws"); 386d4afb5ceSopenharmony_ci p++; 387d4afb5ceSopenharmony_ci 388d4afb5ceSopenharmony_ci env_array[n] = NULL; 389d4afb5ceSopenharmony_ci 390d4afb5ceSopenharmony_ci#if 0 391d4afb5ceSopenharmony_ci for (m = 0; m < n; m++) 392d4afb5ceSopenharmony_ci lwsl_notice(" %s\n", env_array[m]); 393d4afb5ceSopenharmony_ci#endif 394d4afb5ceSopenharmony_ci 395d4afb5ceSopenharmony_ci memset(&info, 0, sizeof(info)); 396d4afb5ceSopenharmony_ci info.env_array = (const char **)env_array; 397d4afb5ceSopenharmony_ci info.exec_array = exec_array; 398d4afb5ceSopenharmony_ci info.max_log_lines = 20000; 399d4afb5ceSopenharmony_ci info.opt_parent = wsi; 400d4afb5ceSopenharmony_ci info.timeout_us = 5 * 60 * LWS_US_PER_SEC; 401d4afb5ceSopenharmony_ci info.tsi = wsi->tsi; 402d4afb5ceSopenharmony_ci info.vh = wsi->a.vhost; 403d4afb5ceSopenharmony_ci info.ops = &role_ops_cgi; 404d4afb5ceSopenharmony_ci info.plsp = &wsi->http.cgi->lsp; 405d4afb5ceSopenharmony_ci info.opaque = wsi; 406d4afb5ceSopenharmony_ci info.reap_cb = lws_cgi_reap_cb; 407d4afb5ceSopenharmony_ci 408d4afb5ceSopenharmony_ci /* 409d4afb5ceSopenharmony_ci * Actually having made the env, as a cgi we don't need the ah 410d4afb5ceSopenharmony_ci * any more 411d4afb5ceSopenharmony_ci */ 412d4afb5ceSopenharmony_ci if (script_uri_path_len >= 0) { 413d4afb5ceSopenharmony_ci lws_header_table_detach(wsi, 0); 414d4afb5ceSopenharmony_ci info.disable_ctrlc = 1; 415d4afb5ceSopenharmony_ci } 416d4afb5ceSopenharmony_ci 417d4afb5ceSopenharmony_ci wsi->http.cgi->lsp = lws_spawn_piped(&info); 418d4afb5ceSopenharmony_ci if (!wsi->http.cgi->lsp) { 419d4afb5ceSopenharmony_ci lwsl_err("%s: spawn failed\n", __func__); 420d4afb5ceSopenharmony_ci goto bail; 421d4afb5ceSopenharmony_ci } 422d4afb5ceSopenharmony_ci 423d4afb5ceSopenharmony_ci /* we are the parent process */ 424d4afb5ceSopenharmony_ci 425d4afb5ceSopenharmony_ci wsi->a.context->count_cgi_spawned++; 426d4afb5ceSopenharmony_ci 427d4afb5ceSopenharmony_ci /* inform cgi owner of the child PID */ 428d4afb5ceSopenharmony_ci n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, 429d4afb5ceSopenharmony_ci LWS_CALLBACK_CGI_PROCESS_ATTACH, 430d4afb5ceSopenharmony_ci wsi->user_space, NULL, (unsigned int)cgi->lsp->child_pid); 431d4afb5ceSopenharmony_ci (void)n; 432d4afb5ceSopenharmony_ci 433d4afb5ceSopenharmony_ci return 0; 434d4afb5ceSopenharmony_ci 435d4afb5ceSopenharmony_cibail: 436d4afb5ceSopenharmony_ci lws_sul_cancel(&wsi->http.cgi->sul_grace); 437d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.cgi); 438d4afb5ceSopenharmony_ci 439d4afb5ceSopenharmony_ci lwsl_err("%s: failed\n", __func__); 440d4afb5ceSopenharmony_ci 441d4afb5ceSopenharmony_ci return -1; 442d4afb5ceSopenharmony_ci} 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_ci/* we have to parse out these headers in the CGI output */ 445d4afb5ceSopenharmony_ci 446d4afb5ceSopenharmony_cistatic const char * const significant_hdr[SIGNIFICANT_HDR_COUNT] = { 447d4afb5ceSopenharmony_ci "content-length: ", 448d4afb5ceSopenharmony_ci "location: ", 449d4afb5ceSopenharmony_ci "status: ", 450d4afb5ceSopenharmony_ci "transfer-encoding: chunked", 451d4afb5ceSopenharmony_ci "content-encoding: gzip", 452d4afb5ceSopenharmony_ci}; 453d4afb5ceSopenharmony_ci 454d4afb5ceSopenharmony_cienum header_recode { 455d4afb5ceSopenharmony_ci HR_NAME, 456d4afb5ceSopenharmony_ci HR_WHITESPACE, 457d4afb5ceSopenharmony_ci HR_ARG, 458d4afb5ceSopenharmony_ci HR_CRLF, 459d4afb5ceSopenharmony_ci}; 460d4afb5ceSopenharmony_ci 461d4afb5ceSopenharmony_ciint 462d4afb5ceSopenharmony_cilws_cgi_write_split_stdout_headers(struct lws *wsi) 463d4afb5ceSopenharmony_ci{ 464d4afb5ceSopenharmony_ci int n, m, cmd; 465d4afb5ceSopenharmony_ci unsigned char buf[LWS_PRE + 4096], *start = &buf[LWS_PRE], *p = start, 466d4afb5ceSopenharmony_ci *end = &buf[sizeof(buf) - 1 - LWS_PRE], *name, 467d4afb5ceSopenharmony_ci *value = NULL; 468d4afb5ceSopenharmony_ci char c, hrs; 469d4afb5ceSopenharmony_ci 470d4afb5ceSopenharmony_ci if (!wsi->http.cgi) 471d4afb5ceSopenharmony_ci return -1; 472d4afb5ceSopenharmony_ci 473d4afb5ceSopenharmony_ci while (wsi->hdr_state != LHCS_PAYLOAD) { 474d4afb5ceSopenharmony_ci /* 475d4afb5ceSopenharmony_ci * We have to separate header / finalize and payload chunks, 476d4afb5ceSopenharmony_ci * since they need to be handled separately 477d4afb5ceSopenharmony_ci */ 478d4afb5ceSopenharmony_ci switch (wsi->hdr_state) { 479d4afb5ceSopenharmony_ci case LHCS_RESPONSE: 480d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "LHCS_RESPONSE: iss response %d", 481d4afb5ceSopenharmony_ci wsi->http.cgi->response_code); 482d4afb5ceSopenharmony_ci if (lws_add_http_header_status(wsi, 483d4afb5ceSopenharmony_ci (unsigned int)wsi->http.cgi->response_code, 484d4afb5ceSopenharmony_ci &p, end)) 485d4afb5ceSopenharmony_ci return 1; 486d4afb5ceSopenharmony_ci if (!wsi->http.cgi->explicitly_chunked && 487d4afb5ceSopenharmony_ci !wsi->http.cgi->content_length && 488d4afb5ceSopenharmony_ci lws_add_http_header_by_token(wsi, 489d4afb5ceSopenharmony_ci WSI_TOKEN_HTTP_TRANSFER_ENCODING, 490d4afb5ceSopenharmony_ci (unsigned char *)"chunked", 7, &p, end)) 491d4afb5ceSopenharmony_ci return 1; 492d4afb5ceSopenharmony_ci if (!(wsi->mux_substream)) 493d4afb5ceSopenharmony_ci if (lws_add_http_header_by_token(wsi, 494d4afb5ceSopenharmony_ci WSI_TOKEN_CONNECTION, 495d4afb5ceSopenharmony_ci (unsigned char *)"close", 5, 496d4afb5ceSopenharmony_ci &p, end)) 497d4afb5ceSopenharmony_ci return 1; 498d4afb5ceSopenharmony_ci n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), 499d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_HEADERS | LWS_WRITE_NO_FIN); 500d4afb5ceSopenharmony_ci 501d4afb5ceSopenharmony_ci /* 502d4afb5ceSopenharmony_ci * so we have a bunch of http/1 style ascii headers 503d4afb5ceSopenharmony_ci * starting from wsi->http.cgi->headers_buf through 504d4afb5ceSopenharmony_ci * wsi->http.cgi->headers_pos. These are OK for http/1 505d4afb5ceSopenharmony_ci * connections, but they're no good for http/2 conns. 506d4afb5ceSopenharmony_ci * 507d4afb5ceSopenharmony_ci * Let's redo them at headers_pos forward using the 508d4afb5ceSopenharmony_ci * correct coding for http/1 or http/2 509d4afb5ceSopenharmony_ci */ 510d4afb5ceSopenharmony_ci if (!wsi->mux_substream) 511d4afb5ceSopenharmony_ci goto post_hpack_recode; 512d4afb5ceSopenharmony_ci 513d4afb5ceSopenharmony_ci p = wsi->http.cgi->headers_start; 514d4afb5ceSopenharmony_ci wsi->http.cgi->headers_start = 515d4afb5ceSopenharmony_ci wsi->http.cgi->headers_pos; 516d4afb5ceSopenharmony_ci wsi->http.cgi->headers_dumped = 517d4afb5ceSopenharmony_ci wsi->http.cgi->headers_start; 518d4afb5ceSopenharmony_ci hrs = HR_NAME; 519d4afb5ceSopenharmony_ci name = buf; 520d4afb5ceSopenharmony_ci 521d4afb5ceSopenharmony_ci while (p < wsi->http.cgi->headers_start) { 522d4afb5ceSopenharmony_ci switch (hrs) { 523d4afb5ceSopenharmony_ci case HR_NAME: 524d4afb5ceSopenharmony_ci /* 525d4afb5ceSopenharmony_ci * in http/2 upper-case header names 526d4afb5ceSopenharmony_ci * are illegal. So convert to lower- 527d4afb5ceSopenharmony_ci * case. 528d4afb5ceSopenharmony_ci */ 529d4afb5ceSopenharmony_ci if (name - buf > 64) 530d4afb5ceSopenharmony_ci return -1; 531d4afb5ceSopenharmony_ci if (*p != ':') { 532d4afb5ceSopenharmony_ci if (*p >= 'A' && *p <= 'Z') 533d4afb5ceSopenharmony_ci *name++ = (unsigned char)((*p++) + 534d4afb5ceSopenharmony_ci ('a' - 'A')); 535d4afb5ceSopenharmony_ci else 536d4afb5ceSopenharmony_ci *name++ = *p++; 537d4afb5ceSopenharmony_ci } else { 538d4afb5ceSopenharmony_ci p++; 539d4afb5ceSopenharmony_ci *name++ = '\0'; 540d4afb5ceSopenharmony_ci value = name; 541d4afb5ceSopenharmony_ci hrs = HR_WHITESPACE; 542d4afb5ceSopenharmony_ci } 543d4afb5ceSopenharmony_ci break; 544d4afb5ceSopenharmony_ci case HR_WHITESPACE: 545d4afb5ceSopenharmony_ci if (*p == ' ') { 546d4afb5ceSopenharmony_ci p++; 547d4afb5ceSopenharmony_ci break; 548d4afb5ceSopenharmony_ci } 549d4afb5ceSopenharmony_ci hrs = HR_ARG; 550d4afb5ceSopenharmony_ci /* fallthru */ 551d4afb5ceSopenharmony_ci case HR_ARG: 552d4afb5ceSopenharmony_ci if (name > end - 64) 553d4afb5ceSopenharmony_ci return -1; 554d4afb5ceSopenharmony_ci 555d4afb5ceSopenharmony_ci if (*p != '\x0a' && *p != '\x0d') { 556d4afb5ceSopenharmony_ci *name++ = *p++; 557d4afb5ceSopenharmony_ci break; 558d4afb5ceSopenharmony_ci } 559d4afb5ceSopenharmony_ci hrs = HR_CRLF; 560d4afb5ceSopenharmony_ci /* fallthru */ 561d4afb5ceSopenharmony_ci case HR_CRLF: 562d4afb5ceSopenharmony_ci if ((*p != '\x0a' && *p != '\x0d') || 563d4afb5ceSopenharmony_ci p + 1 == wsi->http.cgi->headers_start) { 564d4afb5ceSopenharmony_ci *name = '\0'; 565d4afb5ceSopenharmony_ci if ((strcmp((const char *)buf, 566d4afb5ceSopenharmony_ci "transfer-encoding") 567d4afb5ceSopenharmony_ci )) { 568d4afb5ceSopenharmony_ci lwsl_debug("+ %s: %s\n", 569d4afb5ceSopenharmony_ci buf, value); 570d4afb5ceSopenharmony_ci if ( 571d4afb5ceSopenharmony_ci lws_add_http_header_by_name(wsi, buf, 572d4afb5ceSopenharmony_ci (unsigned char *)value, lws_ptr_diff(name, value), 573d4afb5ceSopenharmony_ci (unsigned char **)&wsi->http.cgi->headers_pos, 574d4afb5ceSopenharmony_ci (unsigned char *)wsi->http.cgi->headers_end)) 575d4afb5ceSopenharmony_ci return 1; 576d4afb5ceSopenharmony_ci hrs = HR_NAME; 577d4afb5ceSopenharmony_ci name = buf; 578d4afb5ceSopenharmony_ci break; 579d4afb5ceSopenharmony_ci } 580d4afb5ceSopenharmony_ci } 581d4afb5ceSopenharmony_ci p++; 582d4afb5ceSopenharmony_ci break; 583d4afb5ceSopenharmony_ci } 584d4afb5ceSopenharmony_ci } 585d4afb5ceSopenharmony_cipost_hpack_recode: 586d4afb5ceSopenharmony_ci /* finalize cached headers before dumping them */ 587d4afb5ceSopenharmony_ci if (lws_finalize_http_header(wsi, 588d4afb5ceSopenharmony_ci (unsigned char **)&wsi->http.cgi->headers_pos, 589d4afb5ceSopenharmony_ci (unsigned char *)wsi->http.cgi->headers_end)) { 590d4afb5ceSopenharmony_ci 591d4afb5ceSopenharmony_ci lwsl_notice("finalize failed\n"); 592d4afb5ceSopenharmony_ci return -1; 593d4afb5ceSopenharmony_ci } 594d4afb5ceSopenharmony_ci 595d4afb5ceSopenharmony_ci wsi->hdr_state = LHCS_DUMP_HEADERS; 596d4afb5ceSopenharmony_ci wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_HEADERS; 597d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 598d4afb5ceSopenharmony_ci /* back to the loop for writeability again */ 599d4afb5ceSopenharmony_ci return 0; 600d4afb5ceSopenharmony_ci 601d4afb5ceSopenharmony_ci case LHCS_DUMP_HEADERS: 602d4afb5ceSopenharmony_ci 603d4afb5ceSopenharmony_ci n = (int)(wsi->http.cgi->headers_pos - 604d4afb5ceSopenharmony_ci wsi->http.cgi->headers_dumped); 605d4afb5ceSopenharmony_ci if (n > 512) 606d4afb5ceSopenharmony_ci n = 512; 607d4afb5ceSopenharmony_ci 608d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "LHCS_DUMP_HEADERS: %d", n); 609d4afb5ceSopenharmony_ci 610d4afb5ceSopenharmony_ci cmd = LWS_WRITE_HTTP_HEADERS_CONTINUATION; 611d4afb5ceSopenharmony_ci if (wsi->http.cgi->headers_dumped + n != 612d4afb5ceSopenharmony_ci wsi->http.cgi->headers_pos) { 613d4afb5ceSopenharmony_ci lwsl_notice("adding no fin flag\n"); 614d4afb5ceSopenharmony_ci cmd |= LWS_WRITE_NO_FIN; 615d4afb5ceSopenharmony_ci } 616d4afb5ceSopenharmony_ci 617d4afb5ceSopenharmony_ci m = lws_write(wsi, 618d4afb5ceSopenharmony_ci (unsigned char *)wsi->http.cgi->headers_dumped, 619d4afb5ceSopenharmony_ci (unsigned int)n, (enum lws_write_protocol)cmd); 620d4afb5ceSopenharmony_ci if (m < 0) { 621d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "write says %d", m); 622d4afb5ceSopenharmony_ci return -1; 623d4afb5ceSopenharmony_ci } 624d4afb5ceSopenharmony_ci wsi->http.cgi->headers_dumped += n; 625d4afb5ceSopenharmony_ci if (wsi->http.cgi->headers_dumped == 626d4afb5ceSopenharmony_ci wsi->http.cgi->headers_pos) { 627d4afb5ceSopenharmony_ci wsi->hdr_state = LHCS_PAYLOAD; 628d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.cgi->headers_buf); 629d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "freed cgi headers"); 630d4afb5ceSopenharmony_ci 631d4afb5ceSopenharmony_ci if (wsi->http.cgi->post_in_expected) { 632d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "post data still " 633d4afb5ceSopenharmony_ci "expected, asking " 634d4afb5ceSopenharmony_ci "for writeable"); 635d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 636d4afb5ceSopenharmony_ci } 637d4afb5ceSopenharmony_ci 638d4afb5ceSopenharmony_ci } else { 639d4afb5ceSopenharmony_ci wsi->reason_bf |= 640d4afb5ceSopenharmony_ci LWS_CB_REASON_AUX_BF__CGI_HEADERS; 641d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 642d4afb5ceSopenharmony_ci } 643d4afb5ceSopenharmony_ci 644d4afb5ceSopenharmony_ci /* 645d4afb5ceSopenharmony_ci * writeability becomes uncertain now we wrote 646d4afb5ceSopenharmony_ci * something, we must return to the event loop 647d4afb5ceSopenharmony_ci */ 648d4afb5ceSopenharmony_ci return 0; 649d4afb5ceSopenharmony_ci } 650d4afb5ceSopenharmony_ci 651d4afb5ceSopenharmony_ci if (!wsi->http.cgi->headers_buf) { 652d4afb5ceSopenharmony_ci /* if we don't already have a headers buf, cook one */ 653d4afb5ceSopenharmony_ci n = 2048; 654d4afb5ceSopenharmony_ci if (wsi->mux_substream) 655d4afb5ceSopenharmony_ci n = 4096; 656d4afb5ceSopenharmony_ci wsi->http.cgi->headers_buf = lws_malloc((unsigned int)n + LWS_PRE, 657d4afb5ceSopenharmony_ci "cgi hdr buf"); 658d4afb5ceSopenharmony_ci if (!wsi->http.cgi->headers_buf) { 659d4afb5ceSopenharmony_ci lwsl_wsi_err(wsi, "OOM"); 660d4afb5ceSopenharmony_ci return -1; 661d4afb5ceSopenharmony_ci } 662d4afb5ceSopenharmony_ci 663d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "allocated cgi hdrs"); 664d4afb5ceSopenharmony_ci wsi->http.cgi->headers_start = 665d4afb5ceSopenharmony_ci wsi->http.cgi->headers_buf + LWS_PRE; 666d4afb5ceSopenharmony_ci wsi->http.cgi->headers_pos = wsi->http.cgi->headers_start; 667d4afb5ceSopenharmony_ci wsi->http.cgi->headers_dumped = wsi->http.cgi->headers_pos; 668d4afb5ceSopenharmony_ci wsi->http.cgi->headers_end = 669d4afb5ceSopenharmony_ci wsi->http.cgi->headers_buf + n - 1; 670d4afb5ceSopenharmony_ci 671d4afb5ceSopenharmony_ci for (n = 0; n < SIGNIFICANT_HDR_COUNT; n++) { 672d4afb5ceSopenharmony_ci wsi->http.cgi->match[n] = 0; 673d4afb5ceSopenharmony_ci wsi->http.cgi->lp = 0; 674d4afb5ceSopenharmony_ci } 675d4afb5ceSopenharmony_ci } 676d4afb5ceSopenharmony_ci 677d4afb5ceSopenharmony_ci n = lws_get_socket_fd(wsi->http.cgi->lsp->stdwsi[LWS_STDOUT]); 678d4afb5ceSopenharmony_ci if (n < 0) 679d4afb5ceSopenharmony_ci return -1; 680d4afb5ceSopenharmony_ci n = (int)read(n, &c, 1); 681d4afb5ceSopenharmony_ci if (n < 0) { 682d4afb5ceSopenharmony_ci if (errno != EAGAIN) { 683d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "read says %d", n); 684d4afb5ceSopenharmony_ci return -1; 685d4afb5ceSopenharmony_ci } 686d4afb5ceSopenharmony_ci else 687d4afb5ceSopenharmony_ci n = 0; 688d4afb5ceSopenharmony_ci 689d4afb5ceSopenharmony_ci if (wsi->http.cgi->headers_pos >= 690d4afb5ceSopenharmony_ci wsi->http.cgi->headers_end - 4) { 691d4afb5ceSopenharmony_ci lwsl_wsi_notice(wsi, "CGI hdrs > buf size"); 692d4afb5ceSopenharmony_ci 693d4afb5ceSopenharmony_ci return -1; 694d4afb5ceSopenharmony_ci } 695d4afb5ceSopenharmony_ci } 696d4afb5ceSopenharmony_ci if (!n) 697d4afb5ceSopenharmony_ci goto agin; 698d4afb5ceSopenharmony_ci 699d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "-- 0x%02X %c %d %d", (unsigned char)c, c, 700d4afb5ceSopenharmony_ci wsi->http.cgi->match[1], wsi->hdr_state); 701d4afb5ceSopenharmony_ci if (!c) 702d4afb5ceSopenharmony_ci return -1; 703d4afb5ceSopenharmony_ci switch (wsi->hdr_state) { 704d4afb5ceSopenharmony_ci case LCHS_HEADER: 705d4afb5ceSopenharmony_ci hdr: 706d4afb5ceSopenharmony_ci for (n = 0; n < SIGNIFICANT_HDR_COUNT; n++) { 707d4afb5ceSopenharmony_ci /* 708d4afb5ceSopenharmony_ci * significant headers with 709d4afb5ceSopenharmony_ci * numeric decimal payloads 710d4afb5ceSopenharmony_ci */ 711d4afb5ceSopenharmony_ci if (!significant_hdr[n][wsi->http.cgi->match[n]] && 712d4afb5ceSopenharmony_ci (c >= '0' && c <= '9') && 713d4afb5ceSopenharmony_ci wsi->http.cgi->lp < (int)sizeof(wsi->http.cgi->l) - 1) { 714d4afb5ceSopenharmony_ci wsi->http.cgi->l[wsi->http.cgi->lp++] = c; 715d4afb5ceSopenharmony_ci wsi->http.cgi->l[wsi->http.cgi->lp] = '\0'; 716d4afb5ceSopenharmony_ci switch (n) { 717d4afb5ceSopenharmony_ci case SIGNIFICANT_HDR_CONTENT_LENGTH: 718d4afb5ceSopenharmony_ci wsi->http.cgi->content_length = 719d4afb5ceSopenharmony_ci (lws_filepos_t)atoll(wsi->http.cgi->l); 720d4afb5ceSopenharmony_ci break; 721d4afb5ceSopenharmony_ci case SIGNIFICANT_HDR_STATUS: 722d4afb5ceSopenharmony_ci wsi->http.cgi->response_code = 723d4afb5ceSopenharmony_ci atoi(wsi->http.cgi->l); 724d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "Status set to %d", 725d4afb5ceSopenharmony_ci wsi->http.cgi->response_code); 726d4afb5ceSopenharmony_ci break; 727d4afb5ceSopenharmony_ci default: 728d4afb5ceSopenharmony_ci break; 729d4afb5ceSopenharmony_ci } 730d4afb5ceSopenharmony_ci } 731d4afb5ceSopenharmony_ci /* hits up to the NUL are sticky until next hdr */ 732d4afb5ceSopenharmony_ci if (significant_hdr[n][wsi->http.cgi->match[n]]) { 733d4afb5ceSopenharmony_ci if (tolower(c) == 734d4afb5ceSopenharmony_ci significant_hdr[n][wsi->http.cgi->match[n]]) 735d4afb5ceSopenharmony_ci wsi->http.cgi->match[n]++; 736d4afb5ceSopenharmony_ci else 737d4afb5ceSopenharmony_ci wsi->http.cgi->match[n] = 0; 738d4afb5ceSopenharmony_ci } 739d4afb5ceSopenharmony_ci } 740d4afb5ceSopenharmony_ci 741d4afb5ceSopenharmony_ci /* some cgi only send us \x0a for EOL */ 742d4afb5ceSopenharmony_ci if (c == '\x0a') { 743d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_SINGLE_0A; 744d4afb5ceSopenharmony_ci *wsi->http.cgi->headers_pos++ = '\x0d'; 745d4afb5ceSopenharmony_ci } 746d4afb5ceSopenharmony_ci *wsi->http.cgi->headers_pos++ = (unsigned char)c; 747d4afb5ceSopenharmony_ci if (c == '\x0d') 748d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_LF1; 749d4afb5ceSopenharmony_ci 750d4afb5ceSopenharmony_ci if (wsi->hdr_state != LCHS_HEADER && 751d4afb5ceSopenharmony_ci !significant_hdr[SIGNIFICANT_HDR_TRANSFER_ENCODING] 752d4afb5ceSopenharmony_ci [wsi->http.cgi->match[ 753d4afb5ceSopenharmony_ci SIGNIFICANT_HDR_TRANSFER_ENCODING]]) { 754d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "cgi produced chunked"); 755d4afb5ceSopenharmony_ci wsi->http.cgi->explicitly_chunked = 1; 756d4afb5ceSopenharmony_ci } 757d4afb5ceSopenharmony_ci 758d4afb5ceSopenharmony_ci /* presence of Location: mandates 302 retcode */ 759d4afb5ceSopenharmony_ci if (wsi->hdr_state != LCHS_HEADER && 760d4afb5ceSopenharmony_ci !significant_hdr[SIGNIFICANT_HDR_LOCATION][ 761d4afb5ceSopenharmony_ci wsi->http.cgi->match[SIGNIFICANT_HDR_LOCATION]]) { 762d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "CGI: Location hdr seen"); 763d4afb5ceSopenharmony_ci wsi->http.cgi->response_code = 302; 764d4afb5ceSopenharmony_ci } 765d4afb5ceSopenharmony_ci break; 766d4afb5ceSopenharmony_ci case LCHS_LF1: 767d4afb5ceSopenharmony_ci *wsi->http.cgi->headers_pos++ = (unsigned char)c; 768d4afb5ceSopenharmony_ci if (c == '\x0a') { 769d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_CR2; 770d4afb5ceSopenharmony_ci break; 771d4afb5ceSopenharmony_ci } 772d4afb5ceSopenharmony_ci /* we got \r[^\n]... it's unreasonable */ 773d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "funny CRLF 0x%02X", 774d4afb5ceSopenharmony_ci (unsigned char)c); 775d4afb5ceSopenharmony_ci return -1; 776d4afb5ceSopenharmony_ci 777d4afb5ceSopenharmony_ci case LCHS_CR2: 778d4afb5ceSopenharmony_ci if (c == '\x0d') { 779d4afb5ceSopenharmony_ci /* drop the \x0d */ 780d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_LF2; 781d4afb5ceSopenharmony_ci break; 782d4afb5ceSopenharmony_ci } 783d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_HEADER; 784d4afb5ceSopenharmony_ci for (n = 0; n < SIGNIFICANT_HDR_COUNT; n++) 785d4afb5ceSopenharmony_ci wsi->http.cgi->match[n] = 0; 786d4afb5ceSopenharmony_ci wsi->http.cgi->lp = 0; 787d4afb5ceSopenharmony_ci goto hdr; 788d4afb5ceSopenharmony_ci 789d4afb5ceSopenharmony_ci case LCHS_LF2: 790d4afb5ceSopenharmony_ci case LCHS_SINGLE_0A: 791d4afb5ceSopenharmony_ci m = wsi->hdr_state; 792d4afb5ceSopenharmony_ci if (c == '\x0a') { 793d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "Content-Length: %lld", 794d4afb5ceSopenharmony_ci (unsigned long long) 795d4afb5ceSopenharmony_ci wsi->http.cgi->content_length); 796d4afb5ceSopenharmony_ci wsi->hdr_state = LHCS_RESPONSE; 797d4afb5ceSopenharmony_ci /* 798d4afb5ceSopenharmony_ci * drop the \0xa ... finalize 799d4afb5ceSopenharmony_ci * will add it if needed (HTTP/1) 800d4afb5ceSopenharmony_ci */ 801d4afb5ceSopenharmony_ci break; 802d4afb5ceSopenharmony_ci } 803d4afb5ceSopenharmony_ci if (m == LCHS_LF2) 804d4afb5ceSopenharmony_ci /* we got \r\n\r[^\n]... unreasonable */ 805d4afb5ceSopenharmony_ci return -1; 806d4afb5ceSopenharmony_ci /* we got \x0anext header, it's reasonable */ 807d4afb5ceSopenharmony_ci *wsi->http.cgi->headers_pos++ = (unsigned char)c; 808d4afb5ceSopenharmony_ci wsi->hdr_state = LCHS_HEADER; 809d4afb5ceSopenharmony_ci for (n = 0; n < SIGNIFICANT_HDR_COUNT; n++) 810d4afb5ceSopenharmony_ci wsi->http.cgi->match[n] = 0; 811d4afb5ceSopenharmony_ci wsi->http.cgi->lp = 0; 812d4afb5ceSopenharmony_ci break; 813d4afb5ceSopenharmony_ci case LHCS_PAYLOAD: 814d4afb5ceSopenharmony_ci break; 815d4afb5ceSopenharmony_ci } 816d4afb5ceSopenharmony_ci 817d4afb5ceSopenharmony_ciagin: 818d4afb5ceSopenharmony_ci /* ran out of input, ended the hdrs, or filled up the hdrs buf */ 819d4afb5ceSopenharmony_ci if (!n || wsi->hdr_state == LHCS_PAYLOAD) 820d4afb5ceSopenharmony_ci return 0; 821d4afb5ceSopenharmony_ci } 822d4afb5ceSopenharmony_ci 823d4afb5ceSopenharmony_ci /* payload processing */ 824d4afb5ceSopenharmony_ci 825d4afb5ceSopenharmony_ci m = !wsi->http.cgi->implied_chunked && !wsi->mux_substream && 826d4afb5ceSopenharmony_ci // !wsi->http.cgi->explicitly_chunked && 827d4afb5ceSopenharmony_ci !wsi->http.cgi->content_length; 828d4afb5ceSopenharmony_ci n = lws_get_socket_fd(wsi->http.cgi->lsp->stdwsi[LWS_STDOUT]); 829d4afb5ceSopenharmony_ci if (n < 0) 830d4afb5ceSopenharmony_ci return -1; 831d4afb5ceSopenharmony_ci n = (int)read(n, start, sizeof(buf) - LWS_PRE); 832d4afb5ceSopenharmony_ci 833d4afb5ceSopenharmony_ci if (n < 0 && errno != EAGAIN) { 834d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "stdout read says %d", n); 835d4afb5ceSopenharmony_ci return -1; 836d4afb5ceSopenharmony_ci } 837d4afb5ceSopenharmony_ci if (n > 0) { 838d4afb5ceSopenharmony_ci // lwsl_hexdump_notice(buf, n); 839d4afb5ceSopenharmony_ci 840d4afb5ceSopenharmony_ci if (!wsi->mux_substream && m) { 841d4afb5ceSopenharmony_ci char chdr[LWS_HTTP_CHUNK_HDR_SIZE]; 842d4afb5ceSopenharmony_ci m = lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3, 843d4afb5ceSopenharmony_ci "%X\x0d\x0a", n); 844d4afb5ceSopenharmony_ci memmove(start + m, start, (unsigned int)n); 845d4afb5ceSopenharmony_ci memcpy(start, chdr, (unsigned int)m); 846d4afb5ceSopenharmony_ci memcpy(start + m + n, "\x0d\x0a", 2); 847d4afb5ceSopenharmony_ci n += m + 2; 848d4afb5ceSopenharmony_ci } 849d4afb5ceSopenharmony_ci 850d4afb5ceSopenharmony_ci 851d4afb5ceSopenharmony_ci#if defined(LWS_WITH_HTTP2) 852d4afb5ceSopenharmony_ci if (wsi->mux_substream) { 853d4afb5ceSopenharmony_ci struct lws *nwsi = lws_get_network_wsi(wsi); 854d4afb5ceSopenharmony_ci 855d4afb5ceSopenharmony_ci __lws_set_timeout(wsi, 856d4afb5ceSopenharmony_ci PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31); 857d4afb5ceSopenharmony_ci 858d4afb5ceSopenharmony_ci if (!nwsi->immortal_substream_count) 859d4afb5ceSopenharmony_ci __lws_set_timeout(nwsi, 860d4afb5ceSopenharmony_ci PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31); 861d4afb5ceSopenharmony_ci } 862d4afb5ceSopenharmony_ci#endif 863d4afb5ceSopenharmony_ci 864d4afb5ceSopenharmony_ci cmd = LWS_WRITE_HTTP; 865d4afb5ceSopenharmony_ci if (wsi->http.cgi->content_length_seen + (unsigned int)n == 866d4afb5ceSopenharmony_ci wsi->http.cgi->content_length) 867d4afb5ceSopenharmony_ci cmd = LWS_WRITE_HTTP_FINAL; 868d4afb5ceSopenharmony_ci 869d4afb5ceSopenharmony_ci m = lws_write(wsi, (unsigned char *)start, (unsigned int)n, (enum lws_write_protocol)cmd); 870d4afb5ceSopenharmony_ci //lwsl_notice("write %d\n", m); 871d4afb5ceSopenharmony_ci if (m < 0) { 872d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "stdout write says %d\n", m); 873d4afb5ceSopenharmony_ci return -1; 874d4afb5ceSopenharmony_ci } 875d4afb5ceSopenharmony_ci wsi->http.cgi->content_length_seen += (unsigned int)n; 876d4afb5ceSopenharmony_ci } else { 877d4afb5ceSopenharmony_ci 878d4afb5ceSopenharmony_ci if (!wsi->mux_substream && m) { 879d4afb5ceSopenharmony_ci uint8_t term[LWS_PRE + 6]; 880d4afb5ceSopenharmony_ci 881d4afb5ceSopenharmony_ci lwsl_wsi_info(wsi, "sent trailer"); 882d4afb5ceSopenharmony_ci memcpy(term + LWS_PRE, (uint8_t *)"0\x0d\x0a\x0d\x0a", 5); 883d4afb5ceSopenharmony_ci 884d4afb5ceSopenharmony_ci if (lws_write(wsi, term + LWS_PRE, 5, 885d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL) != 5) 886d4afb5ceSopenharmony_ci return -1; 887d4afb5ceSopenharmony_ci 888d4afb5ceSopenharmony_ci wsi->http.cgi->cgi_transaction_over = 1; 889d4afb5ceSopenharmony_ci 890d4afb5ceSopenharmony_ci return 0; 891d4afb5ceSopenharmony_ci } 892d4afb5ceSopenharmony_ci 893d4afb5ceSopenharmony_ci if (wsi->cgi_stdout_zero_length) { 894d4afb5ceSopenharmony_ci lwsl_wsi_debug(wsi, "stdout is POLLHUP'd"); 895d4afb5ceSopenharmony_ci if (wsi->mux_substream) 896d4afb5ceSopenharmony_ci m = lws_write(wsi, (unsigned char *)start, 0, 897d4afb5ceSopenharmony_ci LWS_WRITE_HTTP_FINAL); 898d4afb5ceSopenharmony_ci else 899d4afb5ceSopenharmony_ci return -1; 900d4afb5ceSopenharmony_ci return 1; 901d4afb5ceSopenharmony_ci } 902d4afb5ceSopenharmony_ci wsi->cgi_stdout_zero_length = 1; 903d4afb5ceSopenharmony_ci } 904d4afb5ceSopenharmony_ci return 0; 905d4afb5ceSopenharmony_ci} 906d4afb5ceSopenharmony_ci 907d4afb5ceSopenharmony_ciint 908d4afb5ceSopenharmony_cilws_cgi_kill(struct lws *wsi) 909d4afb5ceSopenharmony_ci{ 910d4afb5ceSopenharmony_ci struct lws_cgi_args args; 911d4afb5ceSopenharmony_ci pid_t pid; 912d4afb5ceSopenharmony_ci int n, m = 0; 913d4afb5ceSopenharmony_ci 914d4afb5ceSopenharmony_ci if (!wsi->http.cgi || !wsi->http.cgi->lsp) 915d4afb5ceSopenharmony_ci return 0; 916d4afb5ceSopenharmony_ci 917d4afb5ceSopenharmony_ci pid = wsi->http.cgi->lsp->child_pid; 918d4afb5ceSopenharmony_ci 919d4afb5ceSopenharmony_ci args.stdwsi = &wsi->http.cgi->lsp->stdwsi[0]; 920d4afb5ceSopenharmony_ci lws_spawn_piped_kill_child_process(wsi->http.cgi->lsp); 921d4afb5ceSopenharmony_ci /* that has invalidated and NULL'd wsi->http.cgi->lsp */ 922d4afb5ceSopenharmony_ci 923d4afb5ceSopenharmony_ci if (pid != -1) { 924d4afb5ceSopenharmony_ci if (wsi->http.cgi) 925d4afb5ceSopenharmony_ci m = wsi->http.cgi->being_closed; 926d4afb5ceSopenharmony_ci n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, 927d4afb5ceSopenharmony_ci LWS_CALLBACK_CGI_TERMINATED, 928d4afb5ceSopenharmony_ci wsi->user_space, (void *)&args, 929d4afb5ceSopenharmony_ci (unsigned int)pid); 930d4afb5ceSopenharmony_ci if (n && !m) 931d4afb5ceSopenharmony_ci lws_close_free_wsi(wsi, 0, "lws_cgi_kill"); 932d4afb5ceSopenharmony_ci } 933d4afb5ceSopenharmony_ci 934d4afb5ceSopenharmony_ci return 0; 935d4afb5ceSopenharmony_ci} 936d4afb5ceSopenharmony_ci 937d4afb5ceSopenharmony_ciint 938d4afb5ceSopenharmony_cilws_cgi_kill_terminated(struct lws_context_per_thread *pt) 939d4afb5ceSopenharmony_ci{ 940d4afb5ceSopenharmony_ci struct lws_cgi **pcgi, *cgi = NULL; 941d4afb5ceSopenharmony_ci int status, n = 1; 942d4afb5ceSopenharmony_ci 943d4afb5ceSopenharmony_ci while (n > 0) { 944d4afb5ceSopenharmony_ci /* find finished guys but don't reap yet */ 945d4afb5ceSopenharmony_ci n = waitpid(-1, &status, WNOHANG); 946d4afb5ceSopenharmony_ci if (n <= 0) 947d4afb5ceSopenharmony_ci continue; 948d4afb5ceSopenharmony_ci lwsl_cx_debug(pt->context, "observed PID %d terminated", n); 949d4afb5ceSopenharmony_ci 950d4afb5ceSopenharmony_ci pcgi = &pt->http.cgi_list; 951d4afb5ceSopenharmony_ci 952d4afb5ceSopenharmony_ci /* check all the subprocesses on the cgi list */ 953d4afb5ceSopenharmony_ci while (*pcgi) { 954d4afb5ceSopenharmony_ci /* get the next one first as list may change */ 955d4afb5ceSopenharmony_ci cgi = *pcgi; 956d4afb5ceSopenharmony_ci pcgi = &(*pcgi)->cgi_list; 957d4afb5ceSopenharmony_ci 958d4afb5ceSopenharmony_ci if (cgi->lsp->child_pid <= 0) 959d4afb5ceSopenharmony_ci continue; 960d4afb5ceSopenharmony_ci 961d4afb5ceSopenharmony_ci /* finish sending cached headers */ 962d4afb5ceSopenharmony_ci if (cgi->headers_buf) 963d4afb5ceSopenharmony_ci continue; 964d4afb5ceSopenharmony_ci 965d4afb5ceSopenharmony_ci /* wait for stdout to be drained */ 966d4afb5ceSopenharmony_ci if (cgi->content_length > cgi->content_length_seen) 967d4afb5ceSopenharmony_ci continue; 968d4afb5ceSopenharmony_ci 969d4afb5ceSopenharmony_ci if (cgi->content_length) { 970d4afb5ceSopenharmony_ci lwsl_cx_debug(pt->context, "expected content " 971d4afb5ceSopenharmony_ci "length seen: %lld", 972d4afb5ceSopenharmony_ci (unsigned long long)cgi->content_length_seen); 973d4afb5ceSopenharmony_ci } 974d4afb5ceSopenharmony_ci 975d4afb5ceSopenharmony_ci /* reap it */ 976d4afb5ceSopenharmony_ci waitpid(n, &status, WNOHANG); 977d4afb5ceSopenharmony_ci /* 978d4afb5ceSopenharmony_ci * he's already terminated so no need for kill() 979d4afb5ceSopenharmony_ci * but we should do the terminated cgi callback 980d4afb5ceSopenharmony_ci * and close him if he's not already closing 981d4afb5ceSopenharmony_ci */ 982d4afb5ceSopenharmony_ci if (n == cgi->lsp->child_pid) { 983d4afb5ceSopenharmony_ci 984d4afb5ceSopenharmony_ci if (!cgi->content_length) { 985d4afb5ceSopenharmony_ci /* 986d4afb5ceSopenharmony_ci * well, if he sends chunked... 987d4afb5ceSopenharmony_ci * give him 2s after the 988d4afb5ceSopenharmony_ci * cgi terminated to send buffered 989d4afb5ceSopenharmony_ci */ 990d4afb5ceSopenharmony_ci cgi->chunked_grace++; 991d4afb5ceSopenharmony_ci continue; 992d4afb5ceSopenharmony_ci } 993d4afb5ceSopenharmony_ci 994d4afb5ceSopenharmony_ci /* defeat kill() */ 995d4afb5ceSopenharmony_ci cgi->lsp->child_pid = 0; 996d4afb5ceSopenharmony_ci lws_cgi_kill(cgi->wsi); 997d4afb5ceSopenharmony_ci 998d4afb5ceSopenharmony_ci break; 999d4afb5ceSopenharmony_ci } 1000d4afb5ceSopenharmony_ci cgi = NULL; 1001d4afb5ceSopenharmony_ci } 1002d4afb5ceSopenharmony_ci /* if not found on the cgi list, as he's one of ours, reap */ 1003d4afb5ceSopenharmony_ci if (!cgi) 1004d4afb5ceSopenharmony_ci waitpid(n, &status, WNOHANG); 1005d4afb5ceSopenharmony_ci 1006d4afb5ceSopenharmony_ci } 1007d4afb5ceSopenharmony_ci 1008d4afb5ceSopenharmony_ci pcgi = &pt->http.cgi_list; 1009d4afb5ceSopenharmony_ci 1010d4afb5ceSopenharmony_ci /* check all the subprocesses on the cgi list */ 1011d4afb5ceSopenharmony_ci while (*pcgi) { 1012d4afb5ceSopenharmony_ci /* get the next one first as list may change */ 1013d4afb5ceSopenharmony_ci cgi = *pcgi; 1014d4afb5ceSopenharmony_ci pcgi = &(*pcgi)->cgi_list; 1015d4afb5ceSopenharmony_ci 1016d4afb5ceSopenharmony_ci if (!cgi || !cgi->lsp || cgi->lsp->child_pid <= 0) 1017d4afb5ceSopenharmony_ci continue; 1018d4afb5ceSopenharmony_ci 1019d4afb5ceSopenharmony_ci /* we deferred killing him after reaping his PID */ 1020d4afb5ceSopenharmony_ci if (cgi->chunked_grace) { 1021d4afb5ceSopenharmony_ci cgi->chunked_grace++; 1022d4afb5ceSopenharmony_ci if (cgi->chunked_grace < 2) 1023d4afb5ceSopenharmony_ci continue; 1024d4afb5ceSopenharmony_ci goto finish_him; 1025d4afb5ceSopenharmony_ci } 1026d4afb5ceSopenharmony_ci 1027d4afb5ceSopenharmony_ci /* finish sending cached headers */ 1028d4afb5ceSopenharmony_ci if (cgi->headers_buf) 1029d4afb5ceSopenharmony_ci continue; 1030d4afb5ceSopenharmony_ci 1031d4afb5ceSopenharmony_ci /* wait for stdout to be drained */ 1032d4afb5ceSopenharmony_ci if (cgi->content_length > cgi->content_length_seen) 1033d4afb5ceSopenharmony_ci continue; 1034d4afb5ceSopenharmony_ci 1035d4afb5ceSopenharmony_ci if (cgi->content_length) 1036d4afb5ceSopenharmony_ci lwsl_wsi_debug(cgi->wsi, "expected cont len seen: %lld", 1037d4afb5ceSopenharmony_ci (unsigned long long)cgi->content_length_seen); 1038d4afb5ceSopenharmony_ci 1039d4afb5ceSopenharmony_ci /* reap it */ 1040d4afb5ceSopenharmony_ci if (waitpid(cgi->lsp->child_pid, &status, WNOHANG) > 0) { 1041d4afb5ceSopenharmony_ci 1042d4afb5ceSopenharmony_ci if (!cgi->content_length) { 1043d4afb5ceSopenharmony_ci /* 1044d4afb5ceSopenharmony_ci * well, if he sends chunked... 1045d4afb5ceSopenharmony_ci * give him 2s after the 1046d4afb5ceSopenharmony_ci * cgi terminated to send buffered 1047d4afb5ceSopenharmony_ci */ 1048d4afb5ceSopenharmony_ci cgi->chunked_grace++; 1049d4afb5ceSopenharmony_ci continue; 1050d4afb5ceSopenharmony_ci } 1051d4afb5ceSopenharmony_cifinish_him: 1052d4afb5ceSopenharmony_ci lwsl_cx_debug(pt->context, "found PID %d on cgi list", 1053d4afb5ceSopenharmony_ci cgi->lsp->child_pid); 1054d4afb5ceSopenharmony_ci 1055d4afb5ceSopenharmony_ci /* defeat kill() */ 1056d4afb5ceSopenharmony_ci cgi->lsp->child_pid = 0; 1057d4afb5ceSopenharmony_ci lws_cgi_kill(cgi->wsi); 1058d4afb5ceSopenharmony_ci 1059d4afb5ceSopenharmony_ci break; 1060d4afb5ceSopenharmony_ci } 1061d4afb5ceSopenharmony_ci } 1062d4afb5ceSopenharmony_ci 1063d4afb5ceSopenharmony_ci return 0; 1064d4afb5ceSopenharmony_ci} 1065d4afb5ceSopenharmony_ci 1066d4afb5ceSopenharmony_cistruct lws * 1067d4afb5ceSopenharmony_cilws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch) 1068d4afb5ceSopenharmony_ci{ 1069d4afb5ceSopenharmony_ci if (!wsi->http.cgi) 1070d4afb5ceSopenharmony_ci return NULL; 1071d4afb5ceSopenharmony_ci 1072d4afb5ceSopenharmony_ci return wsi->http.cgi->lsp->stdwsi[ch]; 1073d4afb5ceSopenharmony_ci} 1074d4afb5ceSopenharmony_ci 1075d4afb5ceSopenharmony_civoid 1076d4afb5ceSopenharmony_cilws_cgi_remove_and_kill(struct lws *wsi) 1077d4afb5ceSopenharmony_ci{ 1078d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 1079d4afb5ceSopenharmony_ci struct lws_cgi **pcgi = &pt->http.cgi_list; 1080d4afb5ceSopenharmony_ci 1081d4afb5ceSopenharmony_ci /* remove us from the cgi list */ 1082d4afb5ceSopenharmony_ci 1083d4afb5ceSopenharmony_ci while (*pcgi) { 1084d4afb5ceSopenharmony_ci if (*pcgi == wsi->http.cgi) { 1085d4afb5ceSopenharmony_ci /* drop us from the pt cgi list */ 1086d4afb5ceSopenharmony_ci *pcgi = (*pcgi)->cgi_list; 1087d4afb5ceSopenharmony_ci break; 1088d4afb5ceSopenharmony_ci } 1089d4afb5ceSopenharmony_ci pcgi = &(*pcgi)->cgi_list; 1090d4afb5ceSopenharmony_ci } 1091d4afb5ceSopenharmony_ci if (wsi->http.cgi->headers_buf) 1092d4afb5ceSopenharmony_ci lws_free_set_NULL(wsi->http.cgi->headers_buf); 1093d4afb5ceSopenharmony_ci 1094d4afb5ceSopenharmony_ci /* we have a cgi going, we must kill it */ 1095d4afb5ceSopenharmony_ci wsi->http.cgi->being_closed = 1; 1096d4afb5ceSopenharmony_ci lws_cgi_kill(wsi); 1097d4afb5ceSopenharmony_ci 1098d4afb5ceSopenharmony_ci if (!pt->http.cgi_list) 1099d4afb5ceSopenharmony_ci lws_sul_cancel(&pt->sul_cgi); 1100d4afb5ceSopenharmony_ci} 1101