Ver Fonte

Redirect stderr of CGI process to error log (Step 1/3)

bel há 9 anos atrás
pai
commit
390457c535
1 ficheiros alterados com 41 adições e 8 exclusões
  1. 41 8
      src/civetweb.c

+ 41 - 8
src/civetweb.c

@@ -2691,6 +2691,7 @@ static pid_t spawn_process(struct mg_connection *conn,
                            char *envp[],
                            int fdin,
                            int fdout,
+                           int fderr,
                            const char *dir)
 {
 	HANDLE me;
@@ -2725,6 +2726,13 @@ static pid_t spawn_process(struct mg_connection *conn,
 	                0,
 	                TRUE,
 	                DUPLICATE_SAME_ACCESS);
+	DuplicateHandle(me,
+	                (HANDLE)_get_osfhandle(fderr),
+	                me,
+	                &si.hStdError,
+	                0,
+	                TRUE,
+	                DUPLICATE_SAME_ACCESS);
 
 	/* If CGI file is a script, try to read the interpreter line */
 	interp = conn->ctx->config[CGI_INTERPRETER];
@@ -2804,6 +2812,7 @@ static pid_t spawn_process(struct mg_connection *conn,
 
 spawn_cleanup:
 	(void)CloseHandle(si.hStdOutput);
+    (void)CloseHandle(si.hStdError);
 	(void)CloseHandle(si.hStdInput);
 	if (pi.hThread != NULL) {
 		(void)CloseHandle(pi.hThread);
@@ -2920,6 +2929,7 @@ static pid_t spawn_process(struct mg_connection *conn,
                            char *envp[],
                            int fdin,
                            int fdout,
+                           int fderr,
                            const char *dir)
 {
 	pid_t pid;
@@ -2947,11 +2957,16 @@ static pid_t spawn_process(struct mg_connection *conn,
 		} else if (dup2(fdout, 1) == -1) {
 			mg_cry(
 			    conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO));
+		} else if (dup2(fderr, 2) == -1) {
+			mg_cry(
+			    conn, "%s: dup2(%d, 2): %s", __func__, fderr, strerror(ERRNO));
 		} else {
-			/* Not redirecting stderr to stdout, to avoid output being littered
-			 * with the error messages. */
+			/* Keep stderr and stdout in two different pipes.
+             * Stdout will be sent back to the client, 
+             * stderr should go into a server error log. */
 			(void)close(fdin);
 			(void)close(fdout);
+            (void)close(fderr);
 
 			/* After exec, all signal handlers are restored to their default
 			 * values, with one exception of SIGCHLD. According to
@@ -6325,12 +6340,12 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 	char *buf;
 	size_t buflen;
 	int headers_len, data_len, i, truncated;
-	int fdin[2] = {-1, -1}, fdout[2] = {-1, -1};
+	int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
 	const char *status, *status_text, *connection_state;
 	char *pbuf, dir[PATH_MAX], *p;
 	struct mg_request_info ri;
 	struct cgi_environment blk;
-	FILE *in = NULL, *out = NULL;
+	FILE *in = NULL, *out = NULL, *err = NULL;
 	struct file fout = STRUCT_FILE_INITIALIZER;
 	pid_t pid = (pid_t)-1;
 
@@ -6359,13 +6374,13 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 		p = (char *)prog;
 	}
 
-	if (pipe(fdin) != 0 || pipe(fdout) != 0) {
+	if (pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0) {
 		send_http_error(
 		    conn, 500, "Error: Cannot create CGI pipe: %s", strerror(ERRNO));
 		goto done;
 	}
 
-	pid = spawn_process(conn, p, blk.buf, blk.var, fdin[0], fdout[1], dir);
+	pid = spawn_process(conn, p, blk.buf, blk.var, fdin[0], fdout[1], fderr[1], dir);
 	if (pid == (pid_t)-1) {
 		send_http_error(conn,
 		                500,
@@ -6380,6 +6395,8 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 	set_close_on_exec((SOCKET)fdin[1], conn);
 	set_close_on_exec((SOCKET)fdout[0], conn);
 	set_close_on_exec((SOCKET)fdout[1], conn);
+	set_close_on_exec((SOCKET)fderr[0], conn);
+	set_close_on_exec((SOCKET)fderr[1], conn);
 
 	/* Parent closes only one side of the pipes.
 	 * If we don't mark them as closed, close() attempt before
@@ -6387,7 +6404,8 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 	 * Windows does not like when closed descriptor is closed again. */
 	(void)close(fdin[0]);
 	(void)close(fdout[1]);
-	fdin[0] = fdout[1] = -1;
+    (void)close(fderr[1]);
+	fdin[0] = fdout[1] = fderr[1] = -1;
 
 	if ((in = fdopen(fdin[1], "wb")) == NULL) {
 		send_http_error(conn,
@@ -6403,9 +6421,17 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 		                strerror(ERRNO));
 		goto done;
 	}
-
+	if ((err = fdopen(fderr[0], "rb")) == NULL) {
+		send_http_error(conn,
+		                500,
+		                "Error: CGI can not open fdout\nfopen: %s",
+		                strerror(ERRNO));
+		goto done;
+	}
+    
 	setbuf(in, NULL);
 	setbuf(out, NULL);
+    setbuf(err, NULL);
 	fout.fp = out;
 
 	/* Send POST or PUT data to the CGI process if needed */
@@ -6519,6 +6545,13 @@ done:
 	} else if (fdout[0] != -1) {
 		close(fdout[0]);
 	}
+
+	if (err != NULL) {
+		fclose(err);
+	} else if (fderr[0] != -1) {
+		close(fderr[0]);
+	}
+
 	if (buf != NULL) {
 		mg_free(buf);
 	}