Prechádzať zdrojové kódy

Improve documentation and error messages for CGI

Modify example used to investigate #529
Document CGI will not work for systems without fork (#584)
bel2125 7 rokov pred
rodič
commit
1a7f248e23
3 zmenil súbory, kde vykonal 65 pridanie a 18 odobranie
  1. 43 5
      docs/UserManual.md
  2. 11 8
      src/civetweb.c
  3. 11 5
      test/linux_stderr.cgi

+ 43 - 5
docs/UserManual.md

@@ -76,10 +76,12 @@ CivetWeb can also be used to modify `.htpasswd` passwords files:
 
 
     CivetWeb -A <htpasswd_file> <realm> <user> <passwd>
     CivetWeb -A <htpasswd_file> <realm> <user> <passwd>
 
 
-Unlike other web servers, CivetWeb does not require CGI scripts to be located
-in a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
-recognized by the file name pattern. CivetWeb uses shell-like glob
-patterns. Pattern match starts at the beginning of the string, so essentially
+
+# Pattern matching
+
+CivetWeb uses shell-like glob patterns for several configuration options,
+e.g., CGI, SSI and Lua script files are recognized by the file name pattern. 
+Pattern match starts at the beginning of the string, so essentially
 patterns are prefix patterns. Syntax is as follows:
 patterns are prefix patterns. Syntax is as follows:
 
 
      **      Matches everything
      **      Matches everything
@@ -94,6 +96,7 @@ All other characters in the pattern match themselves. Examples:
     /foo         Any string that begins with /foo
     /foo         Any string that begins with /foo
     **a$|**b$    Any string that ends with a or b
     **a$|**b$    Any string that ends with a or b
 
 
+
 # Configuration Options
 # Configuration Options
 
 
 Below is a list of configuration options understood by CivetWeb.
 Below is a list of configuration options understood by CivetWeb.
@@ -841,6 +844,41 @@ An example is shown in
 [websocket.lua](https://github.com/civetweb/civetweb/blob/master/test/websocket.lua).
 [websocket.lua](https://github.com/civetweb/civetweb/blob/master/test/websocket.lua).
 
 
 
 
+# Using CGI
+
+Unlike some other web servers, CivetWeb does not require CGI scripts to be located
+in a special directory. CGI scripts files are recognized by the file name pattern
+and can be anywhere.
+
+When using CGI, make sure your CGI file names match the `cgi\_pattern` parameter
+configured for the server.
+Furthermore, you must either configure a `cgi\_interpreter` to be used for all
+CGI scripts, or all scripts must start with `#!` followed by the CGI
+interpreter executable, e.g.: `#!/path/to/perl.exe` or `#!/bin/sh`.
+
+See `cgi\_pattern` and `cgi\_interpreter` for more details.
+
+It is possible to disable CGI completely by building the server with
+the `NO\_CGI` define. Setting this define is required for operating 
+systems not supporting `fork/exec` or `CreateProcess` (since CGI is
+based on creating child processes, it will not be available on such
+operating systems for principle reasons).
+
+Every CGI request will spawn a new child process. Data sent from the
+HTTP client to the server is passed to stdin of the child process,
+while data written to stdout by the child process is sent back to the
+HTTP client.
+
+In case a CGI script cannot handle a particular request, it might
+write a short error message to stderr instead of writing to stdout.
+This error message is added to the server error log.
+
+A script should not write to stderr after writing a reply header
+to stdout. In case CGI libraries are writing to stderr (e.g., for
+logging/debugging), the CGI script should redirect stderr to a 
+user defined log file at the beginning of the script.
+
+
 # Common Problems
 # Common Problems
 - PHP doesn't work - getting empty page, or 'File not found' error. The
 - PHP doesn't work - getting empty page, or 'File not found' error. The
   reason for that is wrong paths to the interpreter. Remember that with PHP,
   reason for that is wrong paths to the interpreter. Remember that with PHP,
@@ -858,7 +896,7 @@ An example is shown in
 
 
 - CivetWeb fails to start. If CivetWeb exits immediately when started, this
 - CivetWeb fails to start. If CivetWeb exits immediately when started, this
   usually indicates a syntax error in the configuration file
   usually indicates a syntax error in the configuration file
-  (named `CivetWeb.conf` by default) or the command-line arguments.
+  (named `civetweb.conf` by default) or the command-line arguments.
   Syntax checking is omitted from CivetWeb to keep its size low. However,
   Syntax checking is omitted from CivetWeb to keep its size low. However,
   the Manual should be of help. Note: the syntax changes from time to time,
   the Manual should be of help. Note: the syntax changes from time to time,
   so updating the config file might be necessary after executable update.
   so updating the config file might be necessary after executable update.

+ 11 - 8
src/civetweb.c

@@ -10321,7 +10321,7 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 	}
 	}
 
 
 	buf = NULL;
 	buf = NULL;
-	buflen = 16384;
+	buflen = conn->phys_ctx->max_request_size;
 	i = prepare_cgi_environment(conn, prog, &blk);
 	i = prepare_cgi_environment(conn, prog, &blk);
 	if (i != 0) {
 	if (i != 0) {
 		blk.buf = NULL;
 		blk.buf = NULL;
@@ -10432,7 +10432,7 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 		                status);
 		                status);
 		mg_send_http_error(conn,
 		mg_send_http_error(conn,
 		                   500,
 		                   500,
-		                   "Error: CGI can not open fdout\nfopen: %s",
+		                   "Error: CGI can not open fderr\nfopen: %s",
 		                   status);
 		                   status);
 		goto done;
 		goto done;
 	}
 	}
