diff --git a/lib/context.c b/lib/context.c index 7447b1db..d8182133 100644 --- a/lib/context.c +++ b/lib/context.c @@ -230,7 +230,6 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, int n; #endif - switch (reason) { case LWS_CALLBACK_HTTP: #ifndef LWS_NO_SERVER diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index c2ccdd71..9ff11c31 100755 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -1249,6 +1249,8 @@ lws_now_secs(void) LWS_VISIBLE int lws_get_socket_fd(struct lws *wsi) { + if (!wsi) + return -1; return wsi->desc.sockfd; } @@ -2511,8 +2513,8 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len cgi->stdwsi[n]->cgi_channel = n; cgi->stdwsi[n]->vhost = wsi->vhost; -// lwsl_err("%s: cgi %p: pipe fd %d -> fd %d / %d\n", __func__, wsi, n, -// cgi->pipe_fds[n][!!(n == 0)], cgi->pipe_fds[n][!(n == 0)]); + lwsl_debug("%s: cgi %p: pipe fd %d -> fd %d / %d\n", __func__, cgi->stdwsi[n], n, + cgi->pipe_fds[n][!!(n == 0)], cgi->pipe_fds[n][!(n == 0)]); /* read side is 0, stdin we want the write side, others read */ cgi->stdwsi[n]->desc.sockfd = cgi->pipe_fds[n][!!(n == 0)]; @@ -2540,7 +2542,8 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len cgi->stdwsi[LWS_STDOUT]->desc.sockfd, cgi->stdwsi[LWS_STDERR]->desc.sockfd); - lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs); + if (timeout_secs) + lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs); /* the cgi stdout is always sending us http1.x header data first */ wsi->hdr_state = LCHS_HEADER; @@ -2569,15 +2572,18 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len "GET", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", }; - for (m = 0; m < ARRAY_SIZE(meths); m++) - if (lws_hdr_total_length(wsi, meths[m]) >= - script_uri_path_len) { - uritok = meths[m]; - break; - } + if (script_uri_path_len >= 0) + for (m = 0; m < ARRAY_SIZE(meths); m++) + if (lws_hdr_total_length(wsi, meths[m]) >= + script_uri_path_len) { + uritok = meths[m]; + break; + } - if (uritok < 0) + if (script_uri_path_len < 0 && uritok < 0) goto bail3; + if (script_uri_path_len < 0) + uritok = 0; lws_snprintf(cgi_path, sizeof(cgi_path) - 1, "REQUEST_URI=%s", lws_hdr_simple_ptr(wsi, uritok)); @@ -2593,7 +2599,7 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len p += lws_snprintf(p, end - p, "QUERY_STRING="); /* dump the individual URI Arg parameters */ m = 0; - while (1) { + while (script_uri_path_len >= 0) { i = lws_hdr_copy_fragment(wsi, tok, sizeof(tok), WSI_TOKEN_HTTP_URI_ARGS, m); if (i < 0) @@ -2614,37 +2620,44 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len p--; *p++ = '\0'; - env_array[n++] = p; - p += lws_snprintf(p, end - p, "PATH_INFO=%s", - lws_hdr_simple_ptr(wsi, uritok) + - script_uri_path_len); - p++; + if (script_uri_path_len >= 0) { + env_array[n++] = p; + p += lws_snprintf(p, end - p, "PATH_INFO=%s", + lws_hdr_simple_ptr(wsi, uritok) + + script_uri_path_len); + p++; + } } - if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) { + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_REFERER)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "HTTP_REFERER=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_REFERER)); p++; } - if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "HTTP_HOST=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); p++; } - if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "HTTP_COOKIE=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COOKIE)); p++; } - if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) { + if (script_uri_path_len >= 0 && + lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_USER_AGENT)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "USER_AGENT=%s", lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_USER_AGENT)); p++; } - if (uritok == WSI_TOKEN_POST_URI) { + if (script_uri_path_len >= 0 && + uritok == WSI_TOKEN_POST_URI) { if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) { env_array[n++] = p; p += lws_snprintf(p, end - p, "CONTENT_TYPE=%s", @@ -2685,7 +2698,8 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len * Actually having made the env, as a cgi we don't need the ah * any more */ - if (lws_header_table_is_in_detachable_state(wsi)) + if (script_uri_path_len >= 0 && + lws_header_table_is_in_detachable_state(wsi)) lws_header_table_detach(wsi, 0); /* we are ready with the redirection pipes... run the thing */ @@ -2713,6 +2727,12 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len for (n = 0; n < 3; n++) close(cgi->pipe_fds[n][!(n == 0)]); + /* inform cgi owner of the child PID */ + n = user_callback_handle_rxflow(wsi->protocol->callback, wsi, + LWS_CALLBACK_CGI_PROCESS_ATTACH, + wsi->user_space, NULL, cgi->pid); + (void)n; + return 0; } @@ -3106,7 +3126,7 @@ handled: n = user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_CGI_TERMINATED, wsi->user_space, - (void *)&args, 0); + (void *)&args, wsi->cgi->pid); wsi->cgi->pid = -1; if (n && !wsi->cgi->being_closed) lws_close_free_wsi(wsi, 0); @@ -3251,6 +3271,16 @@ finish_him: return 0; } + +LWS_VISIBLE LWS_EXTERN struct lws * +lws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch) +{ + if (!wsi->cgi) + return NULL; + + return wsi->cgi->stdwsi[ch]; +} + #endif #ifdef LWS_NO_EXTENSIONS diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index a6e0f5bb..0d014182 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1213,7 +1213,7 @@ enum lws_callback_reasons { * the wsi is closed. Used to, eg, terminate chunking. * The provided `lws_callback_http_dummy()` * handles this and the callback should be directed there if - * you use CGI. */ + * you use CGI. The child PID that terminated is in @len. */ LWS_CALLBACK_CGI_STDIN_DATA = 42, /**< CGI: Data is, to be sent to the CGI process stdin, eg from * a POST body. The provided `lws_callback_http_dummy()` @@ -1389,6 +1389,9 @@ enum lws_callback_reasons { /**< Sent to parent to notify them a child is closing / being * destroyed. @in is the child wsi. */ + LWS_CALLBACK_CGI_PROCESS_ATTACH = 70, + /**< CGI: Sent when the CGI process is spawned for the wsi. The + * @len parameter is the PID of the child process */ /****** add new things just above ---^ ******/ @@ -5140,7 +5143,7 @@ lws_b64_decode_string(const char *in, char *out, int out_size); * However for most cases, binding the cgi to http in and out, the default * lws implementation already does the right thing. */ -#ifdef LWS_WITH_CGI + enum lws_enum_stdinouterr { LWS_STDIN = 0, LWS_STDOUT = 1, @@ -5167,13 +5170,14 @@ struct lws_cgi_args { int len; /**< length */ }; - +#ifdef LWS_WITH_CGI /** * lws_cgi: spawn network-connected cgi process * * \param wsi: connection to own the process * \param exec_array: array of "exec-name" "arg1" ... "argn" NULL - * \param script_uri_path_len: how many chars on the left of the uri are the path to the cgi + * \param script_uri_path_len: how many chars on the left of the uri are the + * path to the cgi, or -1 to spawn without URL-related env vars * \param timeout_secs: seconds script should be allowed to run * \param mp_cgienv: pvo list with per-vhost cgi options to put in env */ @@ -5197,6 +5201,15 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi); */ LWS_VISIBLE LWS_EXTERN int lws_cgi_kill(struct lws *wsi); + +/** + * lws_cgi_get_stdwsi: get wsi for stdin, stdout, or stderr + * + * \param wsi: parent wsi that has cgi + */ +LWS_VISIBLE LWS_EXTERN struct lws * +lws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch); + #endif ///@} diff --git a/lib/service.c b/lib/service.c index 73c884d0..048b3c32 100644 --- a/lib/service.c +++ b/lib/service.c @@ -1418,8 +1418,8 @@ drain: args.stdwsi = &wsi->parent->cgi->stdwsi[0]; args.hdr_state = wsi->hdr_state; - //lwsl_err("CGI LWS_STDOUT waiting wsi %p mode %d state %d\n", - // wsi->parent, wsi->parent->mode, wsi->parent->state); + lwsl_debug("CGI LWS_STDOUT waiting wsi %p mode %d state %d\n", + wsi->parent, wsi->parent->mode, wsi->parent->state); if (user_callback_handle_rxflow( wsi->parent->protocol->callback,