Commit 1de7fef7 authored by Sergey Lyubka's avatar Sergey Lyubka

fix blocked CGI read

parent f23d9ff3
...@@ -1305,7 +1305,10 @@ static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) { ...@@ -1305,7 +1305,10 @@ static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
if (ssl != NULL) { if (ssl != NULL) {
nread = SSL_read(ssl, buf, len); nread = SSL_read(ssl, buf, len);
} else if (fp != NULL) { } 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)) if (ferror(fp))
nread = -1; nread = -1;
} else { } else {
......
...@@ -59,13 +59,11 @@ sub req { ...@@ -59,13 +59,11 @@ sub req {
last unless print $sock $byte; last unless print $sock $byte;
select undef, undef, undef, .001 if length($request) < 256; select undef, undef, undef, .001 if length($request) < 256;
} }
my $out = ''; my ($out, $buf) = ('', '');
eval { eval {
alarm $timeout if $timeout; alarm $timeout if $timeout;
foreach (<$sock>) { $out .= $buf while (sysread($sock, $buf, 1024) > 0);
$out .= $_; alarm 0 if $timeout;
}
alarm 0;
}; };
close $sock; close $sock;
...@@ -182,6 +180,14 @@ o("GET /hello.txt HTTP/1.0\n\n", 'Content-Length: 17\s', ...@@ -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", o("GET /%68%65%6c%6c%6f%2e%74%78%74 HTTP/1.0\n\n",
'HTTP/1.1 200 OK', 'URL-decoding'); '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 # '+' in URI must not be URL-decoded to space
write_file("$root/a+.txt", ''); write_file("$root/a+.txt", '');
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI'); 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", ...@@ -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', # 'HTTP/1.1 200.+keep-alive.+HTTP/1.1 200.+close',
# 'Request pipelining', 2); # '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 = { my $mime_types = {
html => 'text/html', html => 'text/html',
htm => 'text/html', htm => 'text/html',
......
#!/usr/bin/env perl #!/usr/bin/env perl
use Cwd; # Make stdout unbuffered
use CGI; $| = 1;
use vars '%in';
CGI::ReadParse();
print "Content-Type: text/html\r\n\r\n";
# This script outputs some content, then sleeps for 5 seconds, then exits. # This script outputs some content, then sleeps for 5 seconds, then exits.
# Web server should return the content immediately after it is sent, # Web server should return the content immediately after it is sent,
# not waiting until the script exits. # not waiting until the script exits.
print "Content-Type: text/html\r\n\r\n";
print "Some data"; print "Some data";
flush STDOUT; sleep 3;
sleep 5;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment