From 77e50caaf2ef81cd91075cf836fed0e75718ffb4 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 23:12:02 +0200 Subject: Adding debian version 1.8.3-2. Signed-off-by: Daniel Baumann --- debian/vendor-h2o/misc/build_libFuzzer.sh | 8 + debian/vendor-h2o/misc/clang-format-all.sh | 4 + debian/vendor-h2o/misc/dump-github-repository.pl | 41 + debian/vendor-h2o/misc/embed_mruby_code.pl | 54 + debian/vendor-h2o/misc/fastcgi-cgi.pl | 256 ++++ debian/vendor-h2o/misc/install-perl-module.pl | 27 + debian/vendor-h2o/misc/libressl-2.4.5.tar.gz | Bin 0 -> 3016462 bytes debian/vendor-h2o/misc/libressl.mk | 12 + debian/vendor-h2o/misc/makedoc.pl | 69 ++ debian/vendor-h2o/misc/mk-ca-bundle.pl | 499 ++++++++ debian/vendor-h2o/misc/mkhufftbl.py | 553 +++++++++ debian/vendor-h2o/misc/mruby-mtest/.travis.yml | 2 + debian/vendor-h2o/misc/mruby-mtest/README.md | 63 + .../vendor-h2o/misc/mruby-mtest/example/sample.rb | 46 + debian/vendor-h2o/misc/mruby-mtest/mrbgem.rake | 8 + .../misc/mruby-mtest/mrblib/mtest_unit.rb | 698 +++++++++++ debian/vendor-h2o/misc/mruby-mtest/run_test.rb | 26 + .../misc/mruby-mtest/test/mtest_unit_test.rb | 74 ++ debian/vendor-h2o/misc/mruby_config.rb | 29 + debian/vendor-h2o/misc/p5-net-fastcgi/Changes | 102 ++ .../vendor-h2o/misc/p5-net-fastcgi/MANIFEST.SKIP | 25 + debian/vendor-h2o/misc/p5-net-fastcgi/Makefile.PL | 19 + debian/vendor-h2o/misc/p5-net-fastcgi/README | 113 ++ .../vendor-h2o/misc/p5-net-fastcgi/eg/runfcgi.pl | 226 ++++ debian/vendor-h2o/misc/p5-net-fastcgi/eg/server.pl | 164 +++ .../misc/p5-net-fastcgi/lib/Net/FastCGI.pm | 12 + .../misc/p5-net-fastcgi/lib/Net/FastCGI.pod | 170 +++ .../p5-net-fastcgi/lib/Net/FastCGI/Constant.pm | 179 +++ .../p5-net-fastcgi/lib/Net/FastCGI/Constant.pod | 264 +++++ .../misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pm | 227 ++++ .../misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pod | 391 +++++++ .../p5-net-fastcgi/lib/Net/FastCGI/Protocol.pm | 203 ++++ .../p5-net-fastcgi/lib/Net/FastCGI/Protocol.pod | 1227 ++++++++++++++++++++ .../p5-net-fastcgi/lib/Net/FastCGI/Protocol/PP.pm | 429 +++++++ debian/vendor-h2o/misc/p5-net-fastcgi/t/000_load.t | 29 + .../p5-net-fastcgi/t/020_protocol/001_header.t | 51 + .../t/020_protocol/005_record_length.t | 44 + .../t/020_protocol/010_build_record.t | 44 + .../t/020_protocol/015_build_stream.t | 82 ++ .../t/020_protocol/020_begin_request_body.t | 41 + .../t/020_protocol/025_begin_request_record.t | 30 + .../t/020_protocol/027_begin_request.t | 97 ++ .../t/020_protocol/030_end_request_body.t | 42 + .../t/020_protocol/035_end_request_record.t | 30 + .../t/020_protocol/037_end_request.t | 87 ++ .../t/020_protocol/040_unknown_type_body.t | 42 + .../t/020_protocol/045_unknown_type_record.t | 30 + .../t/020_protocol/050_parse_record.t | 180 +++ .../t/020_protocol/055_parse_record_body.t | 98 ++ .../p5-net-fastcgi/t/020_protocol/060_params.t | 79 ++ .../t/020_protocol/065_record_type.t | 105 ++ .../misc/p5-net-fastcgi/t/020_protocol/070_names.t | 80 ++ .../t/020_protocol/080_dump_record.t | 51 + .../t/020_protocol/085_dump_record_body.t | 150 +++ .../misc/p5-net-fastcgi/t/lib/myconfig.pm | 9 + debian/vendor-h2o/misc/p5-net-fastcgi/xt/000_pod.t | 17 + .../misc/p5-net-fastcgi/xt/010_pod_coverage.t | 29 + debian/vendor-h2o/misc/picotemplate-conf.pl | 21 + debian/vendor-h2o/misc/regen.mk | 45 + debian/vendor-h2o/misc/test-ca/README.md | 7 + debian/vendor-h2o/misc/test-ca/ca.crt | 17 + debian/vendor-h2o/misc/test-ca/ca.key | 27 + debian/vendor-h2o/misc/test-ca/demoCA/index.txt | 2 + .../vendor-h2o/misc/test-ca/demoCA/index.txt.attr | 1 + .../misc/test-ca/demoCA/newcerts/.gitkeep | 0 debian/vendor-h2o/misc/test-ca/demoCA/serial | 1 + debian/vendor-h2o/misc/tokens.pl | 234 ++++ 67 files changed, 8022 insertions(+) create mode 100755 debian/vendor-h2o/misc/build_libFuzzer.sh create mode 100755 debian/vendor-h2o/misc/clang-format-all.sh create mode 100755 debian/vendor-h2o/misc/dump-github-repository.pl create mode 100755 debian/vendor-h2o/misc/embed_mruby_code.pl create mode 100755 debian/vendor-h2o/misc/fastcgi-cgi.pl create mode 100755 debian/vendor-h2o/misc/install-perl-module.pl create mode 100644 debian/vendor-h2o/misc/libressl-2.4.5.tar.gz create mode 100644 debian/vendor-h2o/misc/libressl.mk create mode 100755 debian/vendor-h2o/misc/makedoc.pl create mode 100755 debian/vendor-h2o/misc/mk-ca-bundle.pl create mode 100644 debian/vendor-h2o/misc/mkhufftbl.py create mode 100644 debian/vendor-h2o/misc/mruby-mtest/.travis.yml create mode 100644 debian/vendor-h2o/misc/mruby-mtest/README.md create mode 100644 debian/vendor-h2o/misc/mruby-mtest/example/sample.rb create mode 100644 debian/vendor-h2o/misc/mruby-mtest/mrbgem.rake create mode 100644 debian/vendor-h2o/misc/mruby-mtest/mrblib/mtest_unit.rb create mode 100644 debian/vendor-h2o/misc/mruby-mtest/run_test.rb create mode 100644 debian/vendor-h2o/misc/mruby-mtest/test/mtest_unit_test.rb create mode 100644 debian/vendor-h2o/misc/mruby_config.rb create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/Changes create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/MANIFEST.SKIP create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/Makefile.PL create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/README create mode 100755 debian/vendor-h2o/misc/p5-net-fastcgi/eg/runfcgi.pl create mode 100755 debian/vendor-h2o/misc/p5-net-fastcgi/eg/server.pl create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pm create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pod create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pm create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pod create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pm create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pod create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pm create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pod create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol/PP.pm create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/000_load.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/t/lib/myconfig.pm create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/xt/000_pod.t create mode 100644 debian/vendor-h2o/misc/p5-net-fastcgi/xt/010_pod_coverage.t create mode 100644 debian/vendor-h2o/misc/picotemplate-conf.pl create mode 100755 debian/vendor-h2o/misc/regen.mk create mode 100644 debian/vendor-h2o/misc/test-ca/README.md create mode 100644 debian/vendor-h2o/misc/test-ca/ca.crt create mode 100644 debian/vendor-h2o/misc/test-ca/ca.key create mode 100644 debian/vendor-h2o/misc/test-ca/demoCA/index.txt create mode 100644 debian/vendor-h2o/misc/test-ca/demoCA/index.txt.attr create mode 100644 debian/vendor-h2o/misc/test-ca/demoCA/newcerts/.gitkeep create mode 100644 debian/vendor-h2o/misc/test-ca/demoCA/serial create mode 100755 debian/vendor-h2o/misc/tokens.pl (limited to 'debian/vendor-h2o/misc') diff --git a/debian/vendor-h2o/misc/build_libFuzzer.sh b/debian/vendor-h2o/misc/build_libFuzzer.sh new file mode 100755 index 0000000..67a64c9 --- /dev/null +++ b/debian/vendor-h2o/misc/build_libFuzzer.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +[ -e libFuzzer.a ] && exit 0 +[ -d Fuzzer ] || git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer +cd Fuzzer +git checkout 29d1659edabe4ba2396f9697915bb7a0880cbd2f +cd .. +Fuzzer/build.sh diff --git a/debian/vendor-h2o/misc/clang-format-all.sh b/debian/vendor-h2o/misc/clang-format-all.sh new file mode 100755 index 0000000..aaf606c --- /dev/null +++ b/debian/vendor-h2o/misc/clang-format-all.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +exec clang-format -i $(git ls-files | egrep -v '(^deps/|/_|^handler/mimemap/defaults\.c\.h)' | egrep '\.(c|h)$') +exit $? diff --git a/debian/vendor-h2o/misc/dump-github-repository.pl b/debian/vendor-h2o/misc/dump-github-repository.pl new file mode 100755 index 0000000..ab81157 --- /dev/null +++ b/debian/vendor-h2o/misc/dump-github-repository.pl @@ -0,0 +1,41 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use Errno (); +use File::Basename qw(basename); + +die "Usage: $0 []\n" + if @ARGV < 3; + +my ($repo, $commit, $dest, $path) = @ARGV; +my $strip_components = 1; +my ($rm_path, $tar_path); + +if (defined $path) { + $path =~ s|/*$||; + $strip_components += scalar(split "/", $path) - 1; + $rm_path = "$dest/" . basename $path; + $tar_path = "*/$path"; +} else { + $path = ""; + $rm_path = "$dest"; + $tar_path = ""; +} + +run("rm -rf $rm_path"); + +mkdir("$dest") + or $! == Errno::EEXIST or die "failed to (re)create directory:$dest:$!"; +run("curl --silent --show-error --location $repo/archive/$commit.tar.gz | (cd $dest && tar x --strip-components $strip_components -zf - $tar_path)") == 0 + or die "failed to extract $repo/archive/$commit.tar.gz to $dest"; +run("git add -f `find $rm_path -type f`") == 0 + or die "failed to add files under $dest"; +run("git commit --allow-empty -m 'extract $repo @ $commit @{[defined $path ? qq{($path)} : '']} at $dest' $dest") == 0 + or die "failed to commit"; + +sub run { + my $cmd = shift; + print "$cmd\n"; + system($cmd); +} diff --git a/debian/vendor-h2o/misc/embed_mruby_code.pl b/debian/vendor-h2o/misc/embed_mruby_code.pl new file mode 100755 index 0000000..8797e9c --- /dev/null +++ b/debian/vendor-h2o/misc/embed_mruby_code.pl @@ -0,0 +1,54 @@ +#!/usr/bin/env perl + +# Copyright (c) 2016 DeNA Co., Ltd. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +use strict; +use warnings; +use Path::Tiny; + +my @mruby_files = @ARGV; + +my $out = << 'EOF'; +/* + * DO NOT EDIT! generated by embed_mruby_code.pl + * Please refer to the respective source files for copyright information. + */ + +EOF + +for my $path (map { path($_) } grep { $_ =~ /\.rb$/ } @mruby_files) { + my @lines = $path->lines({ chomp => 1 }); + + my $in_license = 1; + @lines = grep { $in_license = 0 if $_ !~ /^#/; ! $in_license } @lines; + @lines = grep { $_ =~ /\S/ } @lines; + @lines = map { + s/\x5c/\\\\/g; + s/\x22/\\"/g; + $_; + } @lines; + + $out .= "/* $path */\n"; + $out .= "#define H2O_MRUBY_CODE_@{[ uc($path->basename('.rb')) ]} \\\n"; + $out .= join("\n", map { '"' . $_ . '\\n" \\' } @lines); + $out .= "\n\n"; +} +print $out; diff --git a/debian/vendor-h2o/misc/fastcgi-cgi.pl b/debian/vendor-h2o/misc/fastcgi-cgi.pl new file mode 100755 index 0000000..98ee332 --- /dev/null +++ b/debian/vendor-h2o/misc/fastcgi-cgi.pl @@ -0,0 +1,256 @@ +#! /usr/bin/perl + +use strict; +use warnings; +use File::Basename qw(dirname); +use File::Temp qw(tempfile); +use Getopt::Long; +use IO::Socket::UNIX; +use Net::FastCGI; +use Net::FastCGI::Constant qw(:common :type :flag :role :protocol_status); +use Net::FastCGI::IO qw(:all); +use Net::FastCGI::Protocol qw(:all); +use POSIX qw(:sys_wait_h getcwd); +use Socket qw(SOMAXCONN SOCK_STREAM); + +my $master_pid = $$; +my %child_procs; + +$SIG{CHLD} = sub {}; +$SIG{HUP} = sub {}; +$SIG{TERM} = sub { + if ($$ == $master_pid) { + kill "TERM", $_ + for sort keys %child_procs; + } + exit 0; +}; + +my $base_dir = getcwd; +chdir "/" + or die "failed to chdir to /:$!"; +main(); +my $pass_authz; + +sub main { + my $sockfn; + my $max_workers = "inf" + 1; + + GetOptions( + "listen=s" => \$sockfn, + "max-workers=i" => \$max_workers, + "pass-authz" => \$pass_authz, + "help" => sub { + print_help(); + exit 0; + }, + ) or exit 1; + + my $listen_sock; + if (defined $sockfn) { + unlink $sockfn; + $listen_sock = IO::Socket::UNIX->new( + Listen => SOMAXCONN, + Local => $sockfn, + Type => SOCK_STREAM, + ) or die "failed to create unix socket at $sockfn:$!"; + } else { + die "stdin is no a socket" + unless -S STDIN; + $listen_sock = IO::Socket::UNIX->new; + $listen_sock->fdopen(fileno(STDIN), "w") + or die "failed to open unix socket:$!"; + } + + while (1) { + my $wait_opt = 0; + if (keys %child_procs < $max_workers) { + if (my $sock = $listen_sock->accept) { + my $pid = fork; + die "fork failed:$!" + unless defined $pid; + if ($pid == 0) { + close $listen_sock; + handle_connection($sock); + exit 0; + } + $sock->close; + $child_procs{$pid} = 1; + } + $wait_opt = WNOHANG; + } else { + $wait_opt = 0; + } + my $kid = waitpid(-1, $wait_opt); + if ($kid > 0) { + delete $child_procs{$kid}; + } + } +} + +sub handle_connection { + my $sock = shift; + my ($type, $req_id, $content); + my $cur_req_id; + my $params = ""; + my $input_fh; + + # wait for FCGI_BEGIN_REQUEST + ($type, $req_id, $content) = fetch_record($sock); + die "expected FCGI_BEGIN_REQUEST, but got $type" + unless $type == FCGI_BEGIN_REQUEST; + my ($role, $flags) = parse_begin_request_body($content); + die "unexpected role:$role" + unless $role == FCGI_RESPONDER; + $cur_req_id = $req_id; + + # accumulate FCGI_PARAMS + while (1) { + ($type, $req_id, $content) = fetch_record($sock); + last if $type != FCGI_PARAMS; + die "unexpected request id" + if $cur_req_id != $req_id; + $params .= $content; + } + my $env = parse_params($params); + die "SCRIPT_FILENAME not defined" + unless $env->{SCRIPT_FILENAME}; + $env->{SCRIPT_FILENAME} = "$base_dir/$env->{SCRIPT_FILENAME}" + if $env->{SCRIPT_FILENAME} !~ m{^/}; + delete $env->{HTTP_AUTHORIZATION} + unless $pass_authz; + + # accumulate FCGI_STDIN + while (1) { + die "received unexpected record: $type" + if $type != FCGI_STDIN; + die "unexpected request id" + if $cur_req_id != $req_id; + last if length $content == 0; + if (!$input_fh) { + $input_fh = tempfile() + or die "failed to create temporary file:$!"; + } + print $input_fh $content; + ($type, $req_id, $content) = fetch_record($sock); + } + if ($input_fh) { + flush $input_fh; + seek $input_fh, 0, 0 + or die "seek failed:$!"; + } else { + open $input_fh, "<", "/dev/null" + or die "failed to open /dev/null:$!"; + } + + # create pipes for stdout and stderr + pipe(my $stdout_rfh, my $stdout_wfh) + or die "pipe failed:$!"; + pipe(my $stderr_rfh, my $stderr_wfh) + or die "pipe failed:$!"; + + # fork the CGI application + my $pid = fork; + die "fork failed:$!" + unless defined $pid; + if ($pid == 0) { + close $sock; + close $stdout_rfh; + close $stderr_rfh; + open STDERR, ">&", $stderr_wfh + or die "failed to dup STDERR"; + open STDIN, "<&", $input_fh + or die "failed to dup STDIN"; + open STDOUT, ">&", $stdout_wfh + or die "failed to dup STDOUT"; + close $stderr_wfh; + close $input_fh; + close $stdout_wfh; + $ENV{$_} = $env->{$_} + for sort keys %$env; + chdir dirname($env->{SCRIPT_FILENAME}); + exec $env->{SCRIPT_FILENAME}; + exit 111; + } + close $stdout_wfh; + close $stderr_wfh; + + # send response + while ($stdout_rfh || $stderr_rfh) { + my $rin = ''; + vec($rin, fileno $stdout_rfh, 1) = 1 + if $stdout_rfh; + vec($rin, fileno $stderr_rfh, 1) = 1 + if $stderr_rfh; + vec($rin, fileno $sock, 1) = 1; + if (select($rin, undef, undef, undef) <= 0) { + next; + } + if ($stdout_rfh && vec($rin, fileno $stdout_rfh, 1)) { + transfer($sock, FCGI_STDOUT, $cur_req_id, $stdout_rfh) + or undef $stdout_rfh; + } + if ($stderr_rfh && vec($rin, fileno $stderr_rfh, 1)) { + transfer($sock, FCGI_STDERR, $cur_req_id, $stderr_rfh) + or undef $stderr_rfh; + } + if (vec($rin, fileno $sock, 1)) { + # atually means that the client has closed the connection, terminate the CGI process the same way apache does + kill 'TERM', $pid; + $SIG{ALRM} = sub { + kill 'KILL', $pid; + }; + alarm 3; + last; + } + } + + # close (closing without sending FCGI_END_REQUEST indicates to the client that the connection is not persistent) + close $sock; + + # wait for child process to die + while (waitpid($pid, 0) != $pid) { + } +} + +sub fetch_record { + my $sock = shift; + my ($type, $req_id, $content) = read_record($sock) + or die "failed to read FCGI record:$!"; + die "unexpected request id:null" + if $req_id == FCGI_NULL_REQUEST_ID; + ($type, $req_id, $content); +} + +sub transfer { + my ($sock, $type, $req_id, $fh) = @_; + my $buf; + + while (1) { + my $ret = sysread $fh, $buf, 61440; + next if (!defined $ret) && $! == Errno::EINTR; + $buf = "" unless $ret; # send zero-length record to indicate EOS + last; + } + write_record($sock, $type, $req_id, $buf) + or die "failed to write FCGI response:$!"; + return length $buf; +} + +sub print_help { + # do not use Pod::Usage, since we are fatpacking this script + print << "EOT"; +Usage: + $0 [options] + +Options: + --listen=sockfn path to the UNIX socket. If specified, the program will + create a UNIX socket at given path replacing the existing + file (should it exist). If not, file descriptor zero (0) + will be used as the UNIX socket for accepting new + connections. + --max-workers=nnn maximum number of CGI processes (default: unlimited) + --pass-authz if set, preserves HTTP_AUTHORIZATION parameter + +EOT +} diff --git a/debian/vendor-h2o/misc/install-perl-module.pl b/debian/vendor-h2o/misc/install-perl-module.pl new file mode 100755 index 0000000..0e0f9f4 --- /dev/null +++ b/debian/vendor-h2o/misc/install-perl-module.pl @@ -0,0 +1,27 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +sub run_cmd { + my $cmd = shift; + print "$cmd\n"; + system($cmd) == 0 + or die "aborting..., command failed with $?"; +} + +sub install_module { + my $module = shift; + print "checking if $module is installed...\n"; + if (system("perl -M$module -e '' > /dev/null 2>&1") != 0) { + run_cmd("cpanm --sudo --notest $module"); + } +} + +print "checking if cpanm is installed...\n"; +if (system("which cpanm > /dev/null 2>&1") != 0) { + run_cmd("curl -L http://cpanmin.us | perl - --sudo --notest App::cpanminus"); +} + +install_module($_) + for @ARGV; diff --git a/debian/vendor-h2o/misc/libressl-2.4.5.tar.gz b/debian/vendor-h2o/misc/libressl-2.4.5.tar.gz new file mode 100644 index 0000000..cac6e43 Binary files /dev/null and b/debian/vendor-h2o/misc/libressl-2.4.5.tar.gz differ diff --git a/debian/vendor-h2o/misc/libressl.mk b/debian/vendor-h2o/misc/libressl.mk new file mode 100644 index 0000000..d20df41 --- /dev/null +++ b/debian/vendor-h2o/misc/libressl.mk @@ -0,0 +1,12 @@ +SOURCE_DIR=. +VERSION=2.4.5 +ARCHIVE=$(SOURCE_DIR)/libressl-$(VERSION).tar.gz +DEST=libressl-build +UNAME=$(shell uname -s) + +all: $(DEST)/lib/libssl.a + +$(DEST)/lib/libssl.a: $(ARCHIVE) + if [ ! -e "libressl-$(VERSION)" ] ; then tar xzf "$(ARCHIVE)" ; fi + if [ ! -e "libressl-$(VERSION)/Makefile" ] ; then (P=`pwd`/$(DEST); cd libressl-$(VERSION) && ./configure --prefix="$$P" --libdir="$$P/lib" --disable-shared `test "$(UNAME)" = "Darwin" && echo '--disable-asm'`) ; fi + (cd libressl-$(VERSION) && make && make install) diff --git a/debian/vendor-h2o/misc/makedoc.pl b/debian/vendor-h2o/misc/makedoc.pl new file mode 100755 index 0000000..b025536 --- /dev/null +++ b/debian/vendor-h2o/misc/makedoc.pl @@ -0,0 +1,69 @@ +#! /usr/bin/env perl + +use strict; +use warnings; +no warnings qw(once); + +use File::Basename qw(dirname); +use File::Path qw(mkpath); +use Scalar::Util qw(looks_like_number); +use Text::MicroTemplate qw(build_mt render_mt encoded_string); +use Text::MicroTemplate::File; + +my $mt = Text::MicroTemplate::File->new( + include_path => [ qw(../srcdoc/snippets .) ], +); + +die "Usage: $0 \n" + unless @ARGV == 2; + +my ($src_file, $dst_file) = @ARGV; + +$main::context = { + filename => $dst_file, + code => build_mt( + '
', + ), + example => build_mt(<<'EOT', +
+
Example.
+
+
+EOT + ), + directive => sub { + my %args = @_; + $mt->wrapper_file("directive.mt", \%args); + }, + mruby_method => sub { + my %args = @_; + $mt->wrapper_file("mruby_method.mt", \%args); + }, + notes => [], + note => sub { + my ($index, $html); + if (looks_like_number($_[0])) { + $index = $_[0] < 0 ? scalar(@{$main::context->{notes}}) + $_[0] : $_[0]; + $html = $main::context->{notes}->[$index]; + } else { + $index = scalar @{$main::context->{notes}}; + $html = $_[0]; + push @{$main::context->{notes}}, encoded_string($html); + } + my $alt = $html; + $alt =~ s/<.*?>//g; + return render_mt( + '', + $index + 1, + $alt, + ); + }, +}; +my $output = $mt->render_file($src_file); +mkpath(dirname($dst_file)); + +chmod 0666, $dst_file; +open my $dst_fh, '>:utf8', $dst_file + or die "failed to open file:$dst_file:$!"; +print $dst_fh $output; +close $dst_fh; diff --git a/debian/vendor-h2o/misc/mk-ca-bundle.pl b/debian/vendor-h2o/misc/mk-ca-bundle.pl new file mode 100755 index 0000000..5a1435c --- /dev/null +++ b/debian/vendor-h2o/misc/mk-ca-bundle.pl @@ -0,0 +1,499 @@ +#!/usr/bin/perl -w +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at https://curl.haxx.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# *************************************************************************** +# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. +# It downloads certdata.txt from Mozilla's source tree (see URL below), +# then parses certdata.txt and extracts CA Root Certificates into PEM format. +# These are then processed with the OpenSSL commandline tool to produce the +# final ca-bundle.crt file. +# The script is based on the parse-certs script written by Roland Krikava. +# This Perl script works on almost any platform since its only external +# dependency is the OpenSSL commandline tool for optional text listing. +# Hacked by Guenter Knauf. +# +use Getopt::Std; +use MIME::Base64; +use LWP::UserAgent; +use strict; +use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_l $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); +use List::Util; +use Text::Wrap; +my $MOD_SHA = "Digest::SHA"; +eval "require $MOD_SHA"; +if ($@) { + $MOD_SHA = "Digest::SHA::PurePerl"; + eval "require $MOD_SHA"; +} + +my %urls = ( + 'nss' => + 'http://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt', + 'central' => + 'http://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'aurora' => + 'http://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'beta' => + 'http://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'release' => + 'http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', +); + +$opt_d = 'release'; + +# If the OpenSSL commandline is not in search path you can configure it here! +my $openssl = 'openssl'; + +my $version = '1.25'; + +$opt_w = 76; # default base64 encoded lines length + +# default cert types to include in the output (default is to include CAs which may issue SSL server certs) +my $default_mozilla_trust_purposes = "SERVER_AUTH"; +my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; +$opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; + +my @valid_mozilla_trust_purposes = ( + "DIGITAL_SIGNATURE", + "NON_REPUDIATION", + "KEY_ENCIPHERMENT", + "DATA_ENCIPHERMENT", + "KEY_AGREEMENT", + "KEY_CERT_SIGN", + "CRL_SIGN", + "SERVER_AUTH", + "CLIENT_AUTH", + "CODE_SIGNING", + "EMAIL_PROTECTION", + "IPSEC_END_SYSTEM", + "IPSEC_TUNNEL", + "IPSEC_USER", + "TIME_STAMPING", + "STEP_UP_APPROVED" +); + +my @valid_mozilla_trust_levels = ( + "TRUSTED_DELEGATOR", # CAs + "NOT_TRUSTED", # Don't trust these certs. + "MUST_VERIFY_TRUST", # This explicitly tells us that it ISN'T a CA but is otherwise ok. In other words, this should tell the app to ignore any other sources that claim this is a CA. + "TRUSTED" # This cert is trusted, but only for itself and not for delegates (i.e. it is not a CA). +); + +my $default_signature_algorithms = $opt_s = "MD5"; + +my @valid_signature_algorithms = ( + "MD5", + "SHA1", + "SHA256", + "SHA384", + "SHA512" +); + +$0 =~ s@.*(/|\\)@@; +$Getopt::Std::STANDARD_HELP_VERSION = 1; +getopts('bd:fhilnp:qs:tuvw:'); + +if(!defined($opt_d)) { + # to make plain "-d" use not cause warnings, and actually still work + $opt_d = 'release'; +} + +# Use predefined URL or else custom URL specified on command line. +my $url = ( defined( $urls{$opt_d} ) ) ? $urls{$opt_d} : $opt_d; + +my $curl = `curl -V`; + +if ($opt_i) { + print ("=" x 78 . "\n"); + print "Script Version : $version\n"; + print "Perl Version : $]\n"; + print "Operating System Name : $^O\n"; + print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; + print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; + print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n"; + print "LWP.pm Version : ${LWP::VERSION}\n"; + print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if ($Digest::SHA::VERSION); + print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if ($Digest::SHA::PurePerl::VERSION); + print ("=" x 78 . "\n"); +} + +sub warning_message() { + if ( $opt_d =~ m/^risk$/i ) { # Long Form Warning and Exit + print "Warning: Use of this script may pose some risk:\n"; + print "\n"; + print " 1) Using http is subject to man in the middle attack of certdata content\n"; + print " 2) Default to 'release', but more recent updates may be found in other trees\n"; + print " 3) certdata.txt file format may change, lag time to update this script\n"; + print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; + print " 5) Mozilla apps use additional security checks aren't represented in certdata\n"; + print " 6) Use of this script will make a security engineer grind his teeth and\n"; + print " swear at you. ;)\n"; + exit; + } else { # Short Form Warning + print "Warning: Use of this script may pose some risk, -d risk for more details.\n"; + } +} + +sub HELP_MESSAGE() { + print "Usage:\t${0} [-b] [-d] [-f] [-i] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; + print "\t-b\tbackup an existing version of ca-bundle.crt\n"; + print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; + print "\t\t Valid names are:\n"; + print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; + print "\t-f\tforce rebuild even if certdata.txt is current\n"; + print "\t-i\tprint version info about used modules\n"; + print "\t-l\tprint license info about certdata.txt\n"; + print "\t-n\tno download of certdata.txt (to use existing)\n"; + print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; + print "\t\t Valid purposes are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; + print "\t\t Valid levels are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; + print "\t-q\tbe really quiet (no progress output at all)\n"; + print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); + print "\t\t Valid signature algorithms are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; + print "\t-t\tinclude plain text listing of certificates\n"; + print "\t-u\tunlink (remove) certdata.txt after processing\n"; + print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; + exit; +} + +sub VERSION_MESSAGE() { + print "${0} version ${version} running Perl ${]} on ${^O}\n"; +} + +warning_message() unless ($opt_q || $url =~ m/^(ht|f)tps:/i ); +HELP_MESSAGE() if ($opt_h); + +sub report($@) { + my $output = shift; + + print STDERR $output . "\n" unless $opt_q; +} + +sub is_in_list($@) { + my $target = shift; + + return defined(List::Util::first { $target eq $_ } @_); +} + +# Parses $param_string as a case insensitive comma separated list with optional whitespace +# validates that only allowed parameters are supplied +sub parse_csv_param($$@) { + my $description = shift; + my $param_string = shift; + my @valid_values = @_; + + my @values = map { + s/^\s+//; # strip leading spaces + s/\s+$//; # strip trailing spaces + uc $_ # return the modified string as upper case + } split( ',', $param_string ); + + # Find all values which are not in the list of valid values or "ALL" + my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; + + if ( scalar(@invalid) > 0 ) { + # Tell the user which parameters were invalid and print the standard help message which will exit + print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; + HELP_MESSAGE(); + } + + @values = @valid_values if ( is_in_list("ALL",@values) ); + + return @values; +} + +sub sha1 { + my $result; + if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { + open(FILE, $_[0]) or die "Can't open '$_[0]': $!"; + binmode(FILE); + $result = $MOD_SHA->new(1)->addfile(*FILE)->hexdigest; + close(FILE); + } else { + # Use OpenSSL command if Perl Digest::SHA modules not available + $result = (split(/ |\r|\n/,`$openssl dgst -sha1 $_[0]`))[1]; + } + return $result; +} + + +sub oldsha1 { + my $sha1 = ""; + open(C, "<$_[0]") || return 0; + while() { + chomp; + if($_ =~ /^\#\# SHA1: (.*)/) { + $sha1 = $1; + last; + } + } + close(C); + return $sha1; +} + +if ( $opt_p !~ m/:/ ) { + print "Error: Mozilla trust identifier list must include both purposes and levels\n"; + HELP_MESSAGE(); +} + +(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); +my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); +my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); + +my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); + +sub should_output_cert(%) { + my %trust_purposes_by_level = @_; + + foreach my $level (@included_mozilla_trust_levels) { + # for each level we want to output, see if any of our desired purposes are included + return 1 if ( defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} ) ); + } + + return 0; +} + +my $crt = $ARGV[0] || 'ca-bundle.crt'; +(my $txt = $url) =~ s@(.*/|\?.*)@@g; + +my $stdout = $crt eq '-'; +my $resp; +my $fetched; + +my $oldsha1 = oldsha1($crt); + +report "SHA1 of old file: $oldsha1"; + +report "Downloading '$txt' ..."; + +if($curl && !$opt_n) { + my $https = $url; + $https =~ s/^http:/https:/; + report "Get certdata over HTTPS with curl!"; + my $quiet = $opt_q ? "-s" : ""; + my @out = `curl -w %{response_code} $quiet -O $https`; + if(@out && $out[0] == 200) { + $fetched = 1; + } else { + report "Failed downloading HTTPS with curl, trying HTTP with LWP"; + } +} + +unless ($fetched || ($opt_n and -e $txt)) { + my $ua = new LWP::UserAgent(agent => "$0/$version"); + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if ($resp && $resp->code eq '304') { + report "Not modified"; + exit 0 if -e $crt && !$opt_f; + } else { + $fetched = 1; + } + if( !$resp || $resp->code !~ /^(?:200|304)$/ ) { + report "Unable to download latest data: " + . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); + exit 1 if -e $crt || ! -r $txt; + } +} + +my $filedate = $resp ? $resp->last_modified : (stat($txt))[9]; +my $datesrc = "as of"; +if(!$filedate) { + # mxr.mozilla.org gave us a time, hg.mozilla.org does not! + $filedate = time(); + $datesrc="downloaded on"; +} + +# get the hash from the download file +my $newsha1= sha1($txt); + +if(!$opt_f && $oldsha1 eq $newsha1) { + report "Downloaded file identical to previous run\'s source file. Exiting"; + exit; +} + +report "SHA1 of new file: $newsha1"; + +my $currentdate = scalar gmtime($filedate); + +my $format = $opt_t ? "plain text and " : ""; +if( $stdout ) { + open(CRT, '> -') or die "Couldn't open STDOUT: $!\n"; +} else { + open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n"; +} +print CRT <) { + if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { + print CRT; + print if ($opt_l); + while () { + print CRT; + print if ($opt_l); + last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); + } + } + next if /^#|^\s*$/; + chomp; + if (/^CVS_ID\s+\"(.*)\"/) { + print CRT "# $1\n"; + } + + # this is a match for the start of a certificate + if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + $start_of_cert = 1 + } + if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { + $caname = $1; + } + my %trust_purposes_by_level; + if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { + my $data; + while () { + last if (/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for (@octets) { + $data .= chr(oct); + } + } + # scan forwards until the trust part + while () { + last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/); + chomp; + } + # now scan the trust part to determine how we should trust this cert + while () { + last if (/^#/); + if (/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { + if ( !is_in_list($1,@valid_mozilla_trust_purposes) ) { + report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } elsif ( !is_in_list($2,@valid_mozilla_trust_levels) ) { + report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } else { + push @{$trust_purposes_by_level{$2}}, $1; + } + } + } + + if ( !should_output_cert(%trust_purposes_by_level) ) { + $skipnum ++; + } else { + my $encoded = MIME::Base64::encode_base64($data, ''); + $encoded =~ s/(.{1,${opt_w}})/$1\n/g; + my $pem = "-----BEGIN CERTIFICATE-----\n" + . $encoded + . "-----END CERTIFICATE-----\n"; + print CRT "\n$caname\n"; + + my $maxStringLength = length($caname); + if ($opt_t) { + foreach my $key (keys %trust_purposes_by_level) { + my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); + $maxStringLength = List::Util::max( length($string), $maxStringLength ); + print CRT $string . "\n"; + } + } + print CRT ("=" x $maxStringLength . "\n"); + if (!$opt_t) { + print CRT $pem; + } else { + my $pipe = ""; + foreach my $hash (@included_signature_algorithms) { + $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + $pipe = "|$openssl x509 -text -inform PEM"; + if (!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Couldn't close $crt.~: $!"; + } + open(TMP, $pipe) or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + if (!$stdout) { + open(CRT, ">>$crt.~") or die "Couldn't open $crt.~: $!"; + } + } + report "Parsing: $caname" if ($opt_v); + $certnum ++; + $start_of_cert = 0; + } + } +} +close(TXT) or die "Couldn't close $txt: $!\n"; +close(CRT) or die "Couldn't close $crt.~: $!\n"; +unless( $stdout ) { + if ($opt_b && -e $crt) { + my $bk = 1; + while (-e "$crt.~${bk}~") { + $bk++; + } + rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; + } elsif( -e $crt ) { + unlink( $crt ) or die "Failed to remove $crt: $!\n"; + } + rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; +} +unlink $txt if ($opt_u); +report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/debian/vendor-h2o/misc/mkhufftbl.py b/debian/vendor-h2o/misc/mkhufftbl.py new file mode 100644 index 0000000..b514720 --- /dev/null +++ b/debian/vendor-h2o/misc/mkhufftbl.py @@ -0,0 +1,553 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# The MIT License +# +# Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa +# Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors +# Copyright (c) 2016 Fastly, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# Imported from https://raw.githubusercontent.com/nghttp2/nghttp2/master/mkhufftbl.py @ 97648d2 +# +# Additional flags were added to support on the fly validation +# of headers: NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME, +# NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE and NGHTTP2_HUFF_UPPER_CASE_CHAR. +# +# This script reads Huffman Code table [1] and generates symbol table +# and decoding tables in C language. The resulting code is used in +# lib/nghttp2_hd_huffman.h and lib/nghttp2_hd_huffman_data.c +# +# [1] http://http2.github.io/http2-spec/compression.html + +from __future__ import unicode_literals +import re +import sys +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +# From [1] +HUFFMAN_CODE_TABLE = """\ + ( 0) |11111111|11000 1ff8 [13] + ( 1) |11111111|11111111|1011000 7fffd8 [23] + ( 2) |11111111|11111111|11111110|0010 fffffe2 [28] + ( 3) |11111111|11111111|11111110|0011 fffffe3 [28] + ( 4) |11111111|11111111|11111110|0100 fffffe4 [28] + ( 5) |11111111|11111111|11111110|0101 fffffe5 [28] + ( 6) |11111111|11111111|11111110|0110 fffffe6 [28] + ( 7) |11111111|11111111|11111110|0111 fffffe7 [28] + ( 8) |11111111|11111111|11111110|1000 fffffe8 [28] + ( 9) |11111111|11111111|11101010 ffffea [24] + ( 10) |11111111|11111111|11111111|111100 3ffffffc [30] + ( 11) |11111111|11111111|11111110|1001 fffffe9 [28] + ( 12) |11111111|11111111|11111110|1010 fffffea [28] + ( 13) |11111111|11111111|11111111|111101 3ffffffd [30] + ( 14) |11111111|11111111|11111110|1011 fffffeb [28] + ( 15) |11111111|11111111|11111110|1100 fffffec [28] + ( 16) |11111111|11111111|11111110|1101 fffffed [28] + ( 17) |11111111|11111111|11111110|1110 fffffee [28] + ( 18) |11111111|11111111|11111110|1111 fffffef [28] + ( 19) |11111111|11111111|11111111|0000 ffffff0 [28] + ( 20) |11111111|11111111|11111111|0001 ffffff1 [28] + ( 21) |11111111|11111111|11111111|0010 ffffff2 [28] + ( 22) |11111111|11111111|11111111|111110 3ffffffe [30] + ( 23) |11111111|11111111|11111111|0011 ffffff3 [28] + ( 24) |11111111|11111111|11111111|0100 ffffff4 [28] + ( 25) |11111111|11111111|11111111|0101 ffffff5 [28] + ( 26) |11111111|11111111|11111111|0110 ffffff6 [28] + ( 27) |11111111|11111111|11111111|0111 ffffff7 [28] + ( 28) |11111111|11111111|11111111|1000 ffffff8 [28] + ( 29) |11111111|11111111|11111111|1001 ffffff9 [28] + ( 30) |11111111|11111111|11111111|1010 ffffffa [28] + ( 31) |11111111|11111111|11111111|1011 ffffffb [28] +' ' ( 32) |010100 14 [ 6] +'!' ( 33) |11111110|00 3f8 [10] +'"' ( 34) |11111110|01 3f9 [10] +'#' ( 35) |11111111|1010 ffa [12] +'$' ( 36) |11111111|11001 1ff9 [13] +'%' ( 37) |010101 15 [ 6] +'&' ( 38) |11111000 f8 [ 8] +''' ( 39) |11111111|010 7fa [11] +'(' ( 40) |11111110|10 3fa [10] +')' ( 41) |11111110|11 3fb [10] +'*' ( 42) |11111001 f9 [ 8] +'+' ( 43) |11111111|011 7fb [11] +',' ( 44) |11111010 fa [ 8] +'-' ( 45) |010110 16 [ 6] +'.' ( 46) |010111 17 [ 6] +'/' ( 47) |011000 18 [ 6] +'0' ( 48) |00000 0 [ 5] +'1' ( 49) |00001 1 [ 5] +'2' ( 50) |00010 2 [ 5] +'3' ( 51) |011001 19 [ 6] +'4' ( 52) |011010 1a [ 6] +'5' ( 53) |011011 1b [ 6] +'6' ( 54) |011100 1c [ 6] +'7' ( 55) |011101 1d [ 6] +'8' ( 56) |011110 1e [ 6] +'9' ( 57) |011111 1f [ 6] +':' ( 58) |1011100 5c [ 7] +';' ( 59) |11111011 fb [ 8] +'<' ( 60) |11111111|1111100 7ffc [15] +'=' ( 61) |100000 20 [ 6] +'>' ( 62) |11111111|1011 ffb [12] +'?' ( 63) |11111111|00 3fc [10] +'@' ( 64) |11111111|11010 1ffa [13] +'A' ( 65) |100001 21 [ 6] +'B' ( 66) |1011101 5d [ 7] +'C' ( 67) |1011110 5e [ 7] +'D' ( 68) |1011111 5f [ 7] +'E' ( 69) |1100000 60 [ 7] +'F' ( 70) |1100001 61 [ 7] +'G' ( 71) |1100010 62 [ 7] +'H' ( 72) |1100011 63 [ 7] +'I' ( 73) |1100100 64 [ 7] +'J' ( 74) |1100101 65 [ 7] +'K' ( 75) |1100110 66 [ 7] +'L' ( 76) |1100111 67 [ 7] +'M' ( 77) |1101000 68 [ 7] +'N' ( 78) |1101001 69 [ 7] +'O' ( 79) |1101010 6a [ 7] +'P' ( 80) |1101011 6b [ 7] +'Q' ( 81) |1101100 6c [ 7] +'R' ( 82) |1101101 6d [ 7] +'S' ( 83) |1101110 6e [ 7] +'T' ( 84) |1101111 6f [ 7] +'U' ( 85) |1110000 70 [ 7] +'V' ( 86) |1110001 71 [ 7] +'W' ( 87) |1110010 72 [ 7] +'X' ( 88) |11111100 fc [ 8] +'Y' ( 89) |1110011 73 [ 7] +'Z' ( 90) |11111101 fd [ 8] +'[' ( 91) |11111111|11011 1ffb [13] +'\' ( 92) |11111111|11111110|000 7fff0 [19] +']' ( 93) |11111111|11100 1ffc [13] +'^' ( 94) |11111111|111100 3ffc [14] +'_' ( 95) |100010 22 [ 6] +'`' ( 96) |11111111|1111101 7ffd [15] +'a' ( 97) |00011 3 [ 5] +'b' ( 98) |100011 23 [ 6] +'c' ( 99) |00100 4 [ 5] +'d' (100) |100100 24 [ 6] +'e' (101) |00101 5 [ 5] +'f' (102) |100101 25 [ 6] +'g' (103) |100110 26 [ 6] +'h' (104) |100111 27 [ 6] +'i' (105) |00110 6 [ 5] +'j' (106) |1110100 74 [ 7] +'k' (107) |1110101 75 [ 7] +'l' (108) |101000 28 [ 6] +'m' (109) |101001 29 [ 6] +'n' (110) |101010 2a [ 6] +'o' (111) |00111 7 [ 5] +'p' (112) |101011 2b [ 6] +'q' (113) |1110110 76 [ 7] +'r' (114) |101100 2c [ 6] +'s' (115) |01000 8 [ 5] +'t' (116) |01001 9 [ 5] +'u' (117) |101101 2d [ 6] +'v' (118) |1110111 77 [ 7] +'w' (119) |1111000 78 [ 7] +'x' (120) |1111001 79 [ 7] +'y' (121) |1111010 7a [ 7] +'z' (122) |1111011 7b [ 7] +'{' (123) |11111111|1111110 7ffe [15] +'|' (124) |11111111|100 7fc [11] +'}' (125) |11111111|111101 3ffd [14] +'~' (126) |11111111|11101 1ffd [13] + (127) |11111111|11111111|11111111|1100 ffffffc [28] + (128) |11111111|11111110|0110 fffe6 [20] + (129) |11111111|11111111|010010 3fffd2 [22] + (130) |11111111|11111110|0111 fffe7 [20] + (131) |11111111|11111110|1000 fffe8 [20] + (132) |11111111|11111111|010011 3fffd3 [22] + (133) |11111111|11111111|010100 3fffd4 [22] + (134) |11111111|11111111|010101 3fffd5 [22] + (135) |11111111|11111111|1011001 7fffd9 [23] + (136) |11111111|11111111|010110 3fffd6 [22] + (137) |11111111|11111111|1011010 7fffda [23] + (138) |11111111|11111111|1011011 7fffdb [23] + (139) |11111111|11111111|1011100 7fffdc [23] + (140) |11111111|11111111|1011101 7fffdd [23] + (141) |11111111|11111111|1011110 7fffde [23] + (142) |11111111|11111111|11101011 ffffeb [24] + (143) |11111111|11111111|1011111 7fffdf [23] + (144) |11111111|11111111|11101100 ffffec [24] + (145) |11111111|11111111|11101101 ffffed [24] + (146) |11111111|11111111|010111 3fffd7 [22] + (147) |11111111|11111111|1100000 7fffe0 [23] + (148) |11111111|11111111|11101110 ffffee [24] + (149) |11111111|11111111|1100001 7fffe1 [23] + (150) |11111111|11111111|1100010 7fffe2 [23] + (151) |11111111|11111111|1100011 7fffe3 [23] + (152) |11111111|11111111|1100100 7fffe4 [23] + (153) |11111111|11111110|11100 1fffdc [21] + (154) |11111111|11111111|011000 3fffd8 [22] + (155) |11111111|11111111|1100101 7fffe5 [23] + (156) |11111111|11111111|011001 3fffd9 [22] + (157) |11111111|11111111|1100110 7fffe6 [23] + (158) |11111111|11111111|1100111 7fffe7 [23] + (159) |11111111|11111111|11101111 ffffef [24] + (160) |11111111|11111111|011010 3fffda [22] + (161) |11111111|11111110|11101 1fffdd [21] + (162) |11111111|11111110|1001 fffe9 [20] + (163) |11111111|11111111|011011 3fffdb [22] + (164) |11111111|11111111|011100 3fffdc [22] + (165) |11111111|11111111|1101000 7fffe8 [23] + (166) |11111111|11111111|1101001 7fffe9 [23] + (167) |11111111|11111110|11110 1fffde [21] + (168) |11111111|11111111|1101010 7fffea [23] + (169) |11111111|11111111|011101 3fffdd [22] + (170) |11111111|11111111|011110 3fffde [22] + (171) |11111111|11111111|11110000 fffff0 [24] + (172) |11111111|11111110|11111 1fffdf [21] + (173) |11111111|11111111|011111 3fffdf [22] + (174) |11111111|11111111|1101011 7fffeb [23] + (175) |11111111|11111111|1101100 7fffec [23] + (176) |11111111|11111111|00000 1fffe0 [21] + (177) |11111111|11111111|00001 1fffe1 [21] + (178) |11111111|11111111|100000 3fffe0 [22] + (179) |11111111|11111111|00010 1fffe2 [21] + (180) |11111111|11111111|1101101 7fffed [23] + (181) |11111111|11111111|100001 3fffe1 [22] + (182) |11111111|11111111|1101110 7fffee [23] + (183) |11111111|11111111|1101111 7fffef [23] + (184) |11111111|11111110|1010 fffea [20] + (185) |11111111|11111111|100010 3fffe2 [22] + (186) |11111111|11111111|100011 3fffe3 [22] + (187) |11111111|11111111|100100 3fffe4 [22] + (188) |11111111|11111111|1110000 7ffff0 [23] + (189) |11111111|11111111|100101 3fffe5 [22] + (190) |11111111|11111111|100110 3fffe6 [22] + (191) |11111111|11111111|1110001 7ffff1 [23] + (192) |11111111|11111111|11111000|00 3ffffe0 [26] + (193) |11111111|11111111|11111000|01 3ffffe1 [26] + (194) |11111111|11111110|1011 fffeb [20] + (195) |11111111|11111110|001 7fff1 [19] + (196) |11111111|11111111|100111 3fffe7 [22] + (197) |11111111|11111111|1110010 7ffff2 [23] + (198) |11111111|11111111|101000 3fffe8 [22] + (199) |11111111|11111111|11110110|0 1ffffec [25] + (200) |11111111|11111111|11111000|10 3ffffe2 [26] + (201) |11111111|11111111|11111000|11 3ffffe3 [26] + (202) |11111111|11111111|11111001|00 3ffffe4 [26] + (203) |11111111|11111111|11111011|110 7ffffde [27] + (204) |11111111|11111111|11111011|111 7ffffdf [27] + (205) |11111111|11111111|11111001|01 3ffffe5 [26] + (206) |11111111|11111111|11110001 fffff1 [24] + (207) |11111111|11111111|11110110|1 1ffffed [25] + (208) |11111111|11111110|010 7fff2 [19] + (209) |11111111|11111111|00011 1fffe3 [21] + (210) |11111111|11111111|11111001|10 3ffffe6 [26] + (211) |11111111|11111111|11111100|000 7ffffe0 [27] + (212) |11111111|11111111|11111100|001 7ffffe1 [27] + (213) |11111111|11111111|11111001|11 3ffffe7 [26] + (214) |11111111|11111111|11111100|010 7ffffe2 [27] + (215) |11111111|11111111|11110010 fffff2 [24] + (216) |11111111|11111111|00100 1fffe4 [21] + (217) |11111111|11111111|00101 1fffe5 [21] + (218) |11111111|11111111|11111010|00 3ffffe8 [26] + (219) |11111111|11111111|11111010|01 3ffffe9 [26] + (220) |11111111|11111111|11111111|1101 ffffffd [28] + (221) |11111111|11111111|11111100|011 7ffffe3 [27] + (222) |11111111|11111111|11111100|100 7ffffe4 [27] + (223) |11111111|11111111|11111100|101 7ffffe5 [27] + (224) |11111111|11111110|1100 fffec [20] + (225) |11111111|11111111|11110011 fffff3 [24] + (226) |11111111|11111110|1101 fffed [20] + (227) |11111111|11111111|00110 1fffe6 [21] + (228) |11111111|11111111|101001 3fffe9 [22] + (229) |11111111|11111111|00111 1fffe7 [21] + (230) |11111111|11111111|01000 1fffe8 [21] + (231) |11111111|11111111|1110011 7ffff3 [23] + (232) |11111111|11111111|101010 3fffea [22] + (233) |11111111|11111111|101011 3fffeb [22] + (234) |11111111|11111111|11110111|0 1ffffee [25] + (235) |11111111|11111111|11110111|1 1ffffef [25] + (236) |11111111|11111111|11110100 fffff4 [24] + (237) |11111111|11111111|11110101 fffff5 [24] + (238) |11111111|11111111|11111010|10 3ffffea [26] + (239) |11111111|11111111|1110100 7ffff4 [23] + (240) |11111111|11111111|11111010|11 3ffffeb [26] + (241) |11111111|11111111|11111100|110 7ffffe6 [27] + (242) |11111111|11111111|11111011|00 3ffffec [26] + (243) |11111111|11111111|11111011|01 3ffffed [26] + (244) |11111111|11111111|11111100|111 7ffffe7 [27] + (245) |11111111|11111111|11111101|000 7ffffe8 [27] + (246) |11111111|11111111|11111101|001 7ffffe9 [27] + (247) |11111111|11111111|11111101|010 7ffffea [27] + (248) |11111111|11111111|11111101|011 7ffffeb [27] + (249) |11111111|11111111|11111111|1110 ffffffe [28] + (250) |11111111|11111111|11111101|100 7ffffec [27] + (251) |11111111|11111111|11111101|101 7ffffed [27] + (252) |11111111|11111111|11111101|110 7ffffee [27] + (253) |11111111|11111111|11111101|111 7ffffef [27] + (254) |11111111|11111111|11111110|000 7fffff0 [27] + (255) |11111111|11111111|11111011|10 3ffffee [26] +EOS (256) |11111111|11111111|11111111|111111 3fffffff [30] +""" + +# all printable chars, except upper case and separator characters +valid_h2_field_name_char = [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 0-31 + 0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, # 32-63 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1, # 64-95 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0, # 96-127 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 128-159 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 160-191 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 192-223 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 224-255 +] + +# all printable chars + horizontal tab + everything >= 0x80 to let UTF-8 through +valid_h2_field_value_char = [ + 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, # 0-31 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # 32-63 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # 64-95 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, # 96-127 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # 128-159 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # 160-191 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # 192-223 + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, # 224-255 +] + + +class Node: + + def __init__(self, term = None): + self.term = term + self.left = None + self.right = None + self.trans = [] + self.id = None + self.accept = False + +class Context: + + def __init__(self): + self.next_id_ = 0 + self.root = Node() + + def next_id(self): + id = self.next_id_ + self.next_id_ += 1 + return id + +def _add(node, sym, bits): + if len(bits) == 0: + node.term = sym + return + else: + if bits[0] == '0': + if node.left is None: + node.left = Node() + child = node.left + else: + if node.right is None: + node.right = Node() + child = node.right + _add(child, sym, bits[1:]) + +def huffman_tree_add(ctx, sym, bits): + _add(ctx.root, sym, bits) + +def _set_node_id(ctx, node, prefix): + if node.term is not None: + return + if len(prefix) <= 7 and [1] * len(prefix) == prefix: + node.accept = True + node.id = ctx.next_id() + _set_node_id(ctx, node.left, prefix + [0]) + _set_node_id(ctx, node.right, prefix + [1]) + +def huffman_tree_set_node_id(ctx): + _set_node_id(ctx, ctx.root, []) + +def _traverse(node, sym, start_node, root, left): + if left == 0: + if sym == 256: + sym = None + node = None + start_node.trans.append((node, sym)) + return + + if node.term is not None: + node = root + + def go(node): + if node.term is not None: + assert sym is None + nsym = node.term + else: + nsym = sym + + _traverse(node, nsym, start_node, root, left - 1) + + go(node.left) + go(node.right) + +def _build_transition_table(ctx, node): + if node is None: + return + _traverse(node, None, node, ctx.root, 4) + _build_transition_table(ctx, node.left) + _build_transition_table(ctx, node.right) + +def huffman_tree_build_transition_table(ctx): + _build_transition_table(ctx, ctx.root) + +NGHTTP2_HUFF_ACCEPTED = 1 +NGHTTP2_HUFF_SYM = 1 << 1 +NGHTTP2_HUFF_FAIL = 1 << 2 +NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME = 1 << 3 +NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE = 1 << 4 +NGHTTP2_HUFF_UPPER_CASE_CHAR = 1 << 5 + +def _print_transition_table(node): + if node.term is not None: + return + print('/* {} */'.format(node.id)) + print('{') + for nd, sym in node.trans: + flags = 0 + if sym is None: + out = 0 + else: + out = sym + flags |= NGHTTP2_HUFF_SYM + if not valid_h2_field_name_char[sym]: + flags |= NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME + if not valid_h2_field_value_char[sym]: + flags |= NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE + if sym >= ord('A') and sym <= ord('Z'): + flags |= NGHTTP2_HUFF_UPPER_CASE_CHAR + if nd is None: + id = 0 + flags |= NGHTTP2_HUFF_FAIL + else: + id = nd.id + if id is None: + # if nd.id is None, it is a leaf node + id = 0 + flags |= NGHTTP2_HUFF_ACCEPTED + elif nd.accept: + flags |= NGHTTP2_HUFF_ACCEPTED + print(' {{{}, 0x{:02x}, {}}},'.format(id, flags, out)) + print('},') + _print_transition_table(node.left) + _print_transition_table(node.right) + +def huffman_tree_print_transition_table(ctx): + _print_transition_table(ctx.root) + +if __name__ == '__main__': + ctx = Context() + symbol_tbl = [(None, 0) for i in range(257)] + + for line in StringIO(HUFFMAN_CODE_TABLE): + m = re.match( + r'.*\(\s*(\d+)\)\s+([|01]+)\s+(\S+)\s+\[\s*(\d+)\].*', line) + if m: + sym = int(m.group(1)) + bits = re.sub(r'\|', '', m.group(2)) + code = m.group(3) + nbits = int(m.group(4)) + if len(code) > 8: + raise Error('Code is more than 4 bytes long') + assert(len(bits) == nbits) + symbol_tbl[sym] = (nbits, code) + huffman_tree_add(ctx, sym, bits) + + huffman_tree_set_node_id(ctx) + huffman_tree_build_transition_table(ctx) + + print('''\ +// !!! DO NOT EDIT !!! Generated by misc/mkhufftbl.c +/* + * The MIT License + * + * Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa + * Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors + * Copyright (c) 2016 Fastly, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +''') + + print('''\ +typedef struct { + uint32_t nbits; + uint32_t code; +} nghttp2_huff_sym; +''') + + print('''\ +static const nghttp2_huff_sym huff_sym_table[] = {''') + for i in range(257): + print('''\ + {{ {}, 0x{}u }}{}\ +'''.format(symbol_tbl[i][0], symbol_tbl[i][1], ',' if i < 256 else '')) + print('};') + print('') + + print('''\ +typedef enum {{ + NGHTTP2_HUFF_ACCEPTED = {}, + NGHTTP2_HUFF_SYM = {}, + NGHTTP2_HUFF_FAIL = {}, + NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME = {}, + NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE = {}, + NGHTTP2_HUFF_UPPER_CASE_CHAR = {}, +#define NGHTTP2_HUFF_INVALID_CHARS (NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME | NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE) +}} nghttp2_huff_decode_flag; +'''.format(NGHTTP2_HUFF_ACCEPTED, NGHTTP2_HUFF_SYM, NGHTTP2_HUFF_FAIL, NGHTTP2_HUFF_INVALID_FOR_HEADER_NAME, NGHTTP2_HUFF_INVALID_FOR_HEADER_VALUE, NGHTTP2_HUFF_UPPER_CASE_CHAR)) + + print('''\ +typedef struct { + uint8_t state; + uint8_t flags; + uint8_t sym; +} nghttp2_huff_decode; +''') + + print('''\ +static const nghttp2_huff_decode huff_decode_table[][16] = {''') + huffman_tree_print_transition_table(ctx) + print('};') diff --git a/debian/vendor-h2o/misc/mruby-mtest/.travis.yml b/debian/vendor-h2o/misc/mruby-mtest/.travis.yml new file mode 100644 index 0000000..ffe2272 --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/.travis.yml @@ -0,0 +1,2 @@ +script: + - "ruby run_test.rb all test" diff --git a/debian/vendor-h2o/misc/mruby-mtest/README.md b/debian/vendor-h2o/misc/mruby-mtest/README.md new file mode 100644 index 0000000..5a1b1b4 --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/README.md @@ -0,0 +1,63 @@ +Minimum Test Framework for mruby +========= + +[![Build Status](https://travis-ci.org/iij/mruby-mtest.svg?branch=master)](https://travis-ci.org/iij/mruby-mtest) + +## example +```ruby +class Test4MTest < MTest::Unit::TestCase + def test_assert + assert(true) + assert(true, 'true sample test') + end +end + +MTest::Unit.new.run +``` + +### How to use mrbgem's mrbtest +```ruby +if Object.const_defined?(:MTest) + class Test4MTest < MTest::Unit::TestCase + def test_assert_nil + assert_nil(nil, 'nil sample test') + end + end + + if $ok_test + MTest::Unit.new.mrbtest + else + MTest::Unit.new.run + end +else + $asserts << "test skip of Test4MTest." if $asserts +end +``` + +## TODO + + - MiniTest::Unit.autorun is not implemented (because mruby hasn't ``at_exit`` method.) + + +## License + +Copyright (c) 2013 Internet Initiative Japan Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/debian/vendor-h2o/misc/mruby-mtest/example/sample.rb b/debian/vendor-h2o/misc/mruby-mtest/example/sample.rb new file mode 100644 index 0000000..67c4e44 --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/example/sample.rb @@ -0,0 +1,46 @@ +class Test4MTest < MTest::Unit::TestCase + def test_assert + assert(true) + assert(true, 'true sample test') + end + + def test_assert_block + assert_block('msg') do + 'something-block' + end + end + + def test_assert_empty + assert_empty('', 'string empty') + assert_empty([], 'array empty') + assert_empty({}, 'hash empty') + end + + def test_assert_equal + assert_equal('', nil.to_s) + end + + def test_assert_in_delta + assert_in_delta(0, 0.1, 0.5) + end + + def test_assert_includes + assert_include([1,2,3], 1) + end + + def test_assert_instance_of + assert_instance_of Array, [] + assert_instance_of Class, Array + end + + def test_assert_kind_of + assert_kind_of Array, [] + assert_kind_of Class, Array + end + + def test_assert_match + assert_match 'abc', 'abc' + end +end + +MTest::Unit.new.run diff --git a/debian/vendor-h2o/misc/mruby-mtest/mrbgem.rake b/debian/vendor-h2o/misc/mruby-mtest/mrbgem.rake new file mode 100644 index 0000000..027fb73 --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/mrbgem.rake @@ -0,0 +1,8 @@ +MRuby::Gem::Specification.new('mruby-mtest') do |spec| + spec.license = 'MIT' + spec.authors = 'Internet Initiative Japan Inc.' + + spec.add_dependency 'mruby-sprintf', core: 'mruby-sprintf' + spec.add_dependency 'mruby-time', core: 'mruby-time' + spec.add_dependency 'mruby-io', mgem: 'mruby-io' +end diff --git a/debian/vendor-h2o/misc/mruby-mtest/mrblib/mtest_unit.rb b/debian/vendor-h2o/misc/mruby-mtest/mrblib/mtest_unit.rb new file mode 100644 index 0000000..d843cc1 --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/mrblib/mtest_unit.rb @@ -0,0 +1,698 @@ +# -*- coding: utf-8 -*- + +## +# Minimal Test framework for mruby +# +module MTest + + + ## + # Assertion base class + + class Assertion < Exception; end + + ## + # Assertion raised when skipping a test + + class Skip < Assertion; end + + module Assertions + def mu_pp obj + obj.inspect + end + + def diff exp, act + return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" + end + + def _assertions= n + @_assertions = n + end + + def _assertions + @_assertions = 0 unless @_assertions + @_assertions + end + + ## + # Fails unless +test+ is a true value. + + def assert test, msg = nil + msg ||= "Failed assertion, no message given." + self._assertions += 1 + unless test + msg = msg.call if Proc === msg + raise MTest::Assertion, msg + end + true + end + + alias assert_true assert + + ## + # Fails unless +test+ is a false value + def assert_false test, msg = nil + msg = message(msg) { "Expected #{mu_pp(test)} to be false" } + assert test == false, msg + end + + ## + # Fails unless the block returns a true value. + + def assert_block msg = nil + msg = message(msg) { "Expected block to return true value" } + assert yield, msg + end + + ## + # Fails unless +obj+ is empty. + + def assert_empty obj, msg = nil + msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" } + assert_respond_to obj, :empty? + assert obj.empty?, msg + end + + ## + # Fails +obj+ is not empty. + + def assert_not_empty obj, msg = nil + msg = message(msg) { "Expected #{mu_pp(obj)} to be not empty" } + assert_respond_to obj, :empty? + assert !obj.empty?, msg + end + + ## + # Fails unless exp == act printing the difference between + # the two, if possible. + # + # If there is no visible difference but the assertion fails, you + # should suspect that your #== is buggy, or your inspect output is + # missing crucial details. + # + # For floats use assert_in_delta. + # + # See also: MiniTest::Assertions.diff + + def assert_equal exp, act, msg = nil + msg = message(msg, "") { diff exp, act } + assert(exp == act, msg) + end + + ## + # Fails exp == act + def assert_not_equal exp, act, msg = nil + msg = message(msg) { + "Expected #{mu_pp(exp)} to be not equal #{mu_pp(act)}" + } + assert(exp != act, msg) + end + + ## + # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+ + # of each other. + # + # assert_in_delta Math::PI, (22.0 / 7.0), 0.01 + + def assert_in_delta exp, act, delta = 0.001, msg = nil + n = (exp - act).abs + msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" } + assert delta >= n, msg + end + + ## + # For comparing Floats. Fails unless +exp+ and +act+ have a relative + # error less than +epsilon+. + + def assert_in_epsilon a, b, epsilon = 0.001, msg = nil + assert_in_delta a, b, [a, b].min * epsilon, msg + end + + ## + # Fails unless +collection+ includes +obj+. + + def assert_include collection, obj, msg = nil + msg = message(msg) { + "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" + } + assert_respond_to collection, :include? + assert collection.include?(obj), msg + end + + ## + # Fails +collection+ includes +obj+ + def assert_not_include collection, obj, msg = nil + msg = message(msg) { + "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" + } + assert_respond_to collection, :include? + assert !collection.include?(obj), msg + end + + ## + # Fails unless +obj+ is an instance of +cls+. + + def assert_instance_of cls, obj, msg = nil + msg = message(msg) { + "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" + } + + assert obj.instance_of?(cls), msg + end + + ## + # Fails unless +obj+ is a kind of +cls+. + + def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of + msg = message(msg) { + "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" } + + assert obj.kind_of?(cls), msg + end + + ## + # Fails unless +exp+ is =~ +act+. + + def assert_match exp, act, msg = nil + if Object.const_defined?(:Regexp) + msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" } + assert_respond_to act, :"=~" + exp = Regexp.new Regexp.escape exp if String === exp and String === act + assert exp =~ act, msg + else + raise MTest::Skip, "assert_match is not defined, because Regexp is not impl." + end + end + + ## + # Fails unless +obj+ is nil + + def assert_nil obj, msg = nil + msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" } + assert obj.nil?, msg + end + + ## + # For testing equality operators and so-forth. + # + # assert_operator 5, :<=, 4 + + def assert_operator o1, op, o2, msg = nil + msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" } + assert o1.__send__(op, o2), msg + end + + ## + # Fails if stdout or stderr do not output the expected results. + # Pass in nil if you don't care about that streams output. Pass in + # "" if you require it to be silent. + # + # See also: #assert_silent + + def assert_output stdout = nil, stderr = nil + out, err = capture_io do + yield + end + + x = assert_equal stdout, out, "In stdout" if stdout + y = assert_equal stderr, err, "In stderr" if stderr + + (!stdout || x) && (!stderr || y) + end + + ## + # Fails unless the block raises one of +exp+ + + def assert_raise *exp + msg = "#{exp.pop}\n" if String === exp.last + + begin + yield + rescue MTest::Skip => e + return e if exp.include? MTest::Skip + raise e + rescue Exception => e + excepted = exp.any? do |ex| + if ex.instance_of?(Module) + e.kind_of?(ex) + else + e.instance_of?(ex) + end + end + + assert excepted, exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not") + + return e + end + exp = exp.first if exp.size == 1 + flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised." + end + + ## + # Fails unless +obj+ responds to +meth+. + + def assert_respond_to obj, meth, msg = nil + msg = message(msg, '') { + "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}" + } + assert obj.respond_to?(meth), msg + end + + ## + # Fails unless +exp+ and +act+ are #equal? + + def assert_same exp, act, msg = nil + msg = message(msg) { + data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id] + "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data + } + assert exp.equal?(act), msg + end + + ## + # +send_ary+ is a receiver, message and arguments. + # + # Fails unless the call returns a true value + # TODO: I should prolly remove this from specs + + def assert_send send_ary, m = nil + recv, msg, *args = send_ary + m = message(m) { + "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" } + assert recv.__send__(msg, *args), m + end + + ## + # Fails if the block outputs anything to stderr or stdout. + # + # See also: #assert_output + + def assert_silent + assert_output "", "" do + yield + end + end + + ## + # Fails unless the block throws +sym+ + + def assert_throws sym, msg = nil + default = "Expected #{mu_pp(sym)} to have been thrown" + caught = true + catch(sym) do + begin + yield + rescue ArgumentError => e # 1.9 exception + default += ", not #{e.message.split(' ').last}" + rescue NameError => e # 1.8 exception + default += ", not #{e.name.inspect}" + end + caught = false + end + + assert caught, message(msg) { default } + end + + ## + # Returns a proc that will output +msg+ along with the default message. + + def message msg = nil, ending = ".", &default + Proc.new{ + custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? + "#{custom_message}#{default.call}#{ending}" + } + end + + ## + # used for counting assertions + + def pass msg = nil + assert true + end + + ## + # Skips the current test. Gets listed at the end of the run but + # doesn't cause a failure exit code. + + # disable backtrace for mruby + + def skip msg = nil + msg ||= "Skipped, no message given" + raise MTest::Skip, msg + end + + ## + # Returns details for exception +e+ + + # disable backtrace for mruby + + def exception_details e, msg + [ + "#{msg}", + "Class: <#{e.class}>", + "Message: <#{e.message.inspect}>", +# "---Backtrace---", +# "#{MiniTest::filter_backtrace(e.backtrace).join("\n")}", +# "---------------", + ].join "\n" + end + + ## + # Fails with +msg+ + + def flunk msg = nil + msg ||= "Epic Fail!" + assert false, msg + end + + end + + class Unit + attr_accessor :report, :failures, :errors, :skips + attr_accessor :test_count, :assertion_count + attr_accessor :start_time + attr_accessor :help + attr_accessor :verbose + attr_writer :options + + def options + @options ||= {} + end + + @@out = $stdout + @@runner = nil + + def self.output + @@out + end + + def self.output= stream + @@out = stream + end + + def self.runnner= runner + @@runner = runnner + end + + def self.runner + @@runner = self.new unless @@runner + @@runner + end + + def output + self.class.output + end + + def puts *a + output.puts(*a) + end + + def print *a + output.print(*a) + end + + def puke klass, meth, e + e = case e + when MTest::Skip + @skips += 1 + "Skipped:\n#{meth}(#{klass}) #{e.inspect}\n" + when MTest::Assertion + @failures += 1 + "Failure:\n#{meth}(#{klass}) #{e.inspect}\n" + else + @errors += 1 + "Error:\n#{meth}(#{klass}): #{e.class}, #{e.inspect}\n" + end + @report << e + e[0, 1] + end + + def initialize + @report = [] + @errors = @failures = @skips = 0 + @verbose = false + end + + def run args = [] + self.class.runner._run(args) + end + + def mrbtest + suites = TestCase.send "test_suites" + return if suites.empty? + + @test_cound, @assertion_count = 0, 0 + + results = _run_suites suites + + @test_count = results.map{ |r| r[0] }.inject(0) { |sum, tc| sum + tc } + @assertion_count = results.map{ |r| r[1] }.inject(0) { |sum, ac| sum + ac } + + $ok_test += (test_count.to_i - failures.to_i - errors.to_i - skips.to_i) + $ko_test += failures.to_i + $kill_test += errors.to_i + report.each_with_index do |msg, i| + $asserts << "MTest #{i+1}) #{msg}" + end + + TestCase.reset + end + + def _run args = [] + _run_tests + @test_count ||= 0 + @test_count > 0 ? failures + errors : nil + end + + def _run_tests + suites = TestCase.send "test_suites" + return if suites.empty? + + start = Time.now + + puts + puts "# Running tests:" + puts + + @test_count, @assertion_count = 0, 0 + + results = _run_suites suites + + @test_count = results.map{ |r| r[0] }.inject(0) { |sum, tc| sum + tc } + @assertion_count = results.map{ |r| r[1] }.inject(0) { |sum, ac| sum + ac } + + t = Time.now - start + + puts + puts + puts sprintf("Finished tests in %.6fs, %.4f tests/s, %.4f assertions/s.", + t, test_count / t, assertion_count / t) + + report.each_with_index do |msg, i| + puts sprintf("\n%3d) %s", i+1, msg) + end + + puts + + status + end + + def _run_suites suites + suites.map { |suite| _run_suite suite } + end + + def _run_suite suite + header = "test_suite_header" + puts send(header, suite) if respond_to? header + + assertions = suite.send("test_methods").map do |method| + inst = suite.new method + inst._assertions = 0 + + print "#{suite}##{method} = " if @verbose + + @start_time = Time.now + result = inst.run self + time = Time.now - @start_time + + print sprintf("%.2f s = ", time) if @verbose + print result + puts if @verbose + + inst._assertions + end + + return assertions.size, assertions.inject(0) { |sum, n| sum + n } + end + + def status io = self.output + format = "%d tests, %d assertions, %d failures, %d errors, %d skips" + io.puts sprintf(format, test_count, assertion_count, failures, errors, skips) + end + + class TestCase + attr_reader :__name__ + + @@test_suites = {} + + def run runner + result = "" + begin + @passed = nil + self.setup + self.run_setup_hooks + self.__send__ self.__name__ + result = "." unless io? + @passed = true + rescue Exception => e + @passed = false + result = runner.puke self.class, self.__name__, e + ensure + begin + self.run_teardown_hooks + self.teardown + rescue Exception => e + result = runner.puke self.class, self.__name__, e + end + end + result + end + + def initialize name = self.to_s + @__name__ = name + @__io__ = nil + @passed = nil + end + + def io + @__io__ = true + MTest::Unit.output + end + + def io? + @__io__ + end + + def self.reset + @@test_suites = {} + end + + reset + + def self.inherited klass + @@test_suites[klass] = true + klass.reset_setup_teardown_hooks + end + + def self.test_order + :random + end + + def self.test_suites + hash = {} + @@test_suites.keys.each{ |ts| hash[ts.to_s] = ts } + hash.keys.sort.map{ |key| hash[key] } + end + + def self.test_methods # :nodoc: + methods = [] + self.new.methods(true).each do |m| + methods << m.to_s if m.to_s.index('test') == 0 + end + + case self.test_order + when :random then + max = methods.size + # TODO: methods.sort.sort_by { rand max } + methods + when :alpha, :sorted then + methods.sort + else + raise "Unknown test_order: #{self.test_order.inspect}" + end + end + + + def passed? + @passed + end + + def setup; end + def teardown; end + def self.reset_setup_teardown_hooks + @setup_hooks = [] + @teardown_hooks = [] + end + reset_setup_teardown_hooks + + def self.add_setup_hook arg=nil, &block + hook = arg || block + @setup_hooks << hook + end + + def self.setup_hooks # :nodoc: + if superclass.respond_to? :setup_hooks then + superclass.setup_hooks + else + [] + end + @setup_hooks + end + + def run_setup_hooks # :nodoc: + self.class.setup_hooks.each do |hook| + if hook.respond_to?(:arity) && hook.arity == 1 + hook.call(self) + else + hook.call + end + end + end + + def self.add_teardown_hook arg=nil, &block + hook = arg || block + @teardown_hooks << hook + end + + def self.teardown_hooks # :nodoc: + if superclass.respond_to? :teardown_hooks then + superclass.teardown_hooks + else + [] + end + @teardown_hooks + end + + def run_teardown_hooks # :nodoc: + self.class.teardown_hooks.reverse.each do |hook| + if hook.respond_to?(:arity) && hook.arity == 1 + hook.call(self) + else + hook.call + end + end + end + + + include MTest::Assertions + end + end +end + +if __FILE__ == $0 + class Test4MTest < MTest::Unit::TestCase + def setup + puts '*setup' + end + + def teardown + puts '*teardown' + end + + def test_sample + puts '*test_sample' + assert(true, 'true sample test') + assert(true) + end + end + + MTest::Unit.new.run +end diff --git a/debian/vendor-h2o/misc/mruby-mtest/run_test.rb b/debian/vendor-h2o/misc/mruby-mtest/run_test.rb new file mode 100644 index 0000000..c45033e --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/run_test.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# +# mrbgems test runner +# + +if __FILE__ == $0 + repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby' + build_args = ARGV + build_args = ['all', 'test'] if build_args.nil? or build_args.empty? + + Dir.mkdir 'tmp' unless File.exist?('tmp') + unless File.exist?(dir) + system "git clone #{repository} #{dir}" + end + + exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}]) +end + +MRuby::Build.new do |conf| + toolchain :gcc + conf.gembox 'default' + + conf.gem File.expand_path(File.dirname(__FILE__)) + conf.gem :core => 'mruby-time' + conf.gem :github => 'iij/mruby-io' +end diff --git a/debian/vendor-h2o/misc/mruby-mtest/test/mtest_unit_test.rb b/debian/vendor-h2o/misc/mruby-mtest/test/mtest_unit_test.rb new file mode 100644 index 0000000..43f74cf --- /dev/null +++ b/debian/vendor-h2o/misc/mruby-mtest/test/mtest_unit_test.rb @@ -0,0 +1,74 @@ +## +# Test of Minimal Test framework for mruby. +# + +if Object.const_defined?(:MTest) + class Test4MTest < MTest::Unit::TestCase + def test_assert + assert(true) + assert(true, 'true sample test') + assert_true(true) + assert_false(false) + assert_nil(nil) + end + + def test_assert_block + assert_block('msg') do + 'something-block' + end + end + + def test_assert_empty + assert_empty('', 'string empty') + assert_empty([], 'array empty') + assert_empty({}, 'hash empty') + end + + def test_assert_equal + assert_equal('', nil.to_s) + assert_not_equal('a', nil.to_s) + end + + def test_assert_in_delta + assert_in_delta(0, 0.1, 0.5) + end + + def test_assert_include + assert_include([1,2,3], 1) + end + + def test_assert_instance_of + assert_instance_of Array, [] + assert_instance_of Class, Array + end + + def test_assert_kind_of + assert_kind_of Array, [] + assert_kind_of Class, Array + end + + def test_assert_match + assert_match 'abc', 'abc' + end + + def test_assert_raise + assert_raise(RuntimeError) do + raise + end + end + + def test_assert_false_failure + assert_raise(MTest::Assertion) do + assert_false(true) + end + end + end + + if $ok_test + MTest::Unit.new.mrbtest + else + MTest::Unit.new.run + end +else + $asserts << "test skip of mruby-mtest/test/mtest_unit_test.rb" if $asserts +end diff --git a/debian/vendor-h2o/misc/mruby_config.rb b/debian/vendor-h2o/misc/mruby_config.rb new file mode 100644 index 0000000..64e62b6 --- /dev/null +++ b/debian/vendor-h2o/misc/mruby_config.rb @@ -0,0 +1,29 @@ +MRuby::Build.new do |conf| + # load specific toolchain settings + + # Gets set by the VS command prompts. + if ENV['MRUBY_TOOLCHAIN'] + toolchain ENV['MRUBY_TOOLCHAIN'] + elsif ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] + toolchain :visualcpp + else + toolchain :gcc + end + + # enable_debug + + # use mrbgems + Dir.glob("../mruby-*/mrbgem.rake") do |x| + g = File.basename File.dirname x + if g == 'mruby-onig-regexp' + conf.gem "../deps/#{g}" do |c| + c.bundle_onigmo + end + else + conf.gem "../deps/#{g}" + end + end + + # include all the core GEMs + conf.gembox 'full-core' +end diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/Changes b/debian/vendor-h2o/misc/p5-net-fastcgi/Changes new file mode 100644 index 0000000..e8a0c6a --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/Changes @@ -0,0 +1,102 @@ +0.14 2012-03-26 + - No functional changes in this release + - Don't rely on hash keys being ordered in tests, Perl 5.18 introduces a + per process randomization. + +0.13 2011-02-12 + - No functional changes in this release + - Added eg/runfcgi.pl, contributed by Paul Evans (LeoNerd) + - Added eg/server.pl + +0.12 2010-07-14 + - Added Net::FastCGI::IO + +0.11 2010-04-09 + - Documented the goals with this project/distribution + - Net::FastCGI::Protocol + - Fixed dump_record() to properly escape FCGI_NameValuePair header + - Added tests for this + - Added get_record_length() + - Added documentation and tests + - Changed parse_record() to return a list in list context, this makes it + more consistent with parse_header() + - Added documentation and tests this change + - Changed dump_record() to accept a string of octets (old behavior is + still supported but deprecated, please change function call to dump_record_body()) + This change makes it more consistent with parse_record_body(). + - Added documentation and tests this change + +0.10 2010-04-02 + - Minor optimizations to avoid unnecessary copying of '$content' strings + - Fixed dump_record() to properly insert ellipsis when truncating stream content + - added tests for this + - Added more tests for dump_record() + +0.09 2010-03-31 + - Added check_params() and dump_record() + - added documentation + - added test for check_params() and dump_record() (incomplete) + - Minor optimizations to build_stream() and build_record() + +0.08 2010-02-16 + - Documented return value of get_type_name(), get_role_name() + and get_protocol_status_name(). + - Changed test prerequisite from Test::BinaryData to Test::HexString. + - Corrected note about AnyEvent::FCGI, it's capable of multiplexing. + +0.07 2010-02-10 + - Added notes about existing Perl implementations. + - Added references to specifications and white papers. + - Minor internal "cosmetic" changes + - Added more tests for build_begin_request() and build_end_request() + +0.06 2010-02-09 + - NOTE: Changed application_status to app_status, this affects users of + parse_record() or parse_record_body(). Former was unnecessarily verbose. + Latter also matches the component name of FCGI_BeginRequestBody struct. + - Added build_begin_request() and build_end_request() + - added documentation and tests for these + +0.05 2010-02-06 + - Net::FastCGI::Constant + - Improved documentation + - Added @FCGI_TYPE_NAME, @FCGI_ROLE_NAME and @FCGI_PROTOCOL_STATUS_NAME + - Re-factored Net::FastCGI::Protocol to use these. + - Renamed FCGI_MAX_LEN to FCGI_MAX_CONTENT_LEN + - FCGI_MAX_LEN is deprecated and will be removed in a future version. + - Net::FastCGI::Protocol + - Fixed parse_record() and parse_record_body() to properly detect malformed + stream records. + - Added tests for this. + - Increased segment size in build_stream() from 8192 to 32760 to reflect modern + socket buffers. + - Updated tests + - Documented segment size + - Documented scalar return value of parse_header() + - Minor documentation updates + +0.04 2010-01-30 + - Added parse_record() and parse_record_body() + - Added tests for these + - Added docs (incomplete) + - Cleaned up exception messages. Protocol exceptions now have a FastCGI prefix + - Fixed parse_params() to correctly detect incomplete FCGI_NameValuePair's + - added tests for this + - Added tests for build_stream() + - Changed parse_header() to return a hash reference in scalar context + - added tests for this + - Coverage ~90% (stmt:100.0 bran:96.9 cond:92.9) + - More tests (and docs) needed to cover all cases + +0.03 2010-01-23 + - Fixed package loading in Net::FastCGI::Protocol + +0.02 2010-01-23 + - Removed object oriented implementation, it will eventually be released as + a separate distribution with different prerequisites. + - Removed unnecessary functions from Net::FastCGI::Protocol + - Re-factored internals of Net::FastCGI::Protocol to be more performant. + - No major changes planned for existing API in Net::FastCGI::Protocol + +0.01_01 2009-10-17 + - Initial release. diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/MANIFEST.SKIP b/debian/vendor-h2o/misc/p5-net-fastcgi/MANIFEST.SKIP new file mode 100644 index 0000000..b6d0b82 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/MANIFEST.SKIP @@ -0,0 +1,25 @@ +^_build +^Build$ +^blib +~$ +\.bak$ +CVS +\.svn +\.DS_Store +cover_db +\..*\.sw.?$ +^Makefile$ +^pm_to_blib$ +^MakeMaker-\d +^blibdirs$ +\.old$ +^#.*#$ +^\.# +^TODO$ +^PLANS$ +^doc/ +^dev/ +^benchmarks +^\._.*$ +\.shipit +\.git.* diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/Makefile.PL b/debian/vendor-h2o/misc/p5-net-fastcgi/Makefile.PL new file mode 100644 index 0000000..0b1d1f4 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/Makefile.PL @@ -0,0 +1,19 @@ +use strict; +use inc::Module::Install; + +name 'Net-FastCGI'; +perl_version '5.006'; +all_from 'lib/Net/FastCGI.pm'; +repository 'http://github.com/chansen/p5-net-fastcgi'; + +requires 'Carp' => '0'; +requires 'Exporter' => '0'; + +test_requires 'Test::More' => '0.47'; +test_requires 'Test::Exception' => '0'; +test_requires 'Test::HexString' => '0'; + +tests 't/*.t t/*/*.t'; + +WriteAll; + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/README b/debian/vendor-h2o/misc/p5-net-fastcgi/README new file mode 100644 index 0000000..4eea9d5 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/README @@ -0,0 +1,113 @@ +NAME + Net::FastCGI - FastCGI Toolkit + +DESCRIPTION + This distribution aims to provide a complete API for working with the + FastCGI protocol. + + The primary goal is to provide a function oriented and object oriented + API which are not tied to a specific I/O model or framework. + + Secondary goal is to provide higher level tools/API which can be used + for debugging and interoperability testing. + +PROGRESS + The function oriented API is considered feature complete. + Net::FastCGI::Protocol provides functions to build and parse all FastCGI + v1.0 messages, also provided is a few convenient higher level functions + such as "build_begin_request()", "build_end_request()", "parse_record()" + and "dump_record()". + + Work has begun on object oriented implementation and a simple blocking + I/O class which is intended for testing and debugging. + +PACKAGES + Net::FastCGI::Constant + FastCGI protocol constants. + + Net::FastCGI::IO + Provides functions to read and write FastCGI messages. + + Net::FastCGI::Protocol + Provides functions to build and parse FastCGI messages. + +ENVIRONMENT + Environment variable "NET_FASTCGI_PP" can be set to a true value before + loading this package to disable usage of XS implementation. + +PREREQUISITES + Run-Time + perl 5.6 or greater. + Carp, core module. + Exporter, core module. + + Build-Time + In addition to Run-Time: + + Test::More 0.47 or greater, core module since 5.6.2. + Test::Exception. + Test::HexString. + +SEE ALSO + Community + Official FastCGI site + + + Standards + FastCGI Specification Version 1.0 + + + RFC 3875 - The Common Gateway Interface (CGI) Version 1.1 + + + White papers + FastCGI: A High-Performance Web Server Interface + + + FastCGI - The Forgotten Treasure + + + Perl implementations + AnyEvent::FCGI + Application server implementation, built on top of AnyEvent. + Supports Responder role. Capable of multiplexing. + + FCGI + Application server implementation, built on top of "libfcgi" + (reference implementation). Supports all FastCGI roles. Responds to + management records. Processes requests synchronously. + + FCGI::Async + Application server implementation, built on top of IO::Async. + Supports Responder role. Responds to management records. Capable of + multiplexing. + + FCGI::Client + Client (Web server) implementation. Supports Responder role. + + FCGI::EV + Application server implementation, built on top of EV. Supports + Responder role. + + Mojo::Server::FastCGI + Application server implementation. Supports Responder role. + Processes requests synchronously. + + POE::Component::FastCGI + Application server implementation, built on top of POE. Supports + Responder role. Capable of multiplexing. + +SUPPORT + Please report any bugs or feature requests to + "bug-net-fastcgi@rt.cpan.org", or through the web interface at + + +AUTHOR + Christian Hansen "chansen@cpan.org" + +COPYRIGHT + Copyright 2008-2010 by Christian Hansen. + + This library is free software; you can redistribute it and/or modify it + under the same terms as Perl itself. + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/eg/runfcgi.pl b/debian/vendor-h2o/misc/p5-net-fastcgi/eg/runfcgi.pl new file mode 100755 index 0000000..7ee01a9 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/eg/runfcgi.pl @@ -0,0 +1,226 @@ +#!/usr/bin/perl +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. +# +# (C) Paul Evans, 2010 -- leonerd@leonerd.org.uk + +use strict; +use warnings; + +use Getopt::Long; + +use Net::FastCGI::IO qw( read_record ); +use Net::FastCGI::Constant qw( :common :type :role ); +use Net::FastCGI::Protocol qw( + build_begin_request_body + build_params + parse_end_request_body +); + +sub write_record +{ + Net::FastCGI::IO::write_record(@_) or + die "Cannot write_record - $!"; +} + +my %env = ( + REQUEST_METHOD => "GET", + SCRIPT_NAME => "", + SERVER_NAME => "server", + SERVER_PORT => 80, + SERVER_PROTOCOL => "HTTP/1.1", +); + +my $stdin_from; +my $filter_stdout; + +sub usage +{ + print <<"EOF"; +$0 [options] CONNECT URL + +Runs the FastCGI found at CONNECT, as if it had received the URL + +CONNECT may be any of + + exec:PATH Execute as a child process with socket on STDIN + unix:PATH Find a UNIX socket on the given path + tcp:HOST:PORT Connect to the given port on the given host + HOST:PORT as above + +options may be: + + --body Print just the HTTP response body + --no-body Print just the HTTP response headers without the body + -m, --method METHOD Use the specified method (default "GET") + -p, --post Method is POST, pass STDIN + --put Method is PUT, pass STDIN + --stdin PATH Read STDIN from specified path, "-" means real script + +EOF +} + +GetOptions( + 'body' => sub { + defined $filter_stdout and die "Cannot --no-body and --body\n"; + $filter_stdout = "body"; + }, + 'no-body' => sub { + defined $filter_stdout and die "Cannot --no-body and --body\n"; + $filter_stdout = "headers"; + }, + 'm|method=s' => \$env{REQUEST_METHOD}, + 'p|post' => sub { + $env{REQUEST_METHOD} = "POST"; + $stdin_from = "-"; + }, + 'put' => sub { + $env{REQUEST_METHOD} = "PUT"; + $stdin_from = "-"; + }, + 'stdin=s' => \$stdin_from, + 'help' => sub { usage; exit(0) }, +) or exit(1); + +my $connect = shift @ARGV or + die "Require connection string\n"; + +my $url = shift @ARGV or + die "Require a URL"; + +if( $url =~ s{^http(s?)://([^/:]+)(?::([^/]+))?}{} ) { + $env{HTTPS} = "on" if $1; + $env{SERVER_NAME} = $2; + $env{SERVER_PORT} = $3 || ( $1 ? 443 : 80 ); +} + +$env{REQUEST_URI} = $url; + +my ( $path, $query ) = $url =~ m/^(.*)(?:\?(.*))$/; + +$env{PATH_INFO} = $path; +$env{QUERY_STRING} = $query; + +my $socket; + +if( $connect =~ m/^unix:(.*)$/ ) { + my $path = $1; + + require IO::Socket::UNIX; + + $socket = IO::Socket::UNIX->new( + Peer => $path, + ) or die "Cannot connect - $!\n"; +} +elsif( $connect =~ m/^exec:(.*)$/ ) { + my $script = $1; + + require IO::Socket::INET; + + my $listener = IO::Socket::INET->new( + LocalHost => "localhost", + Listen => 1, + ) or die "Cannot listen - $@"; + + defined( my $kid = fork ) or die "Cannot fork - $!"; + END { defined $kid and kill TERM => $kid } + + if( $kid == 0 ) { + close STDIN; + open STDIN, "<&", $listener or die "Cannot dup $listener to STDIN - $!"; + + close $listener; + + exec { $script } $script or die "Cannot exec $script - $!"; + } + + $socket = IO::Socket::INET->new( + PeerHost => $listener->sockhost, + PeerPort => $listener->sockport, + ) or die "Cannot connect - $@"; + + close $listener; +} +elsif( $connect =~ m/^(?:tcp:)?(.*):(.+?)$/ ) { + my $host = $1 || "localhost"; + my $port = $2; + + my $class = eval { require IO::Socket::IP and "IO::Socket::IP" } || + do { require IO::Socket::INET and "IO::Socket::INET" }; + + $socket = $class->new( + PeerHost => $host, + PeerPort => $port, + ) or die "Cannot connect - $@\n"; +} +else { + die "Cannot recognise connection string '$connect'\n"; +} + +write_record( $socket, FCGI_BEGIN_REQUEST, 1, + build_begin_request_body( FCGI_RESPONDER, 0 ) ); + +write_record( $socket, FCGI_PARAMS, 1, + build_params( \%env ) ); + +write_record( $socket, FCGI_PARAMS, 1, "" ); + +if( defined $stdin_from ) { + my $stdin; + + if( $stdin_from eq "-" ) { + $stdin = \*STDIN; + } + else { + open $stdin, "<", $stdin_from or die "Cannot open $stdin_from for input - $!"; + } + + while( read( $stdin, my $buffer, 8192 ) ) { + write_record( $socket, FCGI_STDIN, 1, $buffer ); + } +} + +write_record( $socket, FCGI_STDIN, 1, "" ); + +my $stdout = ""; + +while(1) { + my ( $type, $id, $content ) = read_record( $socket ) + or $! and die "Cannot read_record - $!" + or last; + + if( $type == FCGI_STDOUT ) { + if( !defined $filter_stdout ) { + print STDOUT $content; + } + elsif( $filter_stdout eq "headers" ) { + my $oldlen = length $stdout; + $stdout .= $content; + if( $stdout =~ m/\r\n\r\n/ ) { + # Print only the bit we haven't done yet + print STDOUT substr( $stdout, $oldlen, $+[0] - $oldlen ); + $filter_stdout = 1; # I.e. suppress the lot + } + else { + print STDOUT $content; + } + } + elsif( $filter_stdout eq "body" ) { + $stdout .= $content; + if( $stdout =~ m/\r\n\r\n/ ) { + print STDOUT substr( $stdout, $+[0] ); + $filter_stdout = undef; + } + } + } + elsif( $type == FCGI_STDERR ) { + print STDERR $content; + } + elsif( $type == FCGI_END_REQUEST ) { + my ( $app_status, $protocol_status ) = parse_end_request_body( $content ); + exit $app_status; + } + else { + die "Unrecognised FastCGI request type $type\n"; + } +} diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/eg/server.pl b/debian/vendor-h2o/misc/p5-net-fastcgi/eg/server.pl new file mode 100755 index 0000000..74a8db7 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/eg/server.pl @@ -0,0 +1,164 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use IO::Socket qw[]; +use PerlIO::scalar qw[]; +use Net::FastCGI::Constant qw[:type :role :flag :protocol_status FCGI_NULL_REQUEST_ID]; +use Net::FastCGI::IO qw[read_record write_record write_stream]; +use Net::FastCGI::Protocol qw[build_end_request_body + build_unknown_type_body + build_params + parse_begin_request_body + parse_params + dump_record_body ]; + +my %FCGI_VALUES = ( + FCGI_MAX_CONNS => 1, # maximum number of concurrent transport connections this application will accept + FCGI_MAX_REQS => 1, # maximum number of concurrent requests this application will accept + FCGI_MPXS_CONNS => 0, # multiplex +); + +sub handle_connection { + my ($socket, $on_request) = @_; + + my ( $current_id, # id of the request we are currently processing + $stdin, # buffer for stdin + $stdout, # buffer for stdout + $stderr, # buffer for stderr + $params, # buffer for params (environ) + $keep_conn ); # more requests on this connection? + + ($current_id, $stdin, $stdout, $stderr, $params) = (0, '', '', '', '', ''); + + use warnings FATAL => 'Net::FastCGI::IO'; + + while () { + my ($type, $request_id, $content) = read_record($socket) + or last; + + if ($request_id == FCGI_NULL_REQUEST_ID) { + if ($type == FCGI_GET_VALUES) { + my $values = parse_params($content); + my %params = map { $_ => $FCGI_VALUES{$_} } + grep { exists $FCGI_VALUES{$_} } + keys %{$values}; + write_record($socket, FCGI_GET_VALUES_RESULT, + FCGI_NULL_REQUEST_ID, build_params(\%params)); + } + else { + write_record($socket, FCGI_UNKNOWN_TYPE, + FCGI_NULL_REQUEST_ID, build_unknown_type_body($type)); + } + } + elsif ($type == FCGI_BEGIN_REQUEST) { + my ($role, $flags) = parse_begin_request_body($content); + if ($current_id || $role != FCGI_RESPONDER) { + my $status = $current_id ? FCGI_CANT_MPX_CONN : FCGI_UNKNOWN_ROLE; + write_record($socket, FCGI_END_REQUEST, $request_id, + build_end_request_body(0, $status)); + } + else { + $current_id = $request_id; + $keep_conn = ($flags & FCGI_KEEP_CONN); + } + } + elsif ($request_id != $current_id) { + # ignore inactive requests (FastCGI Specification 3.3) + } + elsif ($type == FCGI_ABORT_REQUEST) { + $current_id = 0; + ($stdin, $stdout, $stderr, $params) = ('', '', '', ''); + } + elsif ($type == FCGI_PARAMS) { + $params .= $content; + } + elsif ($type == FCGI_STDIN) { + $stdin .= $content; + + unless (length $content) { + # process request + + open(my $in, '<', \$stdin) + || die(qq/Couldn't open scalar as a file handle: $!/); + + open(my $out, '>', \$stdout) + || die(qq/Couldn't open scalar as a file handle: $!/); + + open(my $err, '>', \$stderr) + || die(qq/Couldn't open scalar as a file handle: $!/); + + my $environ = parse_params($params); + + eval { + $on_request->($environ, $in, $out, $err); + }; + + if (my $e = $@) { + warn(qq/Caught an exception in request callback: '$e'/); + $stdout = "Status: 500 Internal Server Error\n\n"; + } + + write_stream($socket, FCGI_STDOUT, $current_id, $stdout, 1); + write_stream($socket, FCGI_STDERR, $current_id, $stderr, 1) + if length $stderr; + write_record($socket, FCGI_END_REQUEST, $current_id, + build_end_request_body(0, FCGI_REQUEST_COMPLETE)); + + # prepare for next request + $current_id = 0; + ($stdin, $stdout, $stderr, $params) = ('', '', '', ''); + + last unless $keep_conn; + } + } + else { + warn(q/Received an unexpected record: / . + dump_record_body($type, $request_id, $content)); + } + } + + (!$current_id) + || warn(q/Client prematurely closed connection/); +} + +sub handle_request { + my ($env, $stdin, $stdout, $stderr) = @_; + + $env->{GATEWAY_INTERFACE} ||= 'CGI/1.1'; + + local *ENV = $env; + local *STDIN = $stdin; + local *STDOUT = $stdout; + local *STDERR = $stderr; + + print "Status: 200 OK\n"; + print "Content-Type: text/plain\n\n"; + print map { sprintf "%-25s => %s\n", $_, $ENV{$_} } sort keys %ENV; +} + +my $addr = shift(@ARGV) || 'localhost:3000'; + +my $socket = IO::Socket::INET->new( + Listen => 5, + LocalAddr => $addr, + Reuse => 1, +) or die(qq/Couldn't create INET listener socket <$addr>: '$!'./); + +print STDERR "Listening for connections on <$addr>\n"; + +while () { + my $connection = $socket->accept + or last; + + eval { + handle_connection($connection, \&handle_request); + }; + + if (my $e = $@) { + warn(qq/Caught an exception in handle_connection(): '$e'/); + } + + close $connection; +} + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pm b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pm new file mode 100644 index 0000000..4126b21 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pm @@ -0,0 +1,12 @@ +package Net::FastCGI; + +use strict; +use warnings; + +our $VERSION = '0.14'; + +use Net::FastCGI::Constant; +use Net::FastCGI::Protocol; + +1; + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pod b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pod new file mode 100644 index 0000000..65725b9 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI.pod @@ -0,0 +1,170 @@ +=head1 NAME + +Net::FastCGI - FastCGI Toolkit + +=head1 DESCRIPTION + +This distribution aims to provide a complete API for working with the FastCGI +protocol. + +The primary goal is to provide a function oriented and object oriented API which +are not tied to a specific I/O model or framework. + +Secondary goal is to provide higher level tools/API which can be used for debugging +and interoperability testing. + +=head1 PROGRESS + +The function oriented API is considered feature complete. L +provides functions to build and parse all FastCGI v1.0 messages, also provided is a +few convenient higher level functions such as C, +C, C and C. + +Work has begun on object oriented implementation and a simple blocking I/O class which is +intended for testing and debugging. + +=head1 PACKAGES + +=over 4 + +=item L + +FastCGI protocol constants. + +=item L + +Provides functions to read and write FastCGI messages. + +=item L + +Provides functions to build and parse FastCGI messages. + +=back + +=head1 ENVIRONMENT + +Environment variable C can be set to a true value before loading +this package to disable usage of XS implementation. + +=head1 PREREQUISITES + +=head2 Run-Time + +=over 4 + +=item L 5.6 or greater. + +=item L, core module. + +=item L, core module. + +=back + +=head2 Build-Time + +In addition to Run-Time: + +=over 4 + +=item L 0.47 or greater, core module since 5.6.2. + +=item L. + +=item L. + +=back + +=head1 SEE ALSO + +=head2 Community + +=over 4 + +=item Official FastCGI site + +L + +=back + +=head2 Standards + +=over 4 + +=item FastCGI Specification Version 1.0 + +L + +=item RFC 3875 - The Common Gateway Interface (CGI) Version 1.1 + +L + +=back + +=head2 White papers + +=over 4 + +=item FastCGI: A High-Performance Web Server Interface + +L + +=item FastCGI - The Forgotten Treasure + +L + +=back + +=head2 Perl implementations + +=over 4 + +=item L + +Application server implementation, built on top of L. Supports Responder role. +Capable of multiplexing. + +=item L + +Application server implementation, built on top of C (reference implementation). +Supports all FastCGI roles. Responds to management records. Processes requests synchronously. + +=item L + +Application server implementation, built on top of L. Supports Responder role. +Responds to management records. Capable of multiplexing. + +=item L + +Client (Web server) implementation. Supports Responder role. + +=item L + +Application server implementation, built on top of L. Supports Responder role. + +=item L + +Application server implementation. Supports Responder role. Processes requests synchronously. + +=item L + +Application server implementation, built on top of L. Supports Responder role. +Capable of multiplexing. + +=back + +=head1 SUPPORT + +Please report any bugs or feature requests to C, or through +the web interface at L + +=head1 AUTHOR + +Christian Hansen C + +=head1 COPYRIGHT + +Copyright 2008-2010 by Christian Hansen. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pm b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pm new file mode 100644 index 0000000..1e86dbf --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pm @@ -0,0 +1,179 @@ +package Net::FastCGI::Constant; + +use strict; +use warnings; + +BEGIN { + our $VERSION = '0.14'; + my @common = qw[ FCGI_MAX_CONTENT_LEN + FCGI_MAX_LEN + FCGI_HEADER_LEN + FCGI_VERSION_1 + FCGI_NULL_REQUEST_ID ]; + + my @type = qw[ 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 ]; + + my @role = qw[ FCGI_RESPONDER + FCGI_AUTHORIZER + FCGI_FILTER ]; + + my @flag = qw[ FCGI_KEEP_CONN ]; + + my @protocol_status = qw[ FCGI_REQUEST_COMPLETE + FCGI_CANT_MPX_CONN + FCGI_OVERLOADED + FCGI_UNKNOWN_ROLE ]; + + my @value = qw[ FCGI_MAX_CONNS + FCGI_MAX_REQS + FCGI_MPXS_CONNS ]; + + my @pack = qw[ FCGI_Header + FCGI_BeginRequestBody + FCGI_EndRequestBody + FCGI_UnknownTypeBody ]; + + my @name = qw[ @FCGI_TYPE_NAME + @FCGI_RECORD_NAME + @FCGI_ROLE_NAME + @FCGI_PROTOCOL_STATUS_NAME ]; + + our @EXPORT_OK = ( @common, + @type, + @role, + @flag, + @protocol_status, + @value, + @pack, + @name ); + + our %EXPORT_TAGS = ( all => \@EXPORT_OK, + common => \@common, + type => \@type, + role => \@role, + flag => \@flag, + protocol_status => \@protocol_status, + value => \@value, + pack => \@pack ); + + our @FCGI_TYPE_NAME = ( + undef, # 0 + 'FCGI_BEGIN_REQUEST', # 1 + 'FCGI_ABORT_REQUEST', # 2 + 'FCGI_END_REQUEST', # 3 + 'FCGI_PARAMS', # 4 + 'FCGI_STDIN', # 5 + 'FCGI_STDOUT', # 6 + 'FCGI_STDERR', # 7 + 'FCGI_DATA', # 8 + 'FCGI_GET_VALUES', # 9 + 'FCGI_GET_VALUES_RESULT', # 10 + 'FCGI_UNKNOWN_TYPE' # 11 + ); + + our @FCGI_RECORD_NAME = ( + undef, # 0 + 'FCGI_BeginRequestRecord', # 1 + 'FCGI_AbortRequestRecord', # 2 + 'FCGI_EndRequestRecord', # 3 + 'FCGI_ParamsRecord', # 4 + 'FCGI_StdinRecord', # 5 + 'FCGI_StdoutRecord', # 6 + 'FCGI_StderrRecord', # 7 + 'FCGI_DataRecord', # 8 + 'FCGI_GetValuesRecord', # 9 + 'FCGI_GetValuesResultRecord', # 10 + 'FCGI_UnknownTypeRecord', # 11 + ); + + our @FCGI_ROLE_NAME = ( + undef, # 0 + 'FCGI_RESPONDER', # 1 + 'FCGI_AUTHORIZER', # 2 + 'FCGI_FILTER', # 3 + ); + + our @FCGI_PROTOCOL_STATUS_NAME = ( + 'FCGI_REQUEST_COMPLETE', # 0 + 'FCGI_CANT_MPX_CONN', # 1 + 'FCGI_OVERLOADED', # 2 + 'FCGI_UNKNOWN_ROLE', # 3 + ); + + if (Internals->can('SvREADONLY')) { # 5.8 + Internals::SvREADONLY(@FCGI_TYPE_NAME, 1); + Internals::SvREADONLY(@FCGI_RECORD_NAME, 1); + Internals::SvREADONLY(@FCGI_ROLE_NAME, 1); + Internals::SvREADONLY(@FCGI_PROTOCOL_STATUS_NAME, 1); + Internals::SvREADONLY($_, 1) for @FCGI_TYPE_NAME, + @FCGI_RECORD_NAME, + @FCGI_ROLE_NAME, + @FCGI_PROTOCOL_STATUS_NAME; + } + + require Exporter; + *import = \&Exporter::import; +} + + +sub FCGI_LISTENSOCK_FILENO () { 0 } + +# common +sub FCGI_MAX_CONTENT_LEN () { 0xFFFF } +sub FCGI_MAX_LEN () { 0xFFFF } # deprecated +sub FCGI_HEADER_LEN () { 8 } +sub FCGI_VERSION_1 () { 1 } +sub FCGI_NULL_REQUEST_ID () { 0 } + +# type +sub FCGI_BEGIN_REQUEST () { 1 } +sub FCGI_ABORT_REQUEST () { 2 } +sub FCGI_END_REQUEST () { 3 } +sub FCGI_PARAMS () { 4 } +sub FCGI_STDIN () { 5 } +sub FCGI_STDOUT () { 6 } +sub FCGI_STDERR () { 7 } +sub FCGI_DATA () { 8 } +sub FCGI_GET_VALUES () { 9 } +sub FCGI_GET_VALUES_RESULT () { 10 } +sub FCGI_UNKNOWN_TYPE () { 11 } +sub FCGI_MAXTYPE () { FCGI_UNKNOWN_TYPE } + +# role +sub FCGI_RESPONDER () { 1 } +sub FCGI_AUTHORIZER () { 2 } +sub FCGI_FILTER () { 3 } + +# flags +sub FCGI_KEEP_CONN () { 1 } + +# protocol status +sub FCGI_REQUEST_COMPLETE () { 0 } +sub FCGI_CANT_MPX_CONN () { 1 } +sub FCGI_OVERLOADED () { 2 } +sub FCGI_UNKNOWN_ROLE () { 3 } + +# value +sub FCGI_MAX_CONNS () { 'FCGI_MAX_CONNS' } +sub FCGI_MAX_REQS () { 'FCGI_MAX_REQS' } +sub FCGI_MPXS_CONNS () { 'FCGI_MPXS_CONNS' } + +# pack +sub FCGI_Header () { 'CCnnCx' } +sub FCGI_BeginRequestBody () { 'nCx5' } +sub FCGI_EndRequestBody () { 'NCx3' } +sub FCGI_UnknownTypeBody () { 'Cx7' } + +1; + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pod b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pod new file mode 100644 index 0000000..d0ca04c --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Constant.pod @@ -0,0 +1,264 @@ +=head1 NAME + +Net::FastCGI::Constant - FastCGI protocol constants. + +=head1 DESCRIPTION + +FastCGI protocol constants. + +=head1 CONSTANTS + +Constants can either be imported individually or in sets grouped by tag names. +The tag names are: + +=head2 C<:common> + +=over 4 + +=item C + +Maximum number of octets that the content component of the record can hold. (C<65535>) + +=item C + +Number of octets in C. (C<8>) + +=item C + +Value for C component of C. (C<1>) + +=item C + +Value for C component of C. (C<0>) + +=back + +=head2 C<:type> + +Values for C component of C. + +=over 4 + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=item C + +=back + +=head2 C<:flag> + +Mask for C component of C. + +=over 4 + +=item C + +=back + +=head2 C<:role> + +Values for C component of C. + +=over 4 + +=item C + +=item C + +=item C + +=back + +=head2 C<:protocol_status> + +Values for C component of C. + +=over 4 + +=item C + +=item C + +=item C + +=item C + +=back + +=head2 C<:value> + +Variable names for C / C records. + +=over 4 + +=item C + +=item C + +=item C + +=back + +=head2 C<:pack> + +C / C templates + +=over 4 + +=item C + + Octet/ 0 | 1 | + / | | + | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | + +-----------------+-----------------+ + 0 | Version | Type | + +-----------------+-----------------+ + 2 | Request ID | + +-----------------+-----------------+ + 4 | Content Length | + +-----------------+-----------------+ + 6 | Padding Length | Reserved | + +-----------------+-----------------+ + Total 8 octets + + Template: CCnnCx + + my ($version, $type, $request_id, $content_length, $padding_length) + = unpack(FCGI_Header, $octets); + +=item C + + Octet/ 0 | 1 | + / | | + | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | + +-----------------+-----------------+ + 0 | Role | + +-----------------+-----------------+ + 2 | Flags | | + +-----------------+ + + 4 | | + + Reserved + + 6 | | + +-----------------+-----------------+ + Total 8 octets + + Template: nCx5 + + my ($role, $flags) = unpack(FCGI_BeginRequestBody, $octets); + +=item C + + Octet/ 0 | 1 | + / | | + | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | + +-----------------+-----------------+ + 0 | | + + Application Status + + 2 | | + +-----------------+-----------------+ + 4 | Protocol Status | | + +-----------------+ Reserved + + 6 | | + +-----------------+-----------------+ + Total 8 octets + + Template: NCx3 + + my ($app_status, $protocol_status) + = unpack(FCGI_EndRequestBody, $octets); + +=item C + + Octet/ 0 | 1 | + / | | + | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | + +-----------------+-----------------+ + 0 | Unknown Type | | + +-----------------+ + + 2 | | + + + + 4 | Reserved | + + + + 6 | | + +-----------------+-----------------+ + Total 8 octets + + Template: Cx7 + + my $unknown_type = unpack(FCGI_UnknownTypeBody, $octets); + +=back + +=head2 C<:name> + +Arrays containing names of value components. These are read-only. + +=over 4 + +=item C<@FCGI_TYPE_NAME> + + print $FCGI_TYPE_NAME[FCGI_BEGIN_REQUEST]; # FCGI_BEGIN_REQUEST + +=item C<@FCGI_ROLE_NAME> + + print $FCGI_ROLE_NAME[FCGI_RESPONDER]; # FCGI_RESPONDER + +=item C<@FCGI_PROTOCOL_STATUS_NAME> + + print $FCGI_PROTOCOL_STATUS_NAME[FCGI_OVERLOADED]; # FCGI_OVERLOADED + +=back + +I + +It's not safe to assume that C works for validation purposes, index C<0> +might be C. + +Use boolean context instead: + + ($FCGI_TYPE_NAME[$type]) + || die; + +=head1 EXPORTS + +None by default. All functions can be exported using the C<:all> tag or individually. + +=head1 SEE ALSO + +=over 4 + +=item L + +=back + +=head1 AUTHOR + +Christian Hansen C + +=head1 COPYRIGHT + +Copyright 2008-2010 by Christian Hansen. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pm b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pm new file mode 100644 index 0000000..15583fb --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pm @@ -0,0 +1,227 @@ +package Net::FastCGI::IO; +use strict; +use warnings; +use warnings::register; + +use Carp qw[]; +use Errno qw[EBADF EINTR EPIPE]; +use Net::FastCGI::Constant qw[FCGI_HEADER_LEN]; +use Net::FastCGI::Protocol qw[build_header build_record build_stream + parse_header parse_record]; + +BEGIN { + our $VERSION = '0.14'; + our @EXPORT_OK = qw[ can_read + can_write + read_header + read_record + write_header + write_record + write_stream ]; + + our %EXPORT_TAGS = ( all => \@EXPORT_OK ); + + require Exporter; + *import = \&Exporter::import; + + eval q; +} + +*throw = \&Carp::croak; + +sub read_header { + @_ == 1 || throw(q/Usage: read_header(fh)/); + my ($fh) = @_; + + my $len = FCGI_HEADER_LEN; + my $off = 0; + my $buf; + + while ($len) { + my $r = sysread($fh, $buf, $len, $off); + if (defined $r) { + last unless $r; + $len -= $r; + $off += $r; + } + elsif ($! != EINTR) { + warnings::warn(qq) + if warnings::enabled; + return; + } + } + if ($len) { + $! = $off ? EPIPE : 0; + warnings::warn(q) + if $off && warnings::enabled; + return; + } + return parse_header($buf); +} + +sub write_header { + @_ == 5 || throw(q/Usage: write_header(fh, type, request_id, content_length, padding_length)/); + my $fh = shift; + + my $buf = &build_header; + my $len = FCGI_HEADER_LEN; + my $off = 0; + + while () { + my $r = syswrite($fh, $buf, $len, $off); + if (defined $r) { + $len -= $r; + $off += $r; + last unless $len; + } + elsif ($! != EINTR) { + warnings::warn(qq) + if warnings::enabled; + return undef; + } + } + return $off; +} + +sub read_record { + @_ == 1 || throw(q/Usage: read_record(fh)/); + my ($fh) = @_; + + my $len = FCGI_HEADER_LEN; + my $off = 0; + my $buf; + + while ($len) { + my $r = sysread($fh, $buf, $len, $off); + if (defined $r) { + last unless $r; + $len -= $r; + $off += $r; + if (!$len && $off == FCGI_HEADER_LEN) { + $len = vec($buf, 2, 16) # Content Length + + vec($buf, 6, 8); # Padding Length + } + } + elsif ($! != EINTR) { + warnings::warn(qq) + if warnings::enabled; + return; + } + } + if ($len) { + $! = $off ? EPIPE : 0; + warnings::warn(q) + if $off && warnings::enabled; + return; + } + return parse_record($buf); +} + +sub write_record { + @_ == 4 || @_ == 5 || throw(q/Usage: write_record(fh, type, request_id [, content])/); + my $fh = shift; + + my $buf = &build_record; + my $len = length $buf; + my $off = 0; + + while () { + my $r = syswrite($fh, $buf, $len, $off); + if (defined $r) { + $len -= $r; + $off += $r; + last unless $len; + } + elsif ($! != EINTR) { + warnings::warn(qq) + if warnings::enabled; + return undef; + } + } + return $off; +} + +sub write_stream { + @_ == 4 || @_ == 5 || throw(q/Usage: write_stream(fh, type, request_id, content [, terminate])/); + my $fh = shift; + + my $buf = &build_stream; + my $len = length $buf; + my $off = 0; + + while () { + my $r = syswrite($fh, $buf, $len, $off); + if (defined $r) { + $len -= $r; + $off += $r; + last unless $len; + } + elsif ($! != EINTR) { + warnings::warn(qq) + if warnings::enabled; + return undef; + } + } + return $off; +} + +sub can_read (*$) { + @_ == 2 || throw(q/Usage: can_read(fh, timeout)/); + my ($fh, $timeout) = @_; + + my $fd = fileno($fh); + unless (defined $fd && $fd >= 0) { + $! = EBADF; + return undef; + } + + my $initial = time; + my $pending = $timeout; + my $nfound; + + vec(my $fdset = '', $fd, 1) = 1; + + while () { + $nfound = select($fdset, undef, undef, $pending); + if ($nfound == -1) { + return undef unless $! == EINTR; + redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0; + $nfound = 0; + } + last; + } + $! = 0; + return $nfound; +} + +sub can_write (*$) { + @_ == 2 || throw(q/Usage: can_write(fh, timeout)/); + my ($fh, $timeout) = @_; + + my $fd = fileno($fh); + unless (defined $fd && $fd >= 0) { + $! = EBADF; + return undef; + } + + my $initial = time; + my $pending = $timeout; + my $nfound; + + vec(my $fdset = '', $fd, 1) = 1; + + while () { + $nfound = select(undef, $fdset, undef, $pending); + if ($nfound == -1) { + return undef unless $! == EINTR; + redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0; + $nfound = 0; + } + last; + } + $! = 0; + return $nfound; +} + +1; + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pod b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pod new file mode 100644 index 0000000..84a9f09 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/IO.pod @@ -0,0 +1,391 @@ +=head1 NAME + +Net::FastCGI::IO - Provides functions to read and write FastCGI messages. + +=head1 SYNOPSIS + + # FCGI_Header + @values = read_header($fh); + $header = read_header($fh); + $result = write_header($fh, $type, $request_id, $content_length, $padding_length); + + # FCGI_Record + @values = read_record($fh); + $record = read_record($fh); + $result = write_record($fh, $type, $request_id); + $result = write_record($fh, $type, $request_id, $content); + + # FCGI_Record Stream + $result = write_stream($fh, $type, $request_id, $content); + $result = write_stream($fh, $type, $request_id, $content, $terminate); + + # I/O ready + $result = can_read($fh, $timeout); + $result = can_write($fh, $timeout); + +=head1 DESCRIPTION + +Provides unbuffered blocking I/O functions to read and write FastCGI messages. + +=head1 FUNCTIONS + +=head2 read_header + +Attempts to read a C from file handle C<$fh>. + +I + + ($type, $request_id, $content_length, $padding_length) + = read_header($fh); + + $header = read_header($fh); + say $header->{type}; + say $header->{request_id}; + say $header->{content_length}; + say $header->{padding_length}; + +I + +=over 4 + +=item C<$fh> + +The file handle to read from. Must be a file handle with a file descriptor. File handle +mode should be set to binary. + +=back + +I + +Upon successful completion, the return value of L. +Otherwise, a false value (C in scalar context and an empty list in list context). + +If C reaches end-of-file before reading any octets, it returns a +false value. If unsuccessful, C returns a false value and C<$!> +contains the error from the C call. If C encounters +end-of-file after some but not all of the needed octets, the function returns +a false value and sets C<$!> to C. + +I + +The implementation calls C in a loop, restarting if C +returns C with C<$!> set to C. If C does not provide +all the requested octets, C continues to call C until +either all the octets have been read, reaches end-of-file or an error occurs. + +=head2 read_record + +Attempts to read a C from file handle C<$fh>. + +I + + ($type, $request_id, $content) + = read_record($fh); + + $record = read_record($fh); + say $record->{type}; + say $record->{request_id}; + +I + +=over 4 + +=item C<$fh> + +The file handle to read from. Must be a file handle with a file descriptor. +File handle mode should be set to binary. + +=back + +I + +Upon successful completion, the return value of L. +Otherwise, a false value (C in scalar context and an empty list in list context). + +If C reaches end-of-file before reading any octets, it returns a +false value. If unsuccessful, C returns a false value and C<$!> +contains the error from the C call. If C encounters +end-of-file after some but not all of the needed octets, the function returns +a false value and sets C<$!> to C. + +I + +The implementation calls C in a loop, restarting if C +returns C with C<$!> set to C. If C does not provide +all the requested octets, C continues to call C until +either all the octets have been read, reaches end-of-file or an error occurs. + +=head2 write_header + +Attempts to write a C to file handle C<$fh>. + +I + + $result = write_header($fh, $type, $request_id, $content_length, $padding_length); + +I + +=over 4 + +=item C<$fh> + +The file handle to write to. Must be a file handle with a file descriptor. File handle +mode should be set to binary. + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content_length> + +An unsigned 16-bit integer. + +=item C<$padding_length> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$result> + +Upon successful completion, the number of octets actually written. Otherwise, +C and C<$!> contains the error from the C call. + +=back + +I + +The implementation calls C in a loop, restarting if C +returns C with C<$!> set to C. If C does not output +all the requested octets, C continues to call C until +all the octets have been written or an error occurs. + +=head2 write_record + +Attempts to write a C to file handle C<$fh>. + +I + + $result = write_record($fh, $type, $request_id); + $result = write_record($fh, $type, $request_id, $content); + +I + +=over 4 + +=item C<$fh> + +The file handle to write to. Must be a file handle with a file descriptor. File handle +mode should be set to binary. + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> (optional) + +A string of octets containing the content, cannot exceed 65535 octets in length. + +=back + +I + +=over 4 + +=item C<$result> + +Upon successful completion, the number of octets actually written. Otherwise, +C and C<$!> contains the error from the C call. + +=back + +I + +The implementation calls C in a loop, restarting if C +returns C with C<$!> set to C. If C does not output +all the requested octets, C continues to call C until +all the octets have been written or an error occurs. + +=head2 write_stream + +Attempts to write a C stream to file handle C<$fh>. + +I + + $result = write_stream($fh, $type, $request_id, $content); + $result = write_stream($fh, $type, $request_id, $content, $terminate); + +I + +=over 4 + +=item C<$fh> + +The file handle to write to. Must be a file handle with a file descriptor. File handle +mode should be set to binary. + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> + +A string of octets containing the stream content. + +=item C<$terminate> (optional) + +A boolean indicating whether or not the stream should be terminated. +Defaults to false. + +=back + +I + +=over 4 + +=item C<$result> + +Upon successful completion, the number of octets actually written. Otherwise, +C and C<$!> contains the error from the C call. + +=back + +I + +The implementation calls C in a loop, restarting if C +returns C with C<$!> set to C. If C does not output +all the requested octets, C continues to call C until +all the octets have been written or an error occurs. + +=head2 can_read + +Determines wheter or not the given file handle C<$fh> is ready for reading +within the given timeout C<$timeout>. + +I + + $result = can_read($fh, $timeout); + +I + +=over 4 + +=item C<$fh> + +The file handle to test for readiness. Must be a file handle with a file descriptor. + +=item C<$timeout> + +Maximum interval to wait. Can be set to either a non-negative numeric value or +C for infinite wait. + +=back + +I + +Upon successful completion, C<0> or C<1>. Otherwise, C and C<$!> contains +the C in a loop, restarting if C error. + +I + +The implementation calls C returns +C<-1> with C<$!> set to C and C<$timeout> has not elapsed. + +=head1 EXPORTS + +None by default. All functions can be exported using the C<:all> tag or individually. + +=head1 DIAGNOSTICS + +=over 4 + +=item B<(F)> Usage: %s + +Subroutine called with wrong number of arguments. + +=item B<(W Net::FastCGI::IO)> FastCGI: Could not read %s + +=item B<(W Net::FastCGI::IO)> FastCGI: Could not write %s + +=back + +=head1 SEE ALSO + +=over 4 + +=item FastCGI Specification Version 1.0 + +L + +=item The Common Gateway Interface (CGI) Version 1.1 + +L + +=item L + +=item L + +=back + +=head1 AUTHOR + +Christian Hansen C + +=head1 COPYRIGHT + +Copyright 2008-2010 by Christian Hansen. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pm b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pm new file mode 100644 index 0000000..0c4210e --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pm @@ -0,0 +1,203 @@ +package Net::FastCGI::Protocol; + +use strict; +use warnings; + +use Carp qw[croak]; +use Net::FastCGI qw[]; +use Net::FastCGI::Constant qw[:type :common FCGI_KEEP_CONN]; + +BEGIN { + our $VERSION = '0.14'; + our @EXPORT_OK = qw[ build_begin_request + build_begin_request_body + build_begin_request_record + build_end_request + build_end_request_body + build_end_request_record + build_header + build_params + build_record + build_stream + build_unknown_type_body + build_unknown_type_record + check_params + parse_begin_request_body + parse_end_request_body + parse_header + parse_params + parse_record + parse_record_body + parse_unknown_type_body + get_record_length + get_type_name + get_role_name + get_protocol_status_name + is_known_type + is_management_type + is_discrete_type + is_stream_type ]; + + our %EXPORT_TAGS = ( all => \@EXPORT_OK ); + + my $use_pp = $ENV{NET_FASTCGI_PP} || $ENV{NET_FASTCGI_PROTOCOL_PP}; + + if (!$use_pp) { + eval { + require Net::FastCGI::Protocol::XS; + }; + $use_pp = !!$@; + } + + if ($use_pp) { + require Net::FastCGI::Protocol::PP; + Net::FastCGI::Protocol::PP->import(@EXPORT_OK); + } + else { + Net::FastCGI::Protocol::XS->import(@EXPORT_OK); + } + + # shared between XS and PP implementation + push @EXPORT_OK, 'dump_record', 'dump_record_body'; + + require Exporter; + *import = \&Exporter::import; +} + +our $DUMP_RECORD_MAX = 78; # undocumented +our $DUMP_RECORD_ALIGN = !!0; # undocumented + +my %ESCAPES = ( + "\a" => "\\a", + "\b" => "\\b", + "\t" => "\\t", + "\n" => "\\n", + "\f" => "\\f", + "\r" => "\\r", +); + +sub dump_record { + goto \&dump_record_body if (@_ == 2 || @_ == 3); # deprecated + @_ == 1 || croak(q/Usage: dump_record(octets)/); + + my $len = &get_record_length; + ($len && $len <= length $_[0] && vec($_[0], 0, 8) == FCGI_VERSION_1) + || return '{Malformed FCGI_Record}'; + + return dump_record_body(&parse_record); +} + +sub dump_record_body { + @_ == 2 || @_ == 3 || croak(q/Usage: dump_record_body(type, request_id [, content])/); + my ($type, $request_id) = @_; + + my $content_length = defined $_[2] ? length $_[2] : 0; + + my $max = $DUMP_RECORD_MAX > 0 ? $DUMP_RECORD_MAX : FCGI_MAX_CONTENT_LEN; + my $out = ''; + + if ( $type == FCGI_PARAMS + || $type == FCGI_GET_VALUES + || $type == FCGI_GET_VALUES_RESULT) { + if ($content_length == 0) { + $out = q[""]; + } + elsif (check_params($_[2])) { + my ($off, $klen, $vlen) = (0); + while ($off < $content_length) { + my $pos = $off; + for ($klen, $vlen) { + $_ = vec($_[2], $off, 8); + $_ = vec(substr($_[2], $off, 4), 0, 32) & 0x7FFF_FFFF + if $_ > 0x7F; + $off += $_ > 0x7F ? 4 : 1; + } + + my $head = substr($_[2], $pos, $off - $pos); + $head =~ s/(.)/sprintf('\\%.3o',ord($1))/egs; + $out .= $head; + + my $body = substr($_[2], $off, $klen + $vlen); + for ($body) { + s/([\\\"])/\\$1/g; + s/([\a\b\t\n\f\r])/$ESCAPES{$1}/g; + s/([^\x20-\x7E])/sprintf('\\x%.2X',ord($1))/eg; + } + $out .= $body; + $off += $klen + $vlen; + last if $off > $max; + } + substr($out, $max - 5) = ' ... ' + if length $out > $max; + $out = qq["$out"]; + } + else { + $out = 'Malformed FCGI_NameValuePair(s)'; + } + } + elsif ( $type == FCGI_BEGIN_REQUEST + || $type == FCGI_END_REQUEST + || $type == FCGI_UNKNOWN_TYPE) { + if ($content_length != 8) { + my $name = $type == FCGI_BEGIN_REQUEST ? 'FCGI_BeginRequestBody' + : $type == FCGI_END_REQUEST ? 'FCGI_EndRequestBody' + : 'FCGI_UnknownTypeBody'; + $out = sprintf '{Malformed %s (expected 8 octets got %d)}', $name, $content_length; + } + elsif ($type == FCGI_BEGIN_REQUEST) { + my ($role, $flags) = parse_begin_request_body($_[2]); + if ($flags != 0) { + my @set; + if ($flags & FCGI_KEEP_CONN) { + $flags &= ~FCGI_KEEP_CONN; + push @set, 'FCGI_KEEP_CONN'; + } + if ($flags) { + push @set, sprintf '0x%.2X', $flags; + } + $flags = join '|', @set; + } + $out = sprintf '{%s, %s}', get_role_name($role), $flags; + } + elsif($type == FCGI_END_REQUEST) { + my ($astatus, $pstatus) = parse_end_request_body($_[2]); + $out = sprintf '{%d, %s}', $astatus, get_protocol_status_name($pstatus); + } + else { + my $unknown_type = parse_unknown_type_body($_[2]); + $out = sprintf '{%s}', get_type_name($unknown_type); + } + } + elsif ($content_length) { + my $looks_like_binary = do { + my $count = () = $_[2] =~ /[\r\n\t\x20-\x7E]/g; + ($count / $content_length) < 0.7; + }; + $out = substr($_[2], 0, $max + 1); + for ($out) { + if ($looks_like_binary) { + s/(.)/sprintf('\\x%.2X',ord($1))/egs; + } + else { + s/([\\\"])/\\$1/g; + s/([\a\b\t\n\f\r])/$ESCAPES{$1}/g; + s/([^\x20-\x7E])/sprintf('\\x%.2X',ord($1))/eg; + } + } + substr($out, $max - 5) = ' ... ' + if length $out > $max; + $out = qq["$out"]; + } + else { + $out = q[""]; + } + + my $name = get_type_name($type); + my $width = 0; + $width = 27 - length $name # length("FCGI_GET_VALUES_RESULT") == 22 + if $DUMP_RECORD_ALIGN; # + length(0xFFFF) == 5 + return sprintf '{%s, %*d, %s}', $name, $width, $request_id, $out; +} + +1; + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pod b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pod new file mode 100644 index 0000000..64f6a7e --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol.pod @@ -0,0 +1,1227 @@ +=head1 NAME + +Net::FastCGI::Protocol - Provides functions to build and parse FastCGI messages. + +=head1 SYNOPSIS + + # FCGI_Header + $octets = build_header($type, $request_id, $content_length, $padding_length); + @values = parse_header($octets); + $header = parse_header($octets); + + # FCGI_BeginRequestBody + $octets = build_begin_request_body($role, $flags); + @values = parse_begin_request_body($octets); + + # FCGI_EndRequestBody + $octets = build_end_request_body($app_status, $protocol_status); + @values = parse_end_request_body($octets); + + # FCGI_UnknownTypeBody + $octets = build_unknown_type_body($type); + @values = parse_unknown_type_body($octets); + + # FCGI_BeginRequestRecord + $octets = build_begin_request_record($request_id, $role, $flags); + + # FCGI_EndRequestRecord + $octets = build_end_request_record($request_id, $app_status, $protocol_status); + + # FCGI_UnknownTypeRecord + $octets = build_unknown_type_record($type); + + # FCGI_NameValuePair's + $octets = build_params($params); + $params = parse_params($octets); + $bool = check_params($octets); + + # FCGI_Record + $octets = build_record($type, $request_id); + $octets = build_record($type, $request_id, $content); + @values = parse_record($octets); + $record = parse_record($octets); + $record = parse_record_body($type, $request_id, $content); + + # FCGI_Record Debugging / Tracing + $string = dump_record($octets); + $string = dump_record_body($type, $request_id, $content); + + # FCGI_Record Stream + $octets = build_stream($type, $request_id, $content); + $octets = build_stream($type, $request_id, $content, $terminate); + + # Begin Request + $octets = build_begin_request($request_id, $role, $flags, $params); + $octets = build_begin_request($request_id, $role, $flags, $params, $stdin); + $octets = build_begin_request($request_id, $role, $flags, $params, $stdin, $data); + + # End Request + $octets = build_end_request($request_id, $app_status, $protocol_status); + $octets = build_end_request($request_id, $app_status, $protocol_status, $stdout); + $octets = build_end_request($request_id, $app_status, $protocol_status, $stdout, $stderr); + +=head1 DESCRIPTION + +Provides functions to build and parse FastCGI messages. + +=head1 FUNCTIONS + +Please note that all functions in this package expects octets, not unicode strings. +It's the callers responsibility to ensure this. If any of theese functions is called +with unicode strings containing code points above 255, they will most likely produce +malformed messages. + +=head2 build_begin_request + +Builds a Begin Request message. + +I + + $octets = build_begin_request($request_id, $role, $flags, $params); + $octets = build_begin_request($request_id, $role, $flags, $params, $stdin); + $octets = build_begin_request($request_id, $role, $flags, $params, $stdin, $data); + +I + +=over 4 + +=item C<$request_id> + +An unsigned 16-bit integer. Identifier of the request. + +=item C<$role> + +An unsigned 16-bit integer. This should be set to either C, +C or C. + +=item C<$flags> + +An unsigned 8-bit integer. This should be set to either C<0> or contain the +mask C if a persistent connection is desired. + +=item C<$params> + +A hash reference containing name-value pairs. This is the CGI environ that the +application expects. + +=item C<$stdin> (optional) + +A string of octets containing the C content. This should only be +provided if C<$role> is set to either C or C. The +C stream is terminated if provided. + +=item C<$data> (optional) + +A string of octets containing the C content. This should only be +provided if C<$role> is set to C. The C stream is +terminated if provided. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the message. + +=back + +=head2 build_begin_request_body + +Builds a C. + +I + + $octets = build_begin_request_body($role, $flags); + +I + +=over 4 + +=item C<$role> + +An unsigned 16-bit integer. + +=item C<$flags> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the body. String is 8 octets in length. + +=back + +=head2 build_begin_request_record + +Builds a C. + +I + + $octets = build_begin_request_record($request_id, $role, $flags); + +I + +=over 4 + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$role> + +An unsigned 16-bit integer. + +=item C<$flags> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the record. String is 16 octets in length. + +=back + +=head2 build_end_request + +Builds a End Request message + +I + + $octets = build_end_request($request_id, $app_status, $protocol_status); + $octets = build_end_request($request_id, $app_status, $protocol_status, $stdout); + $octets = build_end_request($request_id, $app_status, $protocol_status, $stdout, $stderr); + +I + +=over 4 + +=item C<$request_id> + +An unsigned 16-bit integer. Identifier of the request. + +=item C<$app_status> + +An unsigned 32-bit integer. Application status code of the request. + +=item C<$protocol_status> + +An unsigned 8-bit integer. This should be set to either C, +C, C or C. + +=item C<$stdout> (optional) + +A string of octets containing the C content. The C +stream is terminated if provided. + +=item C<$stderr> (optional) + +A string of octets containing the C content. The C +stream is terminated if provided. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the message. + +=back + +I + +This function is equivalent to C if called without +C<$stdout> and C<$stderr>. + +=head2 build_end_request_body + +Builds a C. + +I + + $octets = build_end_request_body($app_status, $protocol_status); + +I + +=over 4 + +=item C<$app_status> + +An unsigned 32-bit integer. + +=item C<$protocol_status> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the body. String is 8 octets in length. + +=back + +=head2 build_end_request_record + +Builds a C. + +I + + $octets = build_end_request_record($request_id, $app_status, $protocol_status); + +I + +=over 4 + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$app_status> + +An unsigned 32-bit integer. + +=item C<$protocol_status> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the record. String is 16 octets in length. + +=back + +=head2 build_header + +Builds a C. + +I + + $octets = build_header($type, $request_id, $content_length, $padding_length); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content_length> + +An unsigned 16-bit integer. + +=item C<$padding_length> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the header. String is 8 octets in length. + +=back + +=head2 build_params + +Builds C's. + +I + + $octets = build_params($params); + +I + +=over 4 + +=item C<$params> + +A hash reference containing name-value pairs. + +=back + +I + +=over 4 + +=item C<$octets> + +=back + +=head2 build_record + +Builds a C. + +I + + $octets = build_record($type, $request_id); + $octets = build_record($type, $request_id, $content); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> (optional) + +A string of octets containing the content, cannot exceed 65535 octets in length. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the record. + +=back + +I + +Follows the recommendation in specification and pads the record by +8-(content_length mod 8) zero-octets. + +=head2 build_stream + +Builds a series of stream records. + +I + + $octets = build_stream($type, $request_id, $content); + $octets = build_stream($type, $request_id, $content, $terminate); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> + +A string of octets containing the stream content. + +=item C<$terminate> (optional) + +A boolean indicating whether or not the stream should be terminated. +Defaults to false. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the stream. + +=back + +I + +Stream is not terminated if C<$content> is empty unless C<$terminate> is set. + +C<$content> is split in segment sizes of 32760 octets (32768 - FCGI_HEADER_LEN). + +=head2 build_unknown_type_body + +Builds a C. + +I + + $octets = build_unknown_type_body($type); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the body. String is 8 octets in length. + +=back + +=head2 build_unknown_type_record + +Builds a C. + +I + + $octets = build_unknown_type_record($type); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the record. String is 16 octets in length. + +=back + +=head2 check_params + +Determine wheter or not params is well-formed. + +I + + $boolean = check_params($octets); + +I + +=over 4 + +=item C<$octets> + +A string of octets containing C's. + +=back + +I + +=over 4 + +=item C<$boolean> + +A boolean indicating whether or not C<$octets> consist of well-formed C's. + +=back + +=head2 dump_record + +Dump a C. + +I + + $string = dump_record($octets); + +I + +=over 4 + +=item C<$octets> + +A string of octets containing at least one record. + +=back + +I + +=over 4 + +=item C<$string> + +A short (less than 100 characters) string representation of the record in printable US-ASCII. + +=back + +=head2 dump_record_body + +Dump a C. + +I + + $string = dump_record_body($type, $request_id); + $string = dump_record_body($type, $request_id, $content); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> (optional) + +A string of octets containing the content. + +=back + +I + +=over 4 + +=item C<$string> + +A short (less than 100 characters) string representation of the record in printable US-ASCII. + +=back + +=head2 parse_begin_request_body + +Parses a C. + +I + + ($role, $flags) = parse_begin_request_body($octets); + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the body, must be greater than or equal to 8 octets in length. + +=back + +I + +=over 4 + +=item C<$role> + +An unsigned 16-bit integer. + +=item C<$flags> + +An unsigned 8-bit integer. + +=back + +=head2 parse_end_request_body + +Parses a C. + +I + + ($app_status, $protocol_status) = parse_end_request_body($octets); + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the body, must be greater than or equal to 8 octets in length. + +=back + +I + +=over 4 + +=item C<$app_status> + +An unsigned 32-bit integer. + +=item C<$flags> + +An unsigned 8-bit integer. + +=back + +=head2 parse_header + +Parses a C. + +I + + ($type, $request_id, $content_length, $padding_length) + = parse_header($octets); + + $header = parse_header($octets); + say $header->{type}; + say $header->{request_id}; + say $header->{content_length}; + say $header->{padding_length}; + +I + +=over 4 + +=item C<$octets> + +A string of octets containing the header, must be greater than or equal to 8 octets in length. + +=back + +I + +In list context: + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content_length> + +An unsigned 16-bit integer. + +=item C<$padding_length> + +An unsigned 8-bit integer. + +=back + +In scalar context a hash reference containing above variable names as keys. + +=head2 parse_params + +Parses C's. + +I + + $params = parse_params($octets); + +I + +=over 4 + +=item C<$octets> + +A string of octets containing C's. + +=back + +I + +=over 4 + +=item C<$params> + +A hash reference containing name-value pairs. + +=back + +=head2 parse_record + +Parses a C. + +I + + ($type, $request_id, $content) + = parse_record($octets); + + $record = parse_record($octets); + say $record->{type}; + say $record->{request_id}; + +I + +=over 4 + +=item C<$octets> + +A string of octets containing at least one record. + +=back + +I + +In list context: + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> + +A string of octets containing the record content. + +=back + +In scalar context a hash reference containing the C components. +See L. + +=head2 parse_record_body + +Parses a C. + +I + + $record = parse_record_body($type, $request_id, $content); + say $record->{type}; + say $record->{request_id}; + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=item C<$request_id> + +An unsigned 16-bit integer. + +=item C<$content> + +A string of octets containing the record content. + +=back + +I + +A hash reference which represents the C. The content depends on the +type of record. All record types have the keys: C and C. + +=over 4 + +=item C + +=over 8 + +=item C + +An unsigned 16-bit integer. + +=item C + +An unsigned 8-bit integer. + +=back + +=item C + +=over 8 + +=item C + +An unsigned 32-bit integer. + +=item C + +An unsigned 8-bit integer. + +=back + +=item C + +=item C + +=item C + +=item C + +=item C + +=over 8 + +=item C + +A string of octets containing the content of the stream. + +=back + +=item C + +=item C + +=over 8 + +=item C + +A hash reference containing name-value pairs. + +=back + +=item C + +=over 8 + +=item C + +An unsigned 8-bit integer. + +=back + +=back + +=head2 parse_unknown_type_body + +Parses a C. + +I + + $type = parse_unknown_type_body($octets); + +I + +=over 4 + +=item C<$octets> + +C<$octets> must be greater than or equal to 8 octets in length. + +=back + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +=head2 get_record_length + +I + + $length = get_record_length($octets); + +I + +=over 4 + +=item C<$octets> + +A string of octets containing at least one C. + +=back + +I + +=over 4 + +=item C<$length> + +An unsigned integer containing the length of record in octets. If C<$octets> +contains insufficient octets C<(< FCGI_HEADER_LEN)> C<0> is returned. + +=back + +=head2 get_type_name + +I + + $name = get_type_name($type); + $name = get_type_name(FCGI_BEGIN_REQUEST); # 'FCGI_BEGIN_REQUEST' + $name = get_type_name(255); # '0xFF' + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$name> + +A string containing the name of the type. If C<$type> is not a known v1.0 type, +a hexadecimal value is returned. + +=back + +I + +See also L. + +=head2 get_role_name + +I + + $name = get_role_name($type); + $name = get_role_name(FCGI_RESPONDER); # 'FCGI_RESPONDER' + $name = get_role_name(65535); # '0xFFFF' + +I + +=over 4 + +=item C<$role> + +An unsigned 16-bit integer. + +=back + +I + +=over 4 + +=item C<$name> + +A string containing the name of the role. If C<$role> is not a known v1.0 role, +a hexadecimal value is returned. + +=back + +I + +See also L. + +=head2 get_protocol_status_name + +I + + $name = get_protocol_status_name($protocol_status); + $name = get_protocol_status_name(FCGI_REQUEST_COMPLETE); # 'FCGI_REQUEST_COMPLETE' + $name = get_protocol_status_name(255); # '0xFF' + +I + +=over 4 + +=item C<$protocol_status> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$name> + +A string containing the name of the protocol status. If C<$protocol_status> is +not a known v1.0 protocol status code, a hexadecimal value is returned. + +=back + +I + +See also L. + +=head2 is_known_type + +I + + $boolean = is_known_type($type); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$boolean> + +A boolean indicating whether or not C<$type> is a known FastCGI v1.0 type. + +=back + +=head2 is_management_type + +I + + $boolean = is_management_type($type); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$boolean> + +A boolean indicating whether or not C<$type> is a management type. + +=back + +=head2 is_discrete_type + +I + + $boolean = is_discrete_type($type); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$boolean> + +A boolean indicating whether or not C<$type> is a discrete type. + +=back + +=head2 is_stream_type + +I + + $boolean = is_stream_type($type); + +I + +=over 4 + +=item C<$type> + +An unsigned 8-bit integer. + +=back + +I + +=over 4 + +=item C<$boolean> + +A boolean indicating whether or not C<$type> is a stream type. + +=back + +=head1 EXPORTS + +None by default. All functions can be exported using the C<:all> tag or individually. + +=head1 DIAGNOSTICS + +=over 4 + +=item B<(F)> Usage: %s + +Subroutine called with wrong number of arguments. + +=item B<(F)> Invalid Argument: %s + +=item B<(F)> FastCGI: Insufficient number of octets to parse %s + +=item B<(F)> FastCGI: Malformed record %s + +=item B<(F)> FastCGI: Protocol version mismatch (0x%.2X) + +=back + +=head1 SEE ALSO + +=over 4 + +=item FastCGI Specification Version 1.0 + +L + +=item The Common Gateway Interface (CGI) Version 1.1 + +L + +=item L + + +=back + +=head1 AUTHOR + +Christian Hansen C + +=head1 COPYRIGHT + +Copyright 2008-2010 by Christian Hansen. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol/PP.pm b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol/PP.pm new file mode 100644 index 0000000..bfba257 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/lib/Net/FastCGI/Protocol/PP.pm @@ -0,0 +1,429 @@ +package Net::FastCGI::Protocol::PP; +use strict; +use warnings; + +use Carp qw[]; +use Net::FastCGI::Constant qw[:all]; + +BEGIN { + our $VERSION = '0.14'; + our @EXPORT_OK = qw[ build_begin_request + build_begin_request_body + build_begin_request_record + build_end_request + build_end_request_body + build_end_request_record + build_header + build_params + build_record + build_stream + build_unknown_type_body + build_unknown_type_record + check_params + parse_begin_request_body + parse_end_request_body + parse_header + parse_params + parse_record + parse_record_body + parse_unknown_type_body + is_known_type + is_management_type + is_discrete_type + is_stream_type + get_record_length + get_role_name + get_type_name + get_protocol_status_name ]; + + our %EXPORT_TAGS = ( all => \@EXPORT_OK ); + + require Exporter; + *import = \&Exporter::import; +} + +sub TRUE () { !!1 } +sub FALSE () { !!0 } + +sub ERRMSG_OCTETS () { q/FastCGI: Insufficient number of octets to parse %s/ } +sub ERRMSG_MALFORMED () { q/FastCGI: Malformed record %s/ } +sub ERRMSG_VERSION () { q/FastCGI: Protocol version mismatch (0x%.2X)/ } +sub ERRMSG_OCTETS_LE () { q/Invalid Argument: '%s' cannot exceed %u octets in length/ } + +sub throw { + @_ = ( sprintf($_[0], @_[1..$#_]) ) if @_ > 1; + goto \&Carp::croak; +} + +# FCGI_Header + +sub build_header { + @_ == 4 || throw(q/Usage: build_header(type, request_id, content_length, padding_length)/); + return pack(FCGI_Header, FCGI_VERSION_1, @_); +} + +sub parse_header { + @_ == 1 || throw(q/Usage: parse_header(octets)/); + (defined $_[0] && length $_[0] >= 8) + || throw(ERRMSG_OCTETS, q/FCGI_Header/); + (vec($_[0], 0, 8) == FCGI_VERSION_1) + || throw(ERRMSG_VERSION, unpack('C', $_[0])); + return unpack('xCnnCx', $_[0]) + if wantarray; + my %header; + @header{qw(type request_id content_length padding_length)} + = unpack('xCnnCx', $_[0]); + return \%header; +} + +# FCGI_BeginRequestBody + +sub build_begin_request_body { + @_ == 2 || throw(q/Usage: build_begin_request_body(role, flags)/); + return pack(FCGI_BeginRequestBody, @_); +} + +sub parse_begin_request_body { + @_ == 1 || throw(q/Usage: parse_begin_request_body(octets)/); + (defined $_[0] && length $_[0] >= 8) + || throw(ERRMSG_OCTETS, q/FCGI_BeginRequestBody/); + return unpack(FCGI_BeginRequestBody, $_[0]); +} + +# FCGI_EndRequestBody + +sub build_end_request_body { + @_ == 2 || throw(q/Usage: build_end_request_body(app_status, protocol_status)/); + return pack(FCGI_EndRequestBody, @_); +} + +sub parse_end_request_body { + @_ == 1 || throw(q/Usage: parse_end_request_body(octets)/); + (defined $_[0] && length $_[0] >= 8) + || throw(ERRMSG_OCTETS, q/FCGI_EndRequestBody/); + return unpack(FCGI_EndRequestBody, $_[0]); +} + +# FCGI_UnknownTypeBody + +sub build_unknown_type_body { + @_ == 1 || throw(q/Usage: build_unknown_type_body(type)/); + return pack(FCGI_UnknownTypeBody, @_); +} + +sub parse_unknown_type_body { + @_ == 1 || throw(q/Usage: parse_unknown_type_body(octets)/); + (defined $_[0] && length $_[0] >= 8) + || throw(ERRMSG_OCTETS, q/FCGI_UnknownTypeBody/); + return unpack(FCGI_UnknownTypeBody, $_[0]); +} + +# FCGI_BeginRequestRecord + +sub build_begin_request_record { + @_ == 3 || throw(q/Usage: build_begin_request_record(request_id, role, flags)/); + my ($request_id, $role, $flags) = @_; + return build_record(FCGI_BEGIN_REQUEST, $request_id, + build_begin_request_body($role, $flags)); +} + +# FCGI_EndRequestRecord + +sub build_end_request_record { + @_ == 3 || throw(q/Usage: build_end_request_record(request_id, app_status, protocol_status)/); + my ($request_id, $app_status, $protocol_status) = @_; + return build_record(FCGI_END_REQUEST, $request_id, + build_end_request_body($app_status, $protocol_status)); +} + +# FCGI_UnknownTypeRecord + +sub build_unknown_type_record { + @_ == 1 || throw(q/Usage: build_unknown_type_record(type)/); + my ($type) = @_; + return build_record(FCGI_UNKNOWN_TYPE, FCGI_NULL_REQUEST_ID, + build_unknown_type_body($type)); +} + +sub build_record { + @_ == 2 || @_ == 3 || throw(q/Usage: build_record(type, request_id [, content])/); + my ($type, $request_id) = @_; + + my $content_length = defined $_[2] ? length $_[2] : 0; + my $padding_length = (8 - ($content_length % 8)) % 8; + + ($content_length <= FCGI_MAX_CONTENT_LEN) + || throw(ERRMSG_OCTETS_LE, q/content/, FCGI_MAX_CONTENT_LEN); + + my $res = build_header($type, $request_id, $content_length, $padding_length); + + if ($content_length) { + $res .= $_[2]; + } + + if ($padding_length) { + $res .= "\x00" x $padding_length; + } + + return $res; +} + +sub parse_record { + @_ == 1 || throw(q/Usage: parse_record(octets)/); + my ($type, $request_id, $content_length) = &parse_header; + + (length $_[0] >= FCGI_HEADER_LEN + $content_length) + || throw(ERRMSG_OCTETS, q/FCGI_Record/); + + return wantarray + ? ($type, $request_id, substr($_[0], FCGI_HEADER_LEN, $content_length)) + : parse_record_body($type, $request_id, + substr($_[0], FCGI_HEADER_LEN, $content_length)); +} + +sub parse_record_body { + @_ == 3 || throw(q/Usage: parse_record_body(type, request_id, content)/); + my ($type, $request_id) = @_; + + my $content_length = defined $_[2] ? length $_[2] : 0; + + ($content_length <= FCGI_MAX_CONTENT_LEN) + || throw(ERRMSG_OCTETS_LE, q/content/, FCGI_MAX_CONTENT_LEN); + + my %record = (type => $type, request_id => $request_id); + if ($type == FCGI_BEGIN_REQUEST) { + ($request_id != FCGI_NULL_REQUEST_ID && $content_length == 8) + || throw(ERRMSG_MALFORMED, q/FCGI_BeginRequestRecord/); + @record{ qw(role flags) } = parse_begin_request_body($_[2]); + } + elsif ($type == FCGI_ABORT_REQUEST) { + ($request_id != FCGI_NULL_REQUEST_ID && $content_length == 0) + || throw(ERRMSG_MALFORMED, q/FCGI_AbortRequestRecord/); + } + elsif ($type == FCGI_END_REQUEST) { + ($request_id != FCGI_NULL_REQUEST_ID && $content_length == 8) + || throw(ERRMSG_MALFORMED, q/FCGI_EndRequestRecord/); + @record{ qw(app_status protocol_status) } + = parse_end_request_body($_[2]); + } + elsif ( $type == FCGI_PARAMS + || $type == FCGI_STDIN + || $type == FCGI_STDOUT + || $type == FCGI_STDERR + || $type == FCGI_DATA) { + ($request_id != FCGI_NULL_REQUEST_ID) + || throw(ERRMSG_MALFORMED, $FCGI_RECORD_NAME[$type]); + $record{content} = $content_length ? $_[2] : ''; + } + elsif ( $type == FCGI_GET_VALUES + || $type == FCGI_GET_VALUES_RESULT) { + ($request_id == FCGI_NULL_REQUEST_ID) + || throw(ERRMSG_MALFORMED, $FCGI_RECORD_NAME[$type]); + $record{values} = parse_params($_[2]); + } + elsif ($type == FCGI_UNKNOWN_TYPE) { + ($request_id == FCGI_NULL_REQUEST_ID && $content_length == 8) + || throw(ERRMSG_MALFORMED, q/FCGI_UnknownTypeRecord/); + $record{unknown_type} = parse_unknown_type_body($_[2]); + } + else { + # unknown record type, pass content so caller can decide appropriate action + $record{content} = $_[2] if $content_length; + } + + return \%record; +} + +# Reference implementation use 8192 (libfcgi) +sub FCGI_SEGMENT_LEN () { 32768 - FCGI_HEADER_LEN } + +sub build_stream { + @_ == 3 || @_ == 4 || throw(q/Usage: build_stream(type, request_id, content [, terminate])/); + my ($type, $request_id, undef, $terminate) = @_; + + my $len = defined $_[2] ? length $_[2] : 0; + my $res = ''; + + if ($len) { + if ($len < FCGI_SEGMENT_LEN) { + $res = build_record($type, $request_id, $_[2]); + } + else { + my $header = build_header($type, $request_id, FCGI_SEGMENT_LEN, 0); + my $off = 0; + while ($len >= FCGI_SEGMENT_LEN) { + $res .= $header; + $res .= substr($_[2], $off, FCGI_SEGMENT_LEN); + $len -= FCGI_SEGMENT_LEN; + $off += FCGI_SEGMENT_LEN; + } + if ($len) { + $res .= build_record($type, $request_id, substr($_[2], $off, $len)); + } + } + } + + if ($terminate) { + $res .= build_header($type, $request_id, 0, 0); + } + + return $res; +} + +sub build_params { + @_ == 1 || throw(q/Usage: build_params(params)/); + my ($params) = @_; + my $res = ''; + while (my ($key, $val) = each(%$params)) { + for ($key, $val) { + my $len = defined $_ ? length : 0; + $res .= $len < 0x80 ? pack('C', $len) : pack('N', $len | 0x8000_0000); + } + $res .= $key; + $res .= $val if defined $val; + } + return $res; +} + +sub parse_params { + @_ == 1 || throw(q/Usage: parse_params(octets)/); + my ($octets) = @_; + + (defined $octets) + || return +{}; + + my ($params, $klen, $vlen) = ({}, 0, 0); + while (length $octets) { + for ($klen, $vlen) { + (1 <= length $octets) + || throw(ERRMSG_OCTETS, q/FCGI_NameValuePair/); + $_ = vec(substr($octets, 0, 1, ''), 0, 8); + next if $_ < 0x80; + (3 <= length $octets) + || throw(ERRMSG_OCTETS, q/FCGI_NameValuePair/); + $_ = vec(pack('C', $_ & 0x7F) . substr($octets, 0, 3, ''), 0, 32); + } + ($klen + $vlen <= length $octets) + || throw(ERRMSG_OCTETS, q/FCGI_NameValuePair/); + my $key = substr($octets, 0, $klen, ''); + $params->{$key} = substr($octets, 0, $vlen, ''); + } + return $params; +} + +sub check_params { + @_ == 1 || throw(q/Usage: check_params(octets)/); + (defined $_[0]) + || return FALSE; + + my ($len, $off, $klen, $vlen) = (length $_[0], 0, 0, 0); + while ($off < $len) { + for ($klen, $vlen) { + (($off += 1) <= $len) + || return FALSE; + $_ = vec($_[0], $off - 1, 8); + next if $_ < 0x80; + (($off += 3) <= $len) + || return FALSE; + $_ = vec(substr($_[0], $off - 4, 4), 0, 32) & 0x7FFF_FFFF; + } + (($off += $klen + $vlen) <= $len) + || return FALSE; + } + return TRUE; +} + +sub build_begin_request { + (@_ >= 4 && @_ <= 6) || throw(q/Usage: build_begin_request(request_id, role, flags, params [, stdin [, data]])/); + my ($request_id, $role, $flags, $params) = @_; + + my $r = build_begin_request_record($request_id, $role, $flags) + . build_stream(FCGI_PARAMS, $request_id, build_params($params), TRUE); + + if (@_ > 4) { + $r .= build_stream(FCGI_STDIN, $request_id, $_[4], TRUE); + if (@_ > 5) { + $r .= build_stream(FCGI_DATA, $request_id, $_[5], TRUE); + } + } + return $r; +} + +sub build_end_request { + (@_ >= 3 && @_ <= 5) || throw(q/Usage: build_end_request(request_id, app_status, protocol_status [, stdout [, stderr]])/); + my ($request_id, $app_status, $protocol_status) = @_; + + my $r; + if (@_ > 3) { + $r .= build_stream(FCGI_STDOUT, $request_id, $_[3], TRUE); + if (@_ > 4) { + $r .= build_stream(FCGI_STDERR, $request_id, $_[4], TRUE); + } + } + $r .= build_end_request_record($request_id, $app_status, $protocol_status); + return $r; +} + +sub get_record_length { + @_ == 1 || throw(q/Usage: get_record_length(octets)/); + (defined $_[0] && length $_[0] >= FCGI_HEADER_LEN) + || return 0; + return FCGI_HEADER_LEN + vec($_[0], 2, 16) # contentLength + + vec($_[0], 6, 8); # paddingLength +} + +sub is_known_type { + @_ == 1 || throw(q/Usage: is_known_type(type)/); + my ($type) = @_; + return ($type > 0 && $type <= FCGI_MAXTYPE); +} + +sub is_discrete_type { + @_ == 1 || throw(q/Usage: is_discrete_type(type)/); + my ($type) = @_; + return ( $type == FCGI_BEGIN_REQUEST + || $type == FCGI_ABORT_REQUEST + || $type == FCGI_END_REQUEST + || $type == FCGI_GET_VALUES + || $type == FCGI_GET_VALUES_RESULT + || $type == FCGI_UNKNOWN_TYPE ); +} + +sub is_management_type { + @_ == 1 || throw(q/Usage: is_management_type(type)/); + my ($type) = @_; + return ( $type == FCGI_GET_VALUES + || $type == FCGI_GET_VALUES_RESULT + || $type == FCGI_UNKNOWN_TYPE ); +} + +sub is_stream_type { + @_ == 1 || throw(q/Usage: is_stream_type(type)/); + my ($type) = @_; + return ( $type == FCGI_PARAMS + || $type == FCGI_STDIN + || $type == FCGI_STDOUT + || $type == FCGI_STDERR + || $type == FCGI_DATA ); +} + +sub get_type_name { + @_ == 1 || throw(q/Usage: get_type_name(type)/); + my ($type) = @_; + return $FCGI_TYPE_NAME[$type] || sprintf('0x%.2X', $type); +} + +sub get_role_name { + @_ == 1 || throw(q/Usage: get_role_name(role)/); + my ($role) = @_; + return $FCGI_ROLE_NAME[$role] || sprintf('0x%.4X', $role); +} + +sub get_protocol_status_name { + @_ == 1 || throw(q/Usage: get_protocol_status_name(protocol_status)/); + my ($status) = @_; + return $FCGI_PROTOCOL_STATUS_NAME[$status] || sprintf('0x%.2X', $status); +} + +1; + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/t/000_load.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/000_load.t new file mode 100644 index 0000000..1436a55 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/001_header.t new file mode 100644 index 0000000..8e1476b --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/005_record_length.t new file mode 100644 index 0000000..1d23819 --- /dev/null +++ b/debian/vendor-h2o/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; + } +} + +{ + 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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/010_build_record.t new file mode 100644 index 0000000..9f32126 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/015_build_stream.t new file mode 100644 index 0000000..233f225 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/020_begin_request_body.t new file mode 100644 index 0000000..031a7d1 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/025_begin_request_record.t new file mode 100644 index 0000000..50f9443 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/027_begin_request.t new file mode 100644 index 0000000..e5d6c91 --- /dev/null +++ b/debian/vendor-h2o/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); + } + + 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); + } + + { + my $exp = $begin . $params . $stdin; + my $got = build_begin_request(1, FCGI_RESPONDER, 0, {}, undef); + is_hexstr($got, $exp, q); + } + + 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); + } + + { + my $exp = $begin . $params . $stdin . $data; + my $got = build_begin_request(1, FCGI_RESPONDER, 0, {}, undef, ''); + is_hexstr($got, $exp, q); + } +} + +{ + 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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/030_end_request_body.t new file mode 100644 index 0000000..783408d --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/035_end_request_record.t new file mode 100644 index 0000000..f76dbd1 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/037_end_request.t new file mode 100644 index 0000000..c7c421c --- /dev/null +++ b/debian/vendor-h2o/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); + } + + 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); + } + + { + my $exp = $stdout . $end; + my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, undef); + is_hexstr($got, $exp, q); + } + + 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); + } + + { + my $exp = $stdout . $stderr . $end; + my $got = build_end_request(1, 0, FCGI_REQUEST_COMPLETE, undef, ''); + is_hexstr($got, $exp, q); + } +} + +{ + 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); + } + + 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(request_id, app_status, protocol_status [, stdout [, stderr]]) +for (0..2, 6) { + throws_ok { build_end_request((1) x $_) } qr/^Usage: /; +} + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/040_unknown_type_body.t new file mode 100644 index 0000000..27e0d37 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/045_unknown_type_record.t new file mode 100644 index 0000000..8ee053a --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/050_parse_record.t new file mode 100644 index 0000000..34c5fb9 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/055_parse_record_body.t new file mode 100644 index 0000000..35f3793 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/060_params.t new file mode 100644 index 0000000..92d9a64 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/065_record_type.t new file mode 100644 index 0000000..5836a05 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/070_names.t new file mode 100644 index 0000000..86af502 --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/080_dump_record.t new file mode 100644 index 0000000..0e0bb5d --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t b/debian/vendor-h2o/misc/p5-net-fastcgi/t/020_protocol/085_dump_record_body.t new file mode 100644 index 0000000..af00d7a --- /dev/null +++ b/debian/vendor-h2o/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/debian/vendor-h2o/misc/p5-net-fastcgi/t/lib/myconfig.pm b/debian/vendor-h2o/misc/p5-net-fastcgi/t/lib/myconfig.pm new file mode 100644 index 0000000..1d4f634 --- /dev/null +++ b/debian/vendor-h2o/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; diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/xt/000_pod.t b/debian/vendor-h2o/misc/p5-net-fastcgi/xt/000_pod.t new file mode 100644 index 0000000..95dd65a --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/xt/000_pod.t @@ -0,0 +1,17 @@ +#!perl + +use strict; +use warnings; + +use Test::More; + +BEGIN { + eval 'use Test::Pod'; + + if ($@) { + plan skip_all => 'Needs Test::Pod'; + } +} + +all_pod_files_ok(); + diff --git a/debian/vendor-h2o/misc/p5-net-fastcgi/xt/010_pod_coverage.t b/debian/vendor-h2o/misc/p5-net-fastcgi/xt/010_pod_coverage.t new file mode 100644 index 0000000..bd4e3d2 --- /dev/null +++ b/debian/vendor-h2o/misc/p5-net-fastcgi/xt/010_pod_coverage.t @@ -0,0 +1,29 @@ +#!perl + +use strict; +use warnings; + +use Test::More; + +BEGIN { + eval 'use Test::Pod::Coverage'; + + if ($@) { + plan skip_all => 'Needs Test::Pod::Coverage'; + } +} + +my @modules = sort grep { !/::(?:PP|XS)$/ } all_modules(); + +plan tests => scalar(@modules); + +foreach my $module ( @modules ) { + my $params = {}; + + if ( $module =~ /^Net::FastCGI::Protocol$/ ) { + $params->{coverage_class} = 'Pod::Coverage::ExportOnly'; + } + + pod_coverage_ok( $module, $params ); +} + diff --git a/debian/vendor-h2o/misc/picotemplate-conf.pl b/debian/vendor-h2o/misc/picotemplate-conf.pl new file mode 100644 index 0000000..95eaa7a --- /dev/null +++ b/debian/vendor-h2o/misc/picotemplate-conf.pl @@ -0,0 +1,21 @@ +use strict; +use warnings; + +$main::push_expr = sub { + my $src = shift; + return qq{{ h2o_iovec_t _s = ($src); if (_s.len != 0 && _s.base[_s.len - 1] == '\\n') --_s.len; h2o_buffer_reserve(&_, _s.len); memcpy(_->bytes + _->size, _s.base, _s.len); _->size += _s.len; }}; +}; + +$main::push_void_expr = sub { + my $src = shift; + return qq{{ size_t _l = _->size; { $src }; if (_->size != 0 && _l != _->size && _->bytes[_->size - 1] == '\\n') --_->size; }}; +}; + +$main::push_str = sub { + my $str = shift; + $str =~ s/([\\'"])/\\$1/gs; + $str =~ s/\n/\\n/gs; + return $main::push_expr->(qq{h2o_iovec_init(H2O_STRLIT("$str"))}); +}; + +1; diff --git a/debian/vendor-h2o/misc/regen.mk b/debian/vendor-h2o/misc/regen.mk new file mode 100755 index 0000000..46417e7 --- /dev/null +++ b/debian/vendor-h2o/misc/regen.mk @@ -0,0 +1,45 @@ +define FATPACK_SHEBANG +#! /bin/sh +exec $${H2O_PERL:-perl} -x $$0 "$$@" +#! perl +endef +export FATPACK_SHEBANG + +all: tokens lib/handler/mruby/embedded.c.h lib/http2/hpack_huffman_table.h lib/handler/file/templates.c.h clang-format-all share/h2o/start_server share/h2o/fastcgi-cgi share/h2o/ca-bundle.crt + +tokens: + misc/tokens.pl + +lib/handler/mruby/embedded.c.h: misc/embed_mruby_code.pl \ + lib/handler/mruby/embedded/core.rb \ + lib/handler/mruby/embedded/http_request.rb \ + lib/handler/mruby/embedded/chunked.rb + misc/embed_mruby_code.pl $^ > $@ + clang-format -i $@ + +lib/http2/hpack_huffman_table.h: misc/mkhufftbl.py + python misc/mkhufftbl.py > $@ + +lib/handler/file/templates.c.h: misc/picotemplate-conf.pl lib/handler/file/_templates.c.h + misc/picotemplate/picotemplate.pl --conf misc/picotemplate-conf.pl lib/handler/file/_templates.c.h || exit 1 + clang-format -i $@ + +clang-format-all: + misc/clang-format-all.sh + +share/h2o/start_server: FORCE + cd misc/p5-Server-Starter; \ + fatpack-simple --shebang "$$FATPACK_SHEBANG" -o ../../$@ script/start_server + +share/h2o/fastcgi-cgi: FORCE + cd misc/p5-net-fastcgi; \ + fatpack-simple --shebang "$$FATPACK_SHEBANG" -o ../../$@ ../fastcgi-cgi.pl + +share/h2o/ca-bundle.crt: FORCE + cd share/h2o; \ + ../../misc/mk-ca-bundle.pl; \ + rm -f certdata.txt + +FORCE: + +.PHONY: tokens clang-format-all FORCE diff --git a/debian/vendor-h2o/misc/test-ca/README.md b/debian/vendor-h2o/misc/test-ca/README.md new file mode 100644 index 0000000..e39680b --- /dev/null +++ b/debian/vendor-h2o/misc/test-ca/README.md @@ -0,0 +1,7 @@ +Run the commands below to create a new certificate signed by the CA: + +``` +openssl genrsa -out server.key 2048 +openssl req -days 3650 -new -key server.key -out server.csr +openssl ca -keyfile ca.key -cert ca.crt -extensions usr_cert -policy policy_anything -days 3650 -md sha256 -in server.csr -out server.crt +``` diff --git a/debian/vendor-h2o/misc/test-ca/ca.crt b/debian/vendor-h2o/misc/test-ca/ca.crt new file mode 100644 index 0000000..c08a1bc --- /dev/null +++ b/debian/vendor-h2o/misc/test-ca/ca.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICqDCCAZACCQCapLVXsO/NtjANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtI +Mk8gVGVzdCBDQTAeFw0xNDEyMTAwNjQ0NTVaFw0yNDEyMDcwNjQ0NTVaMBYxFDAS +BgNVBAMTC0gyTyBUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArzfuXVcDcEDcTfIMHb74mV8xaXrP7SqOJsd82/lyupBmnSlXgp8LgHj9vcHc +N12m2sQYkvdo50KJWRfljmzPQKlQ37r8D1focjVEDOc0wwan3UjB/Fg42ummUxeM +13kMukGy/osrQtgY8oFFV00HtAeNOLUF0FrpLy+beSuldoij8PFF3ADdEPay+TSy +tLIvrUrx4/tUv5yMEDL+HA1W0M8X/0L37+cXdT1bbINOBIJ/v6ZrpUSULCpmlR0n +XxDTCV1WWvlxMl1RcQrKvcV2NzeFnEFZI3aAdAkwpo3oUaidKG1g2GjFJA0PIhFz +hpQZkG+eyvRMYF5lPLVrCtZhkwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBItTZh +jyOOPyD4udv5K2qK5xRDGlSzdvqFgZ4ttffppk0XjgSd1ptNjqLnmhtvyzGz1hT3 +Byww/XiFZ+HDbCT7OGDzIByvUMPKpUD5KiTRaRsLbOd3aPIU1JbOYM7GTA921TZJ +qoCwWopAJB63LyoS+wAU4TZj0pUH4BqGsNeODA/XuPYPlUuB1bnfInRXBZiig/FT +JQ2Sab4O6bVRCWiHt9sM+waOCoX40VP7C8o+nYIR0w+calcRJ9GX8L4sR0jgZSQu +fjnp4ASeNZeSyivYvLC56pbBQBmgkMxl6lAvmmPnBKVHBlG+tBRyLZMnsO6ReP2R +UdScMm6oEnThC0k1 +-----END CERTIFICATE----- diff --git a/debian/vendor-h2o/misc/test-ca/ca.key b/debian/vendor-h2o/misc/test-ca/ca.key new file mode 100644 index 0000000..0e482de --- /dev/null +++ b/debian/vendor-h2o/misc/test-ca/ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEArzfuXVcDcEDcTfIMHb74mV8xaXrP7SqOJsd82/lyupBmnSlX +gp8LgHj9vcHcN12m2sQYkvdo50KJWRfljmzPQKlQ37r8D1focjVEDOc0wwan3UjB +/Fg42ummUxeM13kMukGy/osrQtgY8oFFV00HtAeNOLUF0FrpLy+beSuldoij8PFF +3ADdEPay+TSytLIvrUrx4/tUv5yMEDL+HA1W0M8X/0L37+cXdT1bbINOBIJ/v6Zr +pUSULCpmlR0nXxDTCV1WWvlxMl1RcQrKvcV2NzeFnEFZI3aAdAkwpo3oUaidKG1g +2GjFJA0PIhFzhpQZkG+eyvRMYF5lPLVrCtZhkwIDAQABAoIBAFAS4W3qm/mqyoMc +gIj/gyCkLjKkG22pKvlx5Q+qOdIkt6BPClz5TgpSQLN9aqQqulvzjb9sLZayA46h +qxihhT1pozn7e8GPTP0Udprm9mfCHOi1nWEy+Bii+o2yj3zRJw3fhGtrMkQD+bKp +fQTegQy2/sTRhWyofzQ/L2/6kE1Qdid+iMR3J/qCgYKp7KGqn7bVGmuFx5l6hMsK +zSgmkubVFLAu6l23Wxni47IJb1iVVjDdfn4lbHo8PEolL4676FxFhKiyvE5/TRxD ++x6Fqp/IhFW1WCzszfyMnpW8pHOxhMHBkmVQBNQM4BtADZWAIlKPpqo2hCbtCj1c +F8ObSlECgYEA6BjUO6843IkkJ+KZNodEArbt9BUpuHvU/GmFDs31lkJfenfgOo5X +h6pvi8IT2Dpdc/jNyeQUSW1Rq5U4/yjoXBMT+/4bpnCyaYUcB8sGdxA+HmC4NFnv +9J8mWMWLnNnLMxcoEdfxsCj4MymjmPb3eDdQN3ijPCNYz+TZRN8B9LcCgYEAwUOE +NPA/efF3ZEoV8ZcrmGSaWjOts3O/XsegEaQeMCQ9s5rgqHODWUg/kOJpkUurPINo +lB2j1TO8uV9NxgSErwhbboQfPaR9UQa+4hvAKpzjCrHNght9DPTzkdqn+r30jqyl +VK/bomzwEbMOO8Ay3TE9aYcqL5h84WnKOUlCNgUCgYEAz6oXiud2iuwx63X1/DH/ +Cia+tZuR3rz9jnKjWOGzESSF5UAI4puleX9nmralptxh7Xf6ON/XvvMPFeTIQJVL +gcaYJOnxt3QyTfOJZvei6zkfO3LynfSynD8hwl/OUSMVirr3YS/D0gh2OuDQvfaK +6YckQN2xwAcoWaq7M8INL/UCgYEAuIIk7gWQFHObcHvqh0Ozs0IYupUr+G9A/NPI +1g7BY2S2I4pxgWEGvW5kgYYnEzgSuysZ5I6HozxJqRB7x9j4c8Kex9wLl2Y63eh6 +xJOJ2yT8/XDSqqxjrsMM5urCBHjlynC5Ryi9n0wxxjQUGqdb6CDiaKVKeTYzw2Ck +WBzAwaECgYEA0hZtjC3vbL6YZ4NKw53aVMyb7GNl/J3re2g8ZGlOgOBWWgW5BI72 +l917eDBx/GOmZ1lRsI91ai19CyxiyRqd0WcZ4pqQ2qRniq7E0kajoy4+kg8Aj27f +lD29WnSAse3sFHEhvoJYspZMGmKL4SLydXtVvllXeFhqYdK3773bPaE= +-----END RSA PRIVATE KEY----- diff --git a/debian/vendor-h2o/misc/test-ca/demoCA/index.txt b/debian/vendor-h2o/misc/test-ca/demoCA/index.txt new file mode 100644 index 0000000..0f465bc --- /dev/null +++ b/debian/vendor-h2o/misc/test-ca/demoCA/index.txt @@ -0,0 +1,2 @@ +V 241207193305Z 01 unknown /CN=127.0.0.1.xip.io +V 241207201102Z 02 unknown /CN=alternate.127.0.0.1.xip.io diff --git a/debian/vendor-h2o/misc/test-ca/demoCA/index.txt.attr b/debian/vendor-h2o/misc/test-ca/demoCA/index.txt.attr new file mode 100644 index 0000000..8f7e63a --- /dev/null +++ b/debian/vendor-h2o/misc/test-ca/demoCA/index.txt.attr @@ -0,0 +1 @@ +unique_subject = yes diff --git a/debian/vendor-h2o/misc/test-ca/demoCA/newcerts/.gitkeep b/debian/vendor-h2o/misc/test-ca/demoCA/newcerts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/debian/vendor-h2o/misc/test-ca/demoCA/serial b/debian/vendor-h2o/misc/test-ca/demoCA/serial new file mode 100644 index 0000000..75016ea --- /dev/null +++ b/debian/vendor-h2o/misc/test-ca/demoCA/serial @@ -0,0 +1 @@ +03 diff --git a/debian/vendor-h2o/misc/tokens.pl b/debian/vendor-h2o/misc/tokens.pl new file mode 100755 index 0000000..1fcf173 --- /dev/null +++ b/debian/vendor-h2o/misc/tokens.pl @@ -0,0 +1,234 @@ +#! /usr/bin/perl + +# Copyright (c) 2014 DeNA Co., Ltd. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +use strict; +use warnings; +use List::Util qw(max); +use List::MoreUtils qw(uniq); +use Text::MicroTemplate qw(render_mt); + +use constant LICENSE => << 'EOT'; +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +EOT + +my %tokens; +my @hpack; + +while (my $line = ) { + chomp $line; + my ($hpack_index, $proxy_should_drop_for_req, $proxy_should_drop_for_res, $is_init_header_special, $http2_should_reject, $copy_for_push_request, $dont_compress, $name, $value) = + split /\s+/, $line, 9; + next unless $name ne ''; + $tokens{$name} = [ $hpack_index, $proxy_should_drop_for_req, $proxy_should_drop_for_res, $is_init_header_special, $http2_should_reject, $copy_for_push_request, $dont_compress ] + unless defined $tokens{$name}; + if ($hpack_index != 0) { + $hpack[$hpack_index - 1] = [ $name, $value ]; + } +} + +my @tokens = map { [ $_, @{$tokens{$_}} ] } uniq sort keys %tokens; + +# generate token.h +open my $fh, '>', 'include/h2o/token.h' + or die "failed to open include/h2o/token.h:$!"; +print $fh render_mt(<< 'EOT', \@tokens, LICENSE)->as_string; +? my ($tokens, $license) = @_; + +/* DO NOT EDIT! generated by tokens.pl */ +#ifndef h2o__token_h +#define h2o__token_h + +? for my $i (0..$#$tokens) { +#define [$i][0]) ?> (h2o__tokens + ) +? } + +#endif +EOT +close $fh; + +# generate token_table.h +open $fh, '>', 'lib/core/token_table.h' + or die "failed to open lib/core/token_table.h:$!"; +print $fh render_mt(<< 'EOT', \@tokens, LICENSE)->as_string; +? my ($tokens, $license) = @_; + +/* DO NOT EDIT! generated by tokens.pl */ +h2o_token_t h2o__tokens[] = { +? for my $i (0..$#$tokens) { + { { H2O_STRLIT("[$i][0] ?>") }, [$i][$_] } (1..$#{$tokens->[$i]})) ?> } +? } +}; +size_t h2o__num_tokens = ; + +const h2o_token_t *h2o_lookup_token(const char *name, size_t len) +{ + switch (len) { +? for my $len (uniq sort { $a <=> $b } map { length $_->[0] } @$tokens) { + case : + switch (name[]) { +? my @tokens_of_len = grep { length($_->[0]) == $len } @$tokens; +? for my $end (uniq sort map { substr($_->[0], length($_->[0]) - 1) } @tokens_of_len) { + case '': +? my @tokens_of_end = grep { substr($_->[0], length($_->[0]) - 1) eq $end } @tokens_of_len; +? for my $token (@tokens_of_end) { + if (memcmp(name, "[0], 0, length($token->[0]) - 1) ?>", [0]) - 1 ?>) == 0) + return [0]) ?>; +? } + break; +? } + } + break; +? } + } + + return NULL; +} +EOT +close $fh; + +# generate hpack_static_table.h +open $fh, '>', 'lib/http2/hpack_static_table.h' + or die "failed to open lib/hpack_static_table.h:$!"; +print $fh render_mt(<< 'EOT', \@hpack, LICENSE)->as_string; +? my ($entries, $license) = @_; + +/* automatically generated by tokens.pl */ + +static const struct st_h2o_hpack_static_table_entry_t h2o_hpack_static_table[] = { +? for my $i (0..$#$entries) { + { [$i][0]) ?>, { H2O_STRLIT("[$i][1] || "" ?>") } } +? } +}; +EOT +close $fh; + +sub normalize_name { + my $n = shift; + $n =~ s/^://; + $n =~ s/-/_/g; + $n =~ tr/a-z/A-Z/; + "H2O_TOKEN_$n"; +} + +# The table below is used to generate h2o__tokens in lib/core/token_table.h +# +# Meaning of the fields: +# - HTTP/2 static table index (non-zero if present) +# - Proxy should drop in request +# - Proxy should drop in response +# - Is init header special +# - HTTP/2 should reject +# - Copy for push request +# - Disable compression (non-zero) + +__DATA__ +1 0 0 0 0 0 0 :authority +2 0 0 0 0 0 0 :method GET +3 0 0 0 0 0 0 :method POST +4 0 0 0 0 0 0 :path / +5 0 0 0 0 0 0 :path /index.html +6 0 0 0 0 0 0 :scheme http +7 0 0 0 0 0 0 :scheme https +8 0 0 0 0 0 0 :status 200 +9 0 0 0 0 0 0 :status 204 +10 0 0 0 0 0 0 :status 206 +11 0 0 0 0 0 0 :status 304 +12 0 0 0 0 0 0 :status 400 +13 0 0 0 0 0 0 :status 404 +14 0 0 0 0 0 0 :status 500 +15 0 0 0 0 1 0 accept-charset +16 0 0 0 0 1 0 accept-encoding gzip, deflate +17 0 0 0 0 1 0 accept-language +18 0 0 0 0 0 0 accept-ranges +19 0 0 0 0 1 0 accept +20 0 0 0 0 0 0 access-control-allow-origin +21 0 0 0 0 0 0 age +22 0 0 0 0 0 0 allow +23 0 0 0 0 0 0 authorization +24 0 0 0 0 0 0 cache-control +25 0 0 0 0 0 0 content-disposition +26 0 0 0 0 0 0 content-encoding +27 0 0 0 0 0 0 content-language +28 0 0 1 0 0 0 content-length +29 0 0 0 0 0 0 content-location +30 0 0 0 0 0 0 content-range +31 0 0 0 0 0 0 content-type +32 0 0 0 0 0 1 cookie +33 0 1 0 0 0 0 date +34 0 0 0 0 0 0 etag +35 0 0 1 0 0 0 expect +36 0 0 0 0 0 0 expires +37 0 0 0 0 0 0 from +38 0 0 1 1 0 0 host +39 0 0 0 0 0 0 if-match +40 0 0 0 0 0 0 if-modified-since +41 0 0 0 0 0 0 if-none-match +42 0 0 0 0 0 0 if-range +43 0 0 0 0 0 0 if-unmodified-since +44 0 0 0 0 0 0 last-modified +45 0 0 0 0 0 0 link +46 0 0 0 0 0 0 location +47 0 0 0 0 0 0 max-forwards +48 1 0 0 0 0 0 proxy-authenticate +49 1 0 0 0 0 0 proxy-authorization +50 0 0 0 0 0 0 range +51 0 0 0 0 0 0 referer +52 0 0 0 0 0 0 refresh +53 0 0 0 0 0 0 retry-after +54 0 0 0 0 0 0 server +55 0 0 0 0 0 1 set-cookie +56 0 0 0 0 0 0 strict-transport-security +57 1 1 1 1 0 0 transfer-encoding +58 0 0 0 0 1 0 user-agent +59 0 0 0 0 0 0 vary +60 0 0 0 0 0 0 via +61 0 0 0 0 0 0 www-authenticate +0 1 1 0 1 0 0 connection +0 0 0 0 0 0 0 x-reproxy-url +0 1 1 1 1 0 0 upgrade +0 1 0 0 1 0 0 http2-settings +0 1 0 0 1 0 0 te +0 1 1 0 0 0 0 keep-alive +0 0 0 0 0 0 0 x-forwarded-for +0 0 0 0 0 0 0 x-traffic +0 0 0 0 0 0 0 cache-digest +0 0 0 0 0 0 0 x-compress-hint -- cgit v1.2.3