@@ -10492,20 +10492,22 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 		 * stderr. */
 		 * stderr. */
 		i = pull_all(err, conn, buf, (int)buflen);
 		i = pull_all(err, conn, buf, (int)buflen);
 		if (i > 0) {
 		if (i > 0) {
+			/* CGI program explicitly sent an error */
+			/* Write the error message to the internal log */
 			mg_cry_internal(conn,
 			mg_cry_internal(conn,
 			                "Error: CGI program \"%s\" sent error "
 			                "Error: CGI program \"%s\" sent error "
 			                "message: [%.*s]",
 			                "message: [%.*s]",
 			                prog,
 			                prog,
 			                i,
 			                i,
 			                buf);
 			                buf);
+			/* Don't send the error message back to the client */
 			mg_send_http_error(conn,
 			mg_send_http_error(conn,
 			                   500,
 			                   500,
-			                   "Error: CGI program \"%s\" sent error "
-			                   "message: [%.*s]",
-			                   prog,
-			                   i,
-			                   buf);
+			                   "Error: CGI program \"%s\" failed.",
+			                   prog);
 		} else {
 		} else {
+			/* CGI program did not explicitly send an error, but a broken
+			 * respon header */
 			mg_cry_internal(conn,
 			mg_cry_internal(conn,
 			                "Error: CGI program sent malformed or too big "
 			                "Error: CGI program sent malformed or too big "
 			                "(>%u bytes) HTTP headers: [%.*s]",
 			                "(>%u bytes) HTTP headers: [%.*s]",
@@ -10522,6 +10524,7 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 			                   buf);
 			                   buf);
 		}
 		}
 
 
+		/* in both cases, abort processing CGI */
 		goto done;
 		goto done;
 	}
 	}
 
 
@@ -10568,8 +10571,8 @@ handle_cgi_request(struct mg_connection *conn, const char *prog)
 	mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
 	mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
 
 
 	/* Read the rest of CGI output and send to the client */
 	/* Read the rest of CGI output and send to the client */
+	DEBUG_TRACE("CGI: %s", "forward all data");
 	send_file_data(conn, &fout, 0, INT64_MAX);
 	send_file_data(conn, &fout, 0, INT64_MAX);
-
 	DEBUG_TRACE("CGI: %s", "all data sent");
 	DEBUG_TRACE("CGI: %s", "all data sent");
 
 
 done:
 done:

+ 11 - 5
test/linux_stderr.cgi

@@ -1,10 +1,16 @@
-#!/bin/sh
+#!/bin/bash
 
 
 printf "Content-Type: text/plain\r\n"
 printf "Content-Type: text/plain\r\n"
 printf "\r\n"
 printf "\r\n"
 
 
-echo "This is a shell script called by CGI:"
-tree / 1>&2
-echo
-set
+echo "This is a shell script called by CGI"
+
+for ((number=1;number < 5000;number++))
+{
+echo "Write $number to stdout"
+echo "Write $number to stderr" 1>&2
+}
+
+echo "done"
+