changeset 895:894e142ebdf8

Tests: TODO fastcgi request body end-of-stream.
author Sergey Kandaurov <pluknet@nginx.com>
date Mon, 11 Apr 2016 23:06:25 +0300
parents f50ee6804216
children 48d277065309
files fastcgi_body.t
diffstat 1 files changed, 82 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/fastcgi_body.t
+++ b/fastcgi_body.t
@@ -21,10 +21,6 @@ use Test::Nginx;
 select STDERR; $| = 1;
 select STDOUT; $| = 1;
 
-eval { require FCGI; };
-plan(skip_all => 'FCGI not installed') if $@;
-plan(skip_all => 'win32') if $^O eq 'MSWin32';
-
 my $t = Test::Nginx->new()->has(qw/http fastcgi/)->plan(5)
 	->write_file_expand('nginx.conf', <<'EOF');
 
@@ -57,12 +53,16 @@ EOF
 
 ###############################################################################
 
-like(http_get('/'), qr/X-Body: /, 'fastcgi no body');
+like(http_get('/'), qr/X-Body: _eos\x0d?$/ms, 'fastcgi no body');
 
-like(http_get_length('/', ''), qr/X-Body: /, 'fastcgi empty body');
-like(http_get_length('/', 'foobar'), qr/X-Body: foobar/, 'fastcgi body');
+like(http_get_length('/', ''), qr/X-Body: _eos\x0d?$/ms, 'fastcgi empty body');
+like(http_get_length('/', 'foobar'), qr/X-Body: foobar_eos\x0d?$/ms,
+	'fastcgi body');
 
-like(http(<<EOF), qr/X-Body: foobar/, 'fastcgi chunked');
+TODO: {
+local $TODO = 'not yet';
+
+like(http(<<EOF), qr/X-Body: foobar_eos\x0d?$/ms, 'fastcgi chunked');
 GET / HTTP/1.1
 Host: localhost
 Connection: close
@@ -74,7 +74,7 @@ 0
 
 EOF
 
-like(http(<<EOF), qr/X-Body: /, 'fastcgi empty chunked');
+like(http(<<EOF), qr/X-Body: _eos\x0d?$/ms, 'fastcgi empty chunked');
 GET / HTTP/1.1
 Host: localhost
 Connection: close
@@ -84,6 +84,8 @@ 0
 
 EOF
 
+}
+
 ###############################################################################
 
 sub http_get_length {
@@ -101,29 +103,87 @@ EOF
 
 ###############################################################################
 
-sub fastcgi_daemon {
-	my $socket = FCGI::OpenSocket('127.0.0.1:8081', 5);
-	my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV,
-		$socket);
+# Simple FastCGI responder implementation.
+
+# http://www.fastcgi.com/devkit/doc/fcgi-spec.html
+
+sub fastcgi_read_record($) {
+	my ($buf) = @_;
+
+	my ($n, $h, $header);
+
+	return undef unless length $$buf;
+
+	@{$h}{qw/ version type id clen plen /} = unpack("CCnnC", $$buf);
+
+	$h->{content} = substr $$buf, 8, $h->{clen};
+	$h->{padding} = substr $$buf, 8 + $h->{clen}, $h->{plen};
+
+	$$buf = substr $$buf, 8 + $h->{clen} + $h->{plen};
+
+	return $h;
+}
+
+sub fastcgi_respond($$$$) {
+	my ($socket, $version, $id, $body) = @_;
+
+	# stdout
+	$socket->write(pack("CCnnCx", $version, 6, $id, length($body), 0));
+	$socket->write($body);
+
+	# close stdout
+	$socket->write(pack("CCnnCx", $version, 6, $id, 0, 0));
+
+	# end request
+	$socket->write(pack("CCnnCx", $version, 3, $id, 8, 0));
+	$socket->write(pack("NCxxx", 0, 0));
+}
 
-	my $count;
-	my $body;
+sub fastcgi_daemon {
+	my $server = IO::Socket::INET->new(
+		Proto => 'tcp',
+		LocalAddr => '127.0.0.1:8081',
+		Listen => 5,
+		Reuse => 1
+	)
+		or die "Can't create listening socket: $!\n";
+
+	local $SIG{PIPE} = 'IGNORE';
+
+	while (my $client = $server->accept()) {
+		$client->autoflush(1);
+		Test::Nginx::log_core('||', "fastcgi connection");
+
+		$client->sysread(my $buf, 1024) or next;
 
-	while( $request->Accept() >= 0 ) {
-		$count++;
-		read(STDIN, $body, $ENV{'CONTENT_LENGTH'});
+		my ($version, $id);
+		my $body = '';
+
+		while (my $h = fastcgi_read_record(\$buf)) {
+			$version = $h->{version};
+			$id = $h->{id};
+
+			Test::Nginx::log_core('||', "fastcgi record: "
+				. " $h->{version}, $h->{type}, $h->{id}, "
+				. "'$h->{content}'");
 
-		print <<EOF;
+			if ($h->{type} == 5) {
+				$body .= $h->{content} if $h->{clen} > 0;
+
+				# count stdin end-of-stream
+				$body .= '_eos' if $h->{clen} == 0;
+			}
+		}
+
+		# respond
+		fastcgi_respond($client, $version, $id, <<EOF);
 Location: http://127.0.0.1:8080/redirect
 Content-Type: text/html
 X-Body: $body
 
 SEE-THIS
-$count
 EOF
 	}
-
-	FCGI::CloseSocket($socket);
 }
 
 ###############################################################################