diff --git a/mongoose.c b/mongoose.c index 88a85327..a19c41cc 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1305,7 +1305,10 @@ static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) { if (ssl != NULL) { nread = SSL_read(ssl, buf, len); } else if (fp != NULL) { - nread = fread(buf, 1, (size_t) len, fp); + // Use read() instead of fread(), because if we're reading from the CGI + // pipe, fread() may block until IO buffer is filled up. We cannot afford + // to block and must pass all read bytes immediately to the client. + nread = read(fileno(fp), buf, (size_t) len); if (ferror(fp)) nread = -1; } else { diff --git a/test/test.pl b/test/test.pl index 01ee5a78..c577fcfd 100644 --- a/test/test.pl +++ b/test/test.pl @@ -59,13 +59,11 @@ sub req { last unless print $sock $byte; select undef, undef, undef, .001 if length($request) < 256; } - my $out = ''; + my ($out, $buf) = ('', ''); eval { alarm $timeout if $timeout; - foreach (<$sock>) { - $out .= $_; - } - alarm 0; + $out .= $buf while (sysread($sock, $buf, 1024) > 0); + alarm 0 if $timeout; }; close $sock; @@ -182,6 +180,14 @@ o("GET /hello.txt HTTP/1.0\n\n", 'Content-Length: 17\s', o("GET /%68%65%6c%6c%6f%2e%74%78%74 HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding'); +# Break CGI reading after 1 second. We must get full output. +# Since CGI script does sleep, we sleep as well and increase request count +# manually. +fail('Slow CGI output forward ') unless + req("GET /timeout.cgi HTTP/1.0\r\n\r\n", 0, 1) =~ /Some data/s; +sleep 3; +$num_requests++; + # '+' in URI must not be URL-decoded to space write_file("$root/a+.txt", ''); o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI'); @@ -225,9 +231,6 @@ o("GET /ta/x/ HTTP/1.0\n\n", "SCRIPT_NAME=/ta/x/index.cgi", # 'HTTP/1.1 200.+keep-alive.+HTTP/1.1 200.+close', # 'Request pipelining', 2); -fail('Slow CGI output forward ') unless - req("GET /timeout.cgi HTTP/1.0\r\n\r\n", 1, 1) =~ /Some data/gs; - my $mime_types = { html => 'text/html', htm => 'text/html', diff --git a/test/timeout.cgi b/test/timeout.cgi index 264d1cb0..d97e143b 100755 --- a/test/timeout.cgi +++ b/test/timeout.cgi @@ -1,16 +1,11 @@ #!/usr/bin/env perl -use Cwd; -use CGI; - -use vars '%in'; -CGI::ReadParse(); - -print "Content-Type: text/html\r\n\r\n"; +# Make stdout unbuffered +$| = 1; # This script outputs some content, then sleeps for 5 seconds, then exits. # Web server should return the content immediately after it is sent, # not waiting until the script exits. +print "Content-Type: text/html\r\n\r\n"; print "Some data"; -flush STDOUT; -sleep 5; +sleep 3;