summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/misc/p5-net-fastcgi/t
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:57:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:57:58 +0000
commitbe1c7e50e1e8809ea56f2c9d472eccd8ffd73a97 (patch)
tree9754ff1ca740f6346cf8483ec915d4054bc5da2d /web/server/h2o/libh2o/misc/p5-net-fastcgi/t
parentInitial commit. (diff)
downloadnetdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.tar.xz
netdata-be1c7e50e1e8809ea56f2c9d472eccd8ffd73a97.zip
Adding upstream version 1.44.3.upstream/1.44.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/server/h2o/libh2o/misc/p5-net-fastcgi/t')
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/000_load.t29
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t51
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t44
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t44
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t82
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t41
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t30
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t97
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t42
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t30
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t87
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t42
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t30
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t180
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t98
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t79
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t105
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t80
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t51
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t150
-rw-r--r--web/server/h2o/libh2o/misc/p5-net-fastcgi/t/lib/myconfig.pm9
21 files changed, 1401 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/000_load.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/000_load.t
new file mode 100644
index 00000000..1436a558
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/000_load.t
@@ -0,0 +1,29 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 5;
+
+BEGIN {
+ use_ok('Net::FastCGI');
+ use_ok('Net::FastCGI::Constant');
+ use_ok('Net::FastCGI::IO');
+ use_ok('Net::FastCGI::Protocol');
+
+ if ( $ENV{NET_FASTCGI_PP} ) {
+ use_ok('Net::FastCGI::Protocol::PP');
+ }
+ else {
+ use_ok('Net::FastCGI::Protocol::XS');
+ }
+}
+
+diag("Net::FastCGI $Net::FastCGI::VERSION, Perl $], $^X");
+diag("NET_FASTCGI_PP=$ENV{NET_FASTCGI_PP}");
+
+
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t
new file mode 100644
index 00000000..8e1476b5
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t
@@ -0,0 +1,51 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 13;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_header
+ parse_header ]);
+}
+
+my @tests = (
+ # octets type request_id content_length padding_length
+ ["\x01\x00\x00\x00\x00\x00\x00\x00", 0, 0, 0, 0 ],
+ ["\x01\xFF\xFF\xFF\xFF\xFF\xFF\x00", 0xFF, 0xFFFF, 0xFFFF, 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_header(@$test[1..4]);
+ is_hexstr($got, $expected, 'build_header()');
+}
+
+foreach my $test (@tests) {
+ my @expected = @$test[1..4];
+ my @got = parse_header($test->[0]);
+ is_deeply(\@got, \@expected, "parse_header() in list context");
+}
+
+my @components = qw(type request_id content_length padding_length);
+foreach my $test (@tests) {
+ my $expected; @$expected{@components} = @$test[1..4];
+ my $got = parse_header($test->[0]);
+ is_deeply($got, $expected, "parse_header() in scalar context");
+}
+
+
+throws_ok { parse_header("") } qr/FastCGI: Insufficient .* FCGI_Header/;
+throws_ok { parse_header(undef) } qr/FastCGI: Insufficient .* FCGI_Header/;
+throws_ok { parse_header("\x00\x00\x00\x00\x00\x00\x00\x00") } qr/^FastCGI: Protocol version mismatch/;
+throws_ok { parse_header("\xFF\x00\x00\x00\x00\x00\x00\x00") } qr/^FastCGI: Protocol version mismatch/;
+
+throws_ok { build_header() } qr/^Usage: /;
+throws_ok { parse_header() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t
new file mode 100644
index 00000000..1d238198
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t
@@ -0,0 +1,44 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 18;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Constant', qw[:all]);
+ use_ok('Net::FastCGI::Protocol', qw[ build_header
+ build_record
+ get_record_length ]);
+}
+
+
+is get_record_length(undef), 0, 'get_record_length(undef)';
+
+{
+ for my $len (0..7) {
+ is get_record_length("\x00" x $len), 0, qq<get_record_length("\\x00" x $len)>;
+ }
+}
+
+{
+ for my $len (8, 16, 32, 64) {
+ my $record = build_record(0, 0, "\x00" x $len);
+ is get_record_length($record), FCGI_HEADER_LEN + $len;
+ }
+}
+
+{
+ my $header = build_header(0, 0, 8192, 250);
+ is get_record_length($header), FCGI_HEADER_LEN + 8192 + 250;
+}
+
+# get_record_length(octets)
+for (0, 2) {
+ throws_ok { get_record_length((1) x $_) } qr/^Usage: /;
+}
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t
new file mode 100644
index 00000000..9f321261
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t
@@ -0,0 +1,44 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 11;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_record ]);
+}
+
+my @tests = (
+ # octets type request_id content
+ [ "\x01\x00\x00\x00\x00\x00\x00\x00", 0, 0, undef ],
+ [ "\x01\xFF\xFF\xFF\x00\x00\x00\x00", 0xFF, 0xFFFF, undef ],
+ [ "\x01\x01\x00\x01\x00\x01\x07\x00\x01\x00\x00\x00\x00\x00\x00\x00", 1, 1, "\x01" ],
+ [ "\x01\x01\x00\x01\x00\x05\x03\x00\x01\x01\x01\x01\x01\x00\x00\x00", 1, 1, "\x01\x01\x01\x01\x01" ],
+ [ "\x01\x01\x00\x01\x00\x08\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01", 1, 1, "\x01\x01\x01\x01\x01\x01\x01\x01" ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_record(@$test[1..3]);
+ is_hexstr($got, $expected, 'build_record()');
+}
+
+{
+ my $exp = "\x01\x01\x00\x02\x00\x00\x00\x00";
+ my $got = build_record(1, 2);
+ is_hexstr($got, $exp, 'build_record(1, 2)');
+}
+
+throws_ok { build_record( 0, 0, "\x00" x (0xFFFF + 1) ) } qr/^Invalid Argument: 'content' cannot exceed/;
+
+# build_record(type, request_id [, content])
+for (0..1, 4) {
+ throws_ok { build_record((1) x $_) } qr/^Usage: /;
+}
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t
new file mode 100644
index 00000000..233f225f
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t
@@ -0,0 +1,82 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 12;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_stream ]);
+}
+
+sub TRUE () { !!1 }
+sub FALSE () { !!0 }
+
+my @tests = (
+ # expected, type, request_id, content, terminate
+ [ "", 1, 1, '', FALSE ],
+ [ "", 1, 1, undef, FALSE ],
+ [ "\x01\x01\x00\x01\x00\x00\x00\x00", 1, 1, '', TRUE ],
+ [ "\x01\x01\x00\x01\x00\x00\x00\x00", 1, 1, undef, TRUE ],
+
+ [ "\x01\x01\x00\x01\x00\x03\x05\x00"
+ . "FOO\x00\x00\x00\x00\x00", 1, 1, 'FOO', FALSE ],
+
+ [ "\x01\x01\x00\x01\x00\x03\x05\x00"
+ . "FOO\x00\x00\x00\x00\x00"
+ . "\x01\x01\x00\x01\x00\x00\x00\x00", 1, 1, 'FOO', TRUE ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_stream(@$test[1..4]);
+ is_hexstr($got, $expected, 'build_stream()');
+}
+
+{
+ my $header = "\x01\x01\x00\x01\x7F\xF8\x00\x00";
+ my $content = "x" x 32760;
+ my $trailer = "\x01\x01\x00\x01\x00\x00\x00\x00";
+
+ {
+ my $expected = $header . $content;
+ my $got = build_stream(1,1, $content);
+ is_hexstr($got, $expected, 'build_stream(content_length: 32760 terminate:false)');
+ }
+
+ {
+ my $expected = $header . $content . $trailer;
+ my $got = build_stream(1,1, $content, 1);
+ is_hexstr($got, $expected, 'build_stream(content_length: 32760 terminate:true)');
+ }
+}
+
+{
+ my $records = "\x01\x01\x00\x01\x7F\xF8\x00\x00" # H1
+ . "x" x 32760 # C1
+ . "\x01\x01\x00\x01\x00\x08\x00\x00" # H2
+ . "x" x 8 # C2
+ ;
+ my $content = "x" x 32768;
+ my $trailer = "\x01\x01\x00\x01\x00\x00\x00\x00";
+
+ {
+ my $expected = $records;
+ my $got = build_stream(1,1, $content);
+ is_hexstr($got, $records, 'build_stream(content_length: 32768 terminate:false)');
+ }
+
+ {
+ my $expected = $records . $trailer;
+ my $got = build_stream(1,1, $content, 1);
+ is_hexstr($got, $expected, 'build_stream(content_length: 32768 terminate:true)');
+ }
+}
+
+throws_ok { build_stream() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t
new file mode 100644
index 00000000..031a7d17
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t
@@ -0,0 +1,41 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 9;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_begin_request_body
+ parse_begin_request_body ]);
+}
+
+my @tests = (
+ # octets role flags
+ [ "\x00\x00\x00\x00\x00\x00\x00\x00", 0, 0 ],
+ [ "\xFF\xFF\xFF\x00\x00\x00\x00\x00", 0xFFFF, 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_begin_request_body(@$test[1..2]);
+ is_hexstr($got, $expected, 'build_begin_request_body()');
+}
+
+foreach my $test (@tests) {
+ my @expected = @$test[1..2];
+ my @got = parse_begin_request_body($test->[0]);
+ is_deeply(\@got, \@expected, "parse_begin_request_body()");
+}
+
+throws_ok { parse_begin_request_body("") } qr/^FastCGI: Insufficient .* FCGI_BeginRequestBody/;
+throws_ok { parse_begin_request_body(undef) } qr/^FastCGI: Insufficient .* FCGI_BeginRequestBody/;
+
+throws_ok { build_begin_request_body() } qr/^Usage: /;
+throws_ok { parse_begin_request_body() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t
new file mode 100644
index 00000000..50f94432
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t
@@ -0,0 +1,30 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 4;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_begin_request_record ]);
+}
+
+my @tests = (
+ # octets request_id role flags
+ [ "\x01\x01\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 0, 0, 0 ],
+ [ "\x01\x01\xFF\xFF\x00\x08\x00\x00\xFF\xFF\xFF\x00\x00\x00\x00\x00", 0xFFFF, 0xFFFF, 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_begin_request_record(@$test[1..3]);
+ is_hexstr($got, $expected, 'build_begin_request_record()');
+}
+
+throws_ok { build_begin_request_record() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t
new file mode 100644
index 00000000..e5d6c91f
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t
@@ -0,0 +1,97 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 15;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_begin_request ]);
+ use_ok('Net::FastCGI::Constant', qw[ :type :role ]);
+}
+
+{
+ my $begin = "\x01\x01\x00\x01\x00\x08\x00\x00" # FCGI_Header id=1
+ . "\x00\x01\x00\x00\x00\x00\x00\x00"; # FCGI_BeginRequestBody role=FCGI_RESPONDER
+
+ my $params = "\x01\x04\x00\x01\x00\x00\x00\x00"; # FCGI_Header type=FCGI_PARAMS
+
+ {
+ my $exp = $begin . $params;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, {});
+ is_hexstr($got, $exp, q<build_begin_request(1, FCGI_RESPONDER, 0, {})>);
+ }
+
+ my $stdin = "\x01\x05\x00\x01\x00\x00\x00\x00"; # FCGI_Header type=FCGI_STDIN
+
+ {
+ my $exp = $begin . $params . $stdin;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, {}, '');
+ is_hexstr($got, $exp, q<build_begin_request(1, FCGI_RESPONDER, 0, {}, '')>);
+ }
+
+ {
+ my $exp = $begin . $params . $stdin;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, {}, undef);
+ is_hexstr($got, $exp, q<build_begin_request(1, FCGI_RESPONDER, 0, {}, undef)>);
+ }
+
+ my $data = "\x01\x08\x00\x01\x00\x00\x00\x00"; # FCGI_Header type=FCGI_DATA
+
+ {
+ my $exp = $begin . $params . $stdin . $data;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, {}, '', undef);
+ is_hexstr($got, $exp, q<build_begin_request(1, FCGI_RESPONDER, 0, {}, '', undef)>);
+ }
+
+ {
+ my $exp = $begin . $params . $stdin . $data;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, {}, undef, '');
+ is_hexstr($got, $exp, q<build_begin_request(1, FCGI_RESPONDER, 0, {}, undef, '')>);
+ }
+}
+
+{
+ my $begin = "\x01\x01\x00\x01\x00\x08\x00\x00" # FCGI_Header id=1
+ . "\x00\x01\x00\x00\x00\x00\x00\x00"; # FCGI_BeginRequestBody role=FCGI_RESPONDER
+
+ my $params = "\x01\x04\x00\x01\x00\x08\x00\x00" # FCGI_Header type=FCGI_PARAMS
+ . "\x03\x03FooBar"
+ . "\x01\x04\x00\x01\x00\x00\x00\x00";
+
+ {
+ my $exp = $begin . $params;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, { Foo => 'Bar' });
+ is_hexstr($got, $exp, q!build_begin_request(1, FCGI_RESPONDER, 0, { Foo => 'Bar' })!);
+ }
+
+ my $stdin = "\x01\x05\x00\x01\x03\xFC\x04\x00" # FCGI_Header type=FCGI_STDIN
+ . "x" x 1020 . "\0" x 4
+ . "\x01\x05\x00\x01\x00\x00\x00\x00";
+ {
+ my $exp = $begin . $params . $stdin;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, { Foo => 'Bar' }, 'x' x 1020);
+ is_hexstr($got, $exp, q!build_begin_request(1, FCGI_RESPONDER, 0, { Foo => 'Bar' }, 'x' x 1020)!);
+ }
+
+ my $data = "\x01\x08\x00\x01\x04\x00\x00\x00" # FCGI_Header type=FCGI_DATA
+ . "y" x 1024
+ . "\x01\x08\x00\x01\x00\x00\x00\x00";
+
+ {
+ my $exp = $begin . $params . $stdin . $data;
+ my $got = build_begin_request(1, FCGI_RESPONDER, 0, { Foo => 'Bar' }, 'x' x 1020, 'y' x 1024);
+ is_hexstr($got, $exp, q!build_begin_request(1, FCGI_RESPONDER, 0, { Foo => 'Bar' }, 'x' x 1020, 'y' x 1024)!);
+ }
+}
+
+# build_begin_request(request_id, role, flags, params [, stdin [, data]])
+for (0..3, 7) {
+ throws_ok { build_begin_request((1) x $_) } qr/^Usage: /;
+}
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t
new file mode 100644
index 00000000..783408d4
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t
@@ -0,0 +1,42 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 9;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_end_request_body
+ parse_end_request_body ]);
+}
+
+my @tests = (
+ # octets app_status protocol_status
+ [ "\x00\x00\x00\x00\x00\x00\x00\x00", 0, 0 ],
+ [ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", 0xFFFFFFFF, 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_end_request_body(@$test[1..2]);
+ is_hexstr($got, $expected, 'build_end_request_body()');
+}
+
+foreach my $test (@tests) {
+ my @expected = @$test[1..2];
+ my @got = parse_end_request_body($test->[0]);
+ is_deeply(\@got, \@expected, "parse_end_request_body()");
+}
+
+
+throws_ok { parse_end_request_body("") } qr/^FastCGI: Insufficient .* FCGI_EndRequestBody/;
+throws_ok { parse_end_request_body(undef) } qr/^FastCGI: Insufficient .* FCGI_EndRequestBody/;
+
+throws_ok { build_end_request_body() } qr/^Usage: /;
+throws_ok { parse_end_request_body() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t
new file mode 100644
index 00000000..f76dbd1f
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t
@@ -0,0 +1,30 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 4;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_end_request_record ]);
+}
+
+my @tests = (
+ # octets request_id app_status protocol_status
+ [ "\x01\x03\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 0, 0, 0 ],
+ [ "\x01\x03\xFF\xFF\x00\x08\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", 0xFFFF, 0xFFFFFFFF, 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_end_request_record(@$test[1..3]);
+ is_hexstr($got, $expected, 'build_end_request_record()');
+}
+
+throws_ok { build_end_request_record() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t
new file mode 100644
index 00000000..c7c421c5
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t
@@ -0,0 +1,87 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 13;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_end_request ]);
+ use_ok('Net::FastCGI::Constant', qw[ :type :protocol_status ]);
+}
+
+{
+ my $end = "\x01\x03\x00\x01\x00\x08\x00\x00" # FCGI_Header id=1
+ . "\x00\x00\x00\x00\x00\x00\x00\x00" # FCGI_EndRequestBody
+ ;
+
+ {
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE);
+ is_hexstr($got, $end, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE)>);
+ }
+
+ my $stdout = "\x01\x06\x00\x01\x00\x00\x00\x00"; # FCGI_Header type=FCGI_STDOUT
+
+ {
+ my $exp = $stdout . $end;
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, '');
+ is_hexstr($got, $exp, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE, '')>);
+ }
+
+ {
+ my $exp = $stdout . $end;
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, undef);
+ is_hexstr($got, $exp, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE, undef)>);
+ }
+
+ my $stderr = "\x01\x07\x00\x01\x00\x00\x00\x00"; # FCGI_Header type=FCGI_STDERR
+
+ {
+ my $exp = $stdout . $stderr . $end;
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, '', undef);
+ is_hexstr($got, $exp, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE, '', undef)>);
+ }
+
+ {
+ my $exp = $stdout . $stderr . $end;
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, undef, '');
+ is_hexstr($got, $exp, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE, undef, '')>);
+ }
+}
+
+{
+ my $end = "\x01\x03\x00\x01\x00\x08\x00\x00" # FCGI_Header id=1
+ . "\x00\x00\x00\x00\x00\x00\x00\x00" # FCGI_EndRequestBody
+ ;
+
+ my $stdout = "\x01\x06\x00\x01\x03\xFC\x04\x00" # FCGI_Header type=FCGI_STDOUT
+ . "x" x 1020 . "\0" x 4
+ . "\x01\x06\x00\x01\x00\x00\x00\x00";
+
+ {
+ my $exp = $stdout . $end;
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, 'x' x 1020);
+ is_hexstr($got, $exp, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE, 'x' x 1020)>);
+ }
+
+ my $stderr = "\x01\x07\x00\x01\x04\x00\x00\x00" # FCGI_Header type=FCGI_STDERR
+ . "y" x 1024
+ . "\x01\x07\x00\x01\x00\x00\x00\x00";
+
+ {
+ my $exp = $stdout . $stderr . $end;
+ my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, 'x' x 1020, 'y' x 1024);
+ is_hexstr($got, $exp, q<build_end_request(1, 0, FCGI_REQUEST_COMPLETE, 'x' x 1020, 'y' x 1024)>);
+ }
+}
+
+# build_end_request(request_id, app_status, protocol_status [, stdout [, stderr]])
+for (0..2, 6) {
+ throws_ok { build_end_request((1) x $_) } qr/^Usage: /;
+}
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t
new file mode 100644
index 00000000..27e0d379
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t
@@ -0,0 +1,42 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 9;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_unknown_type_body
+ parse_unknown_type_body ]);
+}
+
+my @tests = (
+ # octets type
+ [ "\x00\x00\x00\x00\x00\x00\x00\x00", 0 ],
+ [ "\xFF\x00\x00\x00\x00\x00\x00\x00", 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_unknown_type_body($test->[1]);
+ is_hexstr($got, $expected, 'build_unknown_type_body()');
+}
+
+foreach my $test (@tests) {
+ my @expected = $test->[1];
+ my @got = parse_unknown_type_body($test->[0]);
+ is_deeply(\@got, \@expected, "parse_unknown_type_body()");
+}
+
+
+throws_ok { parse_unknown_type_body("") } qr/^^FastCGI: Insufficient .* FCGI_UnknownTypeBody/;
+throws_ok { parse_unknown_type_body(undef) } qr/^^FastCGI: Insufficient .* FCGI_UnknownTypeBody/;
+
+throws_ok { build_unknown_type_body() } qr/^Usage: /;
+throws_ok { parse_unknown_type_body() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t
new file mode 100644
index 00000000..8ee053ab
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t
@@ -0,0 +1,30 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 4;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_unknown_type_record ]);
+}
+
+my @tests = (
+ # octets type
+ [ "\x01\x0B\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 0 ],
+ [ "\x01\x0B\x00\x00\x00\x08\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00", 0xFF ],
+);
+
+foreach my $test (@tests) {
+ my $expected = $test->[0];
+ my $got = build_unknown_type_record($test->[1]);
+ is_hexstr($got, $expected, 'build_unknown_type_record()');
+}
+
+throws_ok { build_unknown_type_record() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t
new file mode 100644
index 00000000..34c5fb92
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t
@@ -0,0 +1,180 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 54;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Constant', qw[:all]);
+ use_ok('Net::FastCGI::Protocol', qw[ build_header
+ build_record
+ build_stream
+ parse_record ]);
+}
+
+my @records_ok = (
+ [
+ "\x01\x01\x00\x01\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00",
+ "\x00\x01\x00\x00\x00\x00\x00\x00",
+ { type => FCGI_BEGIN_REQUEST,
+ request_id => 1,
+ role => FCGI_RESPONDER,
+ flags => 0 }
+ ],
+ [
+ "\x01\x02\x00\x01\x00\x00\x00\x00",
+ "",
+ { type => FCGI_ABORT_REQUEST,
+ request_id => 1 }
+ ],
+ [
+ "\x01\x03\x00\x01\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00",
+ { type => FCGI_END_REQUEST,
+ request_id => 1,
+ protocol_status => 0,
+ app_status => 0 }
+ ],
+ [
+ "\x01\x04\x00d\x00\x0B\x05\x00FCGI_PARAMS\x00\x00\x00\x00\x00",
+ "FCGI_PARAMS",
+ { type => FCGI_PARAMS,
+ request_id => 100,
+ content => 'FCGI_PARAMS' }
+ ],
+ [
+ "\x01\x05\x00\xC8\x00\x0A\x06\x00FCGI_STDIN\x00\x00\x00\x00\x00\x00",
+ "FCGI_STDIN",
+ { type => FCGI_STDIN,
+ request_id => 200,
+ content => 'FCGI_STDIN' }
+ ],
+ [
+ "\x01\x06\x01\x2C\x00\x0B\x05\x00FCGI_STDOUT\x00\x00\x00\x00\x00",
+ "FCGI_STDOUT",
+ { type => FCGI_STDOUT,
+ request_id => 300,
+ content => 'FCGI_STDOUT' }
+ ],
+ [
+ "\x01\x07\x01\x90\x00\x0B\x05\x00FCGI_STDERR\x00\x00\x00\x00\x00",
+ "FCGI_STDERR",
+ { type => FCGI_STDERR,
+ request_id => 400,
+ content => 'FCGI_STDERR' }
+ ],
+ [
+ "\x01\x08\x01\xF4\x00\x09\x07\x00FCGI_DATA\x00\x00\x00\x00\x00\x00\x00",
+ "FCGI_DATA",
+ { type => FCGI_DATA,
+ request_id => 500,
+ content => 'FCGI_DATA' }
+ ],
+ [
+ "\x01\x09\x00\x00\x00\x0D\x03\x00\x03\x03BarBaZ\x03\x00FOO\x00\x00\x00",
+ "\x03\x03BarBaZ\x03\x00FOO",
+ { type => FCGI_GET_VALUES,
+ request_id => FCGI_NULL_REQUEST_ID,
+ values => { FOO => '', Bar => 'BaZ' }
+ }
+ ],
+ [
+ "\x01\x0A\x00\x00\x00\x17\x01\x00\x04\x01BETA2\x05\x01ALPHA1\x05\x01GAMMA3\x00",
+ "\x04\x01BETA2\x05\x01ALPHA1\x05\x01GAMMA3",
+ { type => FCGI_GET_VALUES_RESULT,
+ request_id => FCGI_NULL_REQUEST_ID,
+ values => { ALPHA => 1, BETA => 2, GAMMA => 3 }
+ }
+ ],
+ [
+ "\x01\x0B\x00\x00\x00\x08\x00\x00\x64\x00\x00\x00\x00\x00\x00\x00",
+ "\x64\x00\x00\x00\x00\x00\x00\x00",
+ { type => FCGI_UNKNOWN_TYPE,
+ request_id => FCGI_NULL_REQUEST_ID,
+ unknown_type => 100 }
+ ],
+ [
+ "\x01\x6F\x00\xDE\x00\x04\x04\x00oops\x00\x00\x00\x00",
+ "oops",
+ { type => 111,
+ request_id => 222,
+ content => 'oops' }
+ ],
+ [
+ "\x01\xFF\xFF\xFF\x00\x00\x00\x00",
+ "",
+ { type => 0xFF,
+ request_id => 0xFFFF }
+ ],
+);
+
+foreach my $test (@records_ok) {
+ my $expected = $test->[2];
+ my $got = parse_record($test->[0]);
+ is_deeply($got, $expected, "parse_record() in scalar context");
+}
+
+foreach my $test (@records_ok) {
+ my @expected = ($test->[2]->{type}, $test->[2]->{request_id}, $test->[1]);
+ my @got = parse_record($test->[0]);
+ is_deeply(\@got, \@expected, "parse_record() in list context");
+}
+
+my @headers_malformed = (
+ # type, request_id, content_length, padding_length
+ [ FCGI_BEGIN_REQUEST, 0, 0, 0 ],
+ [ FCGI_BEGIN_REQUEST, 1, 0, 0 ],
+ [ FCGI_ABORT_REQUEST, 0, 0, 0 ],
+ [ FCGI_END_REQUEST, 0, 0, 0 ],
+ [ FCGI_END_REQUEST, 1, 0, 0 ],
+ [ FCGI_PARAMS, 0, 0, 0 ],
+ [ FCGI_STDIN, 0, 0, 0 ],
+ [ FCGI_STDOUT, 0, 0, 0 ],
+ [ FCGI_STDERR, 0, 0, 0 ],
+ [ FCGI_DATA, 0, 0, 0 ],
+ [ FCGI_GET_VALUES, 1, 0, 0 ],
+ [ FCGI_GET_VALUES_RESULT, 1, 0, 0 ],
+ [ FCGI_UNKNOWN_TYPE, 0, 0, 0 ],
+ [ FCGI_UNKNOWN_TYPE, 1, 0, 0 ]
+);
+
+foreach my $test (@headers_malformed) {
+ my $octets = build_header(@$test);
+ throws_ok { parse_record($octets) } qr/^FastCGI: Malformed/;
+}
+
+{
+ my $octets = build_header(FCGI_ABORT_REQUEST, 1, 8, 0) . "\x00" x 8;
+ throws_ok { parse_record($octets) } qr/^FastCGI: Malformed/;
+}
+
+my @stream_types = (
+ FCGI_PARAMS,
+ FCGI_STDIN,
+ FCGI_STDOUT,
+ FCGI_STDERR,
+ FCGI_DATA
+);
+
+foreach my $type (@stream_types) {
+ my $expected = { type => $type, request_id => 1, content => '' };
+ my $octets = build_record($type, 1, '');
+ my $got = parse_record($octets);
+ is_deeply($got, $expected, "parse_record(stream record) in scalar context");
+}
+
+foreach my $type (@stream_types) {
+ my @expected = ($type, 1, '');
+ my $octets = build_record($type, 1, '');
+ my @got = parse_record($octets);
+ is_deeply(\@got, \@expected, "parse_record(stream record) in list context");
+}
+
+throws_ok { parse_record() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t
new file mode 100644
index 00000000..35f3793c
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t
@@ -0,0 +1,98 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 33;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Constant', qw[:all]);
+ use_ok('Net::FastCGI::Protocol', qw[ build_header
+ build_record
+ build_stream
+ parse_record_body ]);
+}
+
+my @ok = (
+ [
+ "\x00\x01\x01\x00\x00\x00\x00\x00",
+ { type => FCGI_BEGIN_REQUEST,
+ request_id => 1,
+ role => 1,
+ flags => 1 }
+ ],
+ [
+ "\x00\x00\x00\x01\x01\x00\x00\x00",
+ { type => FCGI_END_REQUEST,
+ request_id => 1,
+ app_status => 1,
+ protocol_status => 1 }
+ ],
+ [
+ undef,
+ { type => FCGI_STDIN,
+ request_id => 1,
+ content => '' }
+ ],
+ [
+ "",
+ { type => FCGI_PARAMS,
+ request_id => 1,
+ content => '' }
+ ],
+ [
+ "\x01\x01A1\x01\x01B2",
+ { type => FCGI_GET_VALUES,
+ request_id => FCGI_NULL_REQUEST_ID,
+ values => { A => 1, B => 2 } }
+ ],
+ [
+ undef,
+ { type => FCGI_GET_VALUES_RESULT,
+ request_id => FCGI_NULL_REQUEST_ID,
+ values => {} }
+ ]
+);
+
+foreach my $test (@ok) {
+ my $exp = $test->[1];
+ my $got = parse_record_body($exp->{type}, $exp->{request_id}, $test->[0]);
+ is_deeply($got, $exp, "parse_record_body()");
+}
+
+my @malformed = (
+ # type, request_id
+ [ FCGI_BEGIN_REQUEST, 0 ],
+ [ FCGI_END_REQUEST, 0 ],
+ [ FCGI_PARAMS, 0 ],
+ [ FCGI_STDIN, 0 ],
+ [ FCGI_STDOUT, 0 ],
+ [ FCGI_STDERR, 0 ],
+ [ FCGI_DATA, 0 ],
+ [ FCGI_GET_VALUES, 1 ],
+ [ FCGI_GET_VALUES_RESULT, 1 ],
+ [ FCGI_UNKNOWN_TYPE, 1 ]
+);
+
+foreach my $test (@malformed) {
+ my ($type, $request_id) = @$test;
+ throws_ok { parse_record_body($type, $request_id, '') } qr/^FastCGI: Malformed/;
+}
+
+{
+ my $content = "\x00" x (FCGI_MAX_CONTENT_LEN + 1);
+ foreach my $type (0..12) {
+ throws_ok { parse_record_body($type, 0, $content) } qr/^Invalid Argument: 'content' cannot exceed/;
+ }
+}
+
+# parse_record_body(type, request_id, content)
+for (0, 4) {
+ throws_ok { parse_record_body((1) x $_) } qr/^Usage: /;
+}
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t
new file mode 100644
index 00000000..92d9a64c
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t
@@ -0,0 +1,79 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 38;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[ build_params
+ check_params
+ parse_params ]);
+}
+
+sub TRUE () { !!1 }
+sub FALSE () { !!0 }
+
+my @tests = (
+ # octets params
+ [ "", { } ],
+ [ "\x00\x00", { '' => '' }, ],
+ [ "\x01\x01\x31\x31", { 1 => 1 }, ],
+ [ "\x01\x01\x41\x42\x01\x01\x43\x44\x01\x01\x45\x46", { A => 'B', C => 'D', E => 'F' } ],
+);
+
+foreach my $test (@tests) {
+ my ($expected, $params) = @$test;
+ my $got = join '', map {
+ build_params({ $_ => $params->{$_} })
+ } sort keys %$params;
+ is_hexstr($got, $expected, 'build_params()');
+}
+
+is_hexstr("\x03\x00foo", build_params({foo => undef}), 'build_params({foo => undef})');
+is_hexstr("\x7F\x00" . "x" x 127, build_params({ "x" x 127 => '' }));
+is_hexstr("\x00\x7F" . "x" x 127, build_params({ '' => "x" x 127 }));
+is_hexstr("\x80\x00\x00\x80\x00" . "x" x 128, build_params({ "x" x 128 => '' }));
+is_hexstr("\x00\x80\x00\x00\x80" . "x" x 128, build_params({ '' => "x" x 128 }));
+
+foreach my $test (@tests) {
+ my $expected = $test->[1];
+ my $got = parse_params($test->[0]);
+ is_deeply($got, $expected, 'parse_params()');
+}
+
+foreach my $test (@tests) {
+ my $octets = $test->[0];
+ is(check_params($octets), TRUE, 'check_params(octets) eq TRUE');
+}
+
+my @insufficient = (
+ "\x00",
+ "\x01",
+ "\x00\x01",
+ "\x01\x00",
+ "\x00\xFF",
+ "\x01\xFF\x00",
+ "\x00\x80\x00\x00\x80",
+ "\x80\x00\x00\x80\x00",
+);
+
+foreach my $test (@insufficient) {
+ throws_ok { parse_params($test) } qr/^FastCGI: Insufficient .* FCGI_NameValuePair/;
+}
+
+foreach my $test (@insufficient) {
+ is(check_params($test), FALSE, 'check_params(octets) eq FALSE');
+}
+
+is(check_params(undef), FALSE, 'check_params(undef) eq FALSE');
+
+throws_ok { check_params() } qr/^Usage: /;
+throws_ok { build_params() } qr/^Usage: /;
+throws_ok { parse_params() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t
new file mode 100644
index 00000000..5836a05b
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t
@@ -0,0 +1,105 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 55;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Constant', qw[ :type ] );
+ use_ok('Net::FastCGI::Protocol', qw[ is_discrete_type
+ is_known_type
+ is_management_type
+ is_stream_type ] );
+}
+
+sub TRUE () { !!1 }
+sub FALSE () { !!0 }
+
+{
+ my @known = (
+ FCGI_BEGIN_REQUEST,
+ FCGI_ABORT_REQUEST,
+ FCGI_END_REQUEST,
+ FCGI_PARAMS,
+ FCGI_STDIN,
+ FCGI_STDOUT,
+ FCGI_STDERR,
+ FCGI_DATA,
+ FCGI_GET_VALUES,
+ FCGI_GET_VALUES_RESULT,
+ FCGI_UNKNOWN_TYPE,
+ FCGI_MAXTYPE,
+ );
+
+ foreach my $type (@known) {
+ is( is_known_type($type), TRUE, qq/is_known_type($type) = true/ );
+ }
+}
+
+{
+ my @discrete = (
+ FCGI_BEGIN_REQUEST,
+ FCGI_ABORT_REQUEST,
+ FCGI_END_REQUEST,
+ FCGI_GET_VALUES,
+ FCGI_GET_VALUES_RESULT,
+ FCGI_UNKNOWN_TYPE,
+ );
+
+ foreach my $type ( @discrete ) {
+ is( is_stream_type($type), FALSE, qq/is_stream_type($type) = false/ );
+ is( is_discrete_type($type), TRUE, qq/is_discrete_type($type) = true/ );
+ }
+}
+
+{
+ my @management = (
+ FCGI_GET_VALUES,
+ FCGI_GET_VALUES_RESULT,
+ FCGI_UNKNOWN_TYPE,
+ );
+
+ foreach my $type (@management) {
+ is( is_management_type($type), TRUE, qq/is_management_type($type) = true/ );
+ }
+}
+
+{
+ my @stream = (
+ FCGI_PARAMS,
+ FCGI_STDIN,
+ FCGI_STDOUT,
+ FCGI_STDERR,
+ FCGI_DATA,
+ );
+
+ foreach my $type (@stream) {
+ is( is_stream_type($type), TRUE, qq/is_stream_type($type) = true/ );
+ is( is_discrete_type($type), FALSE, qq/is_discrete_type($type) = false/ );
+ }
+}
+
+{
+ my @subnames = qw(
+ is_known_type
+ is_discrete_type
+ is_management_type
+ is_stream_type
+ );
+
+ foreach my $name (@subnames) {
+ my $sub = __PACKAGE__->can($name);
+ is($sub->($_), FALSE, qq/$name($_) = false/) for (-10, 0, 12);
+ }
+}
+
+throws_ok { is_known_type() } qr/^Usage: /;
+throws_ok { is_discrete_type() } qr/^Usage: /;
+throws_ok { is_management_type() } qr/^Usage: /;
+throws_ok { is_stream_type() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t
new file mode 100644
index 00000000..86af502d
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t
@@ -0,0 +1,80 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 29;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Constant', qw[ :type :role :protocol_status ] );
+ use_ok('Net::FastCGI::Protocol', qw[ get_type_name
+ get_role_name
+ get_protocol_status_name ] );
+}
+
+{
+ my @tests = (
+ [ FCGI_BEGIN_REQUEST, 'FCGI_BEGIN_REQUEST' ],
+ [ FCGI_ABORT_REQUEST, 'FCGI_ABORT_REQUEST' ],
+ [ FCGI_END_REQUEST, 'FCGI_END_REQUEST' ],
+ [ FCGI_PARAMS, 'FCGI_PARAMS' ],
+ [ FCGI_STDIN, 'FCGI_STDIN' ],
+ [ FCGI_STDOUT, 'FCGI_STDOUT' ],
+ [ FCGI_STDERR, 'FCGI_STDERR' ],
+ [ FCGI_DATA, 'FCGI_DATA' ],
+ [ FCGI_GET_VALUES, 'FCGI_GET_VALUES' ],
+ [ FCGI_GET_VALUES_RESULT, 'FCGI_GET_VALUES_RESULT' ],
+ [ FCGI_UNKNOWN_TYPE, 'FCGI_UNKNOWN_TYPE' ],
+ );
+
+ foreach my $test ( @tests ) {
+ my ( $type, $name ) = @$test;
+ is( get_type_name($type), $name, qq/get_type_name($type) = $name/ );
+ }
+
+ foreach my $type ( 0, 0xFF ) {
+ is(get_type_name($type), sprintf('0x%.2X', $type));
+ }
+}
+
+{
+ my @tests = (
+ [ FCGI_RESPONDER, 'FCGI_RESPONDER' ],
+ [ FCGI_AUTHORIZER, 'FCGI_AUTHORIZER' ],
+ [ FCGI_FILTER, 'FCGI_FILTER' ],
+ );
+
+ foreach my $test ( @tests ) {
+ my ( $role, $name ) = @$test;
+ is( get_role_name($role), $name, qq/get_role_name($role) = $name/ );
+ }
+
+ foreach my $role ( 0, 0xFF, 0xFFFF ) {
+ is(get_role_name($role), sprintf('0x%.4X', $role));
+ }
+}
+
+{
+ my @tests = (
+ [ FCGI_REQUEST_COMPLETE, 'FCGI_REQUEST_COMPLETE' ],
+ [ FCGI_CANT_MPX_CONN, 'FCGI_CANT_MPX_CONN' ],
+ [ FCGI_OVERLOADED, 'FCGI_OVERLOADED' ],
+ [ FCGI_UNKNOWN_ROLE, 'FCGI_UNKNOWN_ROLE' ],
+ );
+
+ foreach my $test ( @tests ) {
+ my ( $status, $name ) = @$test;
+ is( get_protocol_status_name($status), $name, qq/get_protocol_status_name($status) = $name/ );
+ }
+
+ is(get_protocol_status_name(0xFF), '0xFF');
+}
+
+throws_ok { get_type_name() } qr/^Usage: /;
+throws_ok { get_role_name() } qr/^Usage: /;
+throws_ok { get_protocol_status_name() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t
new file mode 100644
index 00000000..0e0bb5de
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t
@@ -0,0 +1,51 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 9;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Protocol', qw[build_record dump_record]);
+}
+
+{
+ my $record = build_record(0, 0, "\x00\x01\x02\x03\x04\x05\x06\x07");
+ my $dump = dump_record($record);
+ like $dump, qr/\A \{0x00, \s 0, \s "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07"\}/x;
+}
+
+{
+ my $record = build_record(0, 0, "\x00\x01\x02\x03\x04\x05\x06\x07");
+
+ for my $len (0, 8) {
+ my $dump = dump_record(substr($record, 0, $len));
+ like $dump, qr/\A \{ Malformed \s FCGI_Record }/x, "Insufficient octets";
+ }
+}
+
+{
+ for my $header ("\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\xFF\x00\x00\x00\x00\x00\x00\x00") {
+ my $dump = dump_record($header);
+ like $dump, qr/\A \{ Malformed \s FCGI_Record }/x, "Protocol version mismatch";
+ }
+}
+
+# dump_record(type, request_id [, content]) deprecated
+{
+ my $dump = dump_record(0, 0);
+ like $dump, qr/\A \{0x00, \s 0, \s ""\}/x;
+}
+{
+ my $dump = dump_record(0, 0, "\x00\x01\x02\x03\x04\x05\x06\x07");
+ like $dump, qr/\A \{0x00, \s 0, \s "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07"\}/x;
+}
+
+# dump_record(octets)
+throws_ok { dump_record() } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t
new file mode 100644
index 00000000..af00d7a3
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t
@@ -0,0 +1,150 @@
+#!perl
+
+use strict;
+use warnings;
+
+use lib 't/lib', 'lib';
+use myconfig;
+
+use Test::More tests => 64;
+use Test::HexString;
+use Test::Exception;
+
+BEGIN {
+ use_ok('Net::FastCGI::Constant', qw[:all]);
+ use_ok('Net::FastCGI::Protocol', qw[:all]);
+}
+
+my @KNOWN_TYPES = (
+ FCGI_BEGIN_REQUEST,
+ FCGI_ABORT_REQUEST,
+ FCGI_END_REQUEST,
+ FCGI_PARAMS,
+ FCGI_STDIN,
+ FCGI_STDOUT,
+ FCGI_STDERR,
+ FCGI_DATA,
+ FCGI_GET_VALUES,
+ FCGI_GET_VALUES_RESULT,
+ FCGI_UNKNOWN_TYPE,
+);
+
+foreach my $type (@KNOWN_TYPES) {
+ like dump_record_body($type, 0), qr/\A\{ $FCGI_TYPE_NAME[$type]\, \s+ 0/x;
+}
+
+foreach my $type (FCGI_PARAMS, FCGI_GET_VALUES, FCGI_GET_VALUES_RESULT) {
+ my $name = $FCGI_TYPE_NAME[$type];
+ {
+ my $dump = dump_record_body($type, 1, '');
+ like $dump, qr/\A \{ $name\, \s+ 1\, \s ""/x;
+ }
+ {
+ my $dump = dump_record_body($type, 1, build_params({ '' => '' }));
+ like $dump, qr/\A \{ $name\, \s+ 1\, \s "\\000\\000"/x;
+ }
+ {
+ my $dump = dump_record_body($type, 1, build_params({ 'Foo' => '' }));
+ like $dump, qr/\A \{ $name\, \s+ 1\, \s "\\003\\000Foo"/x;
+ }
+ {
+ my $dump = dump_record_body($type, 1, build_params({ "Foo\r\n" => "\x01\x02" }));
+ like $dump, qr/\A \{ $name\, \s+ 1\, \s "\\005\\002Foo\\r\\n\\x01\\x02/x;
+ }
+ {
+ my $dump = dump_record_body($type, 1, build_params({ 'x' => 'y' x 128 }));
+ like $dump, qr/\A \{ $name\, \s+ 1\, \s "\\001\\200\\000\\000\\200 x y+/x;
+ }
+ {
+ my $dump = dump_record_body($type, 1, "\001\001");
+ like $dump, qr/\A \{ $name\, \s+ 1\, \s Malformed \s FCGI_NameValuePair/x;
+ }
+}
+
+# Streams
+{
+ my @tests = (
+ [ FCGI_STDIN, 1, "Foo\r\n\t",
+ qr/\A \{ FCGI_STDIN\, \s+ 1\, \s \"Foo\\r\\n\\t/x ],
+ [ FCGI_STDOUT, 1, "\x00\x01\x02\x03\x04\x05\x06\x07",
+ qr/\A \{ FCGI_STDOUT\, \s+ 1\, \s \"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07/x ],
+ [ FCGI_STDERR, 1, "Foo \x01\x02 Bar\n",
+ qr/\A \{ FCGI_STDERR\, \s+ 1\, \s \"Foo\x20\\x01\\x02\x20Bar\\n/x ],
+ [ FCGI_DATA, 1, 'x' x 80,
+ qr/\A \{ FCGI_DATA\, \s+ 1\, \s \" x+ \s \.\.\./x ],
+ );
+
+ foreach my $test (@tests) {
+ my ($type, $request_id, $content, $expected) = @$test;
+ my $dump = dump_record_body($type, $request_id, $content);
+ like $dump, $expected;
+ }
+}
+
+# FCGI_BEGIN_REQUEST
+{
+ my @tests = (
+ [ build_begin_request_body(FCGI_RESPONDER, FCGI_KEEP_CONN),
+ qr/\A \{ FCGI_BEGIN_REQUEST\, \s+ 1\, \s \{ FCGI_RESPONDER\, \s+ FCGI_KEEP_CONN\}/x ],
+ [ build_begin_request_body(FCGI_FILTER, FCGI_KEEP_CONN | 0x10),
+ qr/\A \{ FCGI_BEGIN_REQUEST\, \s+ 1\, \s \{ FCGI_FILTER\, \s+ FCGI_KEEP_CONN|0x10\}/x ],
+ [ build_begin_request_body(FCGI_AUTHORIZER, 0),
+ qr/\A \{ FCGI_BEGIN_REQUEST\, \s+ 1\, \s \{ FCGI_AUTHORIZER\, \s+ 0\}/x ],
+ [ build_begin_request_body(0, 0x80),
+ qr/\A \{ FCGI_BEGIN_REQUEST\, \s+ 1\, \s \{ 0x0000\, \s+ 0x80\}/x ],
+ map([ $_,
+ qr/\A \{ FCGI_BEGIN_REQUEST\, \s+ 1\, \s \{ Malformed \s FCGI_BeginRequestBody/x ],
+ ('', "\x00" x 10)),
+ );
+
+ foreach my $test (@tests) {
+ my ($content, $expected) = @$test;
+ my $dump = dump_record_body(FCGI_BEGIN_REQUEST, 1, $content);
+ like $dump, $expected;
+ }
+}
+
+# FCGI_END_REQUEST
+{
+ my @tests = (
+ [ build_end_request_body(10, 0x80),
+ qr/\A \{ FCGI_END_REQUEST\, \s+ 1\, \s \{ 10\, \s+ 0x80\}/x ],
+ map([ $_,
+ qr/\A \{ FCGI_END_REQUEST\, \s+ 1\, \s \{ Malformed \s FCGI_EndRequestBody/x ],
+ ('', "\x00" x 10)),
+ map([ build_end_request_body(0, $_),
+ qr/\A \{ FCGI_END_REQUEST\, \s+ 1\, \s \{ 0\, \s+ $FCGI_PROTOCOL_STATUS_NAME[$_]\}/x ],
+ (0..3)),
+ );
+
+ foreach my $test (@tests) {
+ my ($content, $expected) = @$test;
+ my $dump = dump_record_body(FCGI_END_REQUEST, 1, $content);
+ like $dump, $expected;
+ }
+}
+
+# FCGI_UNKNOWN_TYPE
+{
+ my @tests = (
+ [ build_unknown_type_body(0),
+ qr/\A \{ FCGI_UNKNOWN_TYPE\, \s+ 0\, \s \{ 0/x ],
+ map([ build_unknown_type_body($_),
+ qr/\A \{ FCGI_UNKNOWN_TYPE\, \s+ 0\, \s \{ $FCGI_TYPE_NAME[$_]/x ],
+ @KNOWN_TYPES),
+ map([ $_,
+ qr/\A \{ FCGI_UNKNOWN_TYPE\, \s+ 0\, \s \{ Malformed \s FCGI_UnknownTypeBody/x ],
+ ('', "\x00" x 10)),
+ );
+
+ foreach my $test (@tests) {
+ my ($content, $expected) = @$test;
+ my $dump = dump_record_body(FCGI_UNKNOWN_TYPE, 0, $content);
+ like $dump, $expected;
+ }
+}
+
+
+throws_ok { dump_record_body() } qr/^Usage: /;
+throws_ok { dump_record_body(0, 0, undef, 0) } qr/^Usage: /;
+
diff --git a/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/lib/myconfig.pm b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/lib/myconfig.pm
new file mode 100644
index 00000000..1d4f6348
--- /dev/null
+++ b/web/server/h2o/libh2o/misc/p5-net-fastcgi/t/lib/myconfig.pm
@@ -0,0 +1,9 @@
+package myconfig;
+
+use strict;
+
+BEGIN {
+ $ENV{NET_FASTCGI_PP} = 0 + !(-e "XS.xs" || -e "../XS.xs");
+}
+
+1;