Browse Source

Document option for disabling CGI buffering

bel2125 3 years ago
parent
commit
762493c16f
3 changed files with 28 additions and 5 deletions
  1. 10 0
      docs/UserManual.md
  2. 10 1
      src/civetweb.c
  3. 8 4
      test/flush.php

+ 10 - 0
docs/UserManual.md

@@ -260,6 +260,16 @@ Maximum allowed runtime for CGI scripts.  CGI processes are terminated by
 the server after this time.  The default is "no timeout", so scripts may
 the server after this time.  The default is "no timeout", so scripts may
 run or block for undefined time.
 run or block for undefined time.
 
 
+### cgi\_buffering `yes`
+Allow buffering response of CGI program before sending to the client.
+When buffering is enabled content created by CGI scripts is collected in 
+a buffer and forwarded to the client in larger blocks, improving efficiency.
+If partial content has to be sent to the client, try setting 
+`cgi_buffering` to `no`, `allow_sendfile_call` to `no` 
+and `tcp_nodelay` to `1`. This will cost some performance, but not guarantee
+there is no buffering between CGI program and client code, since intermediate 
+proxies or browsers may also buffer data.
+
 ### decode\_query\_string `no`
 ### decode\_query\_string `no`
 URL decode all query strings in the server. 
 URL decode all query strings in the server. 
 If you set this option to `yes`, all callbacks and scripts will only see the already
 If you set this option to `yes`, all callbacks and scripts will only see the already

+ 10 - 1
src/civetweb.c

@@ -10003,7 +10003,16 @@ send_file_data(struct mg_connection *conn,
 			    "Error: Unable to access file at requested position.");
 			    "Error: Unable to access file at requested position.");
 		} else {
 		} else {
 			while (len > 0) {
 			while (len > 0) {
-				/* Calculate how much to read from the file into the buffer */
+				/* Calculate how much to read from the file into the buffer. */
+				/* If no_buffering is set, we should not wait until the
+				 * CGI->Server buffer is filled, but send everything
+				 * immediately. In theory buffering could be turned off using
+				 * setbuf(filep->access.fp, NULL);
+				 * setvbuf(filep->access.fp, NULL, _IONBF, 0);
+				 * but in practice this does not work. A "Linux only" solution
+				 * may be to use select(). The only portable way is to read byte
+				 * by byte, but this is quite inefficient from a performance
+				 * point of view. */
 				to_read = no_buffering ? 1 : sizeof(buf);
 				to_read = no_buffering ? 1 : sizeof(buf);
 				if ((int64_t)to_read > len) {
 				if ((int64_t)to_read > len) {
 					to_read = (int)len;
 					to_read = (int)len;

+ 8 - 4
test/flush.php

@@ -1,12 +1,16 @@
 <?php
 <?php
+// Server test options:
+//  ./civetweb -document_root test -cgi_interpreter /usr/bin/php-cgi -allow_sendfile_call no -num_threads 2 -cgi_buffering no &
+
 set_time_limit(20);
 set_time_limit(20);
 header('Content-Type: text/plain; charset=utf-8');
 header('Content-Type: text/plain; charset=utf-8');
-echo "CivetWeb Auto Flush Test\n";
-for($i = 0; $i <10; $i++) {
-	echo "Auto flush $i\n";
+
+echo "CivetWeb Flush Test:\nPrint one line every second.\n\n";
+for($i = 1; $i <= 10; $i++) {
+	@printf("Line: %2d / 10\n", $i);
 	@flush();
 	@flush();
 	@ob_flush();
 	@ob_flush();
 	sleep(1);
 	sleep(1);
 }
 }
-echo "\nCurrently this test fails, only the first FLUSH is processed by the server.\n";
+echo "\nEnd of test.\n";
 ?>
 ?>