diff options
Diffstat (limited to 'web/server/h2o/libh2o/misc/fastcgi-cgi.pl')
-rwxr-xr-x | web/server/h2o/libh2o/misc/fastcgi-cgi.pl | 256 |
1 files changed, 0 insertions, 256 deletions
diff --git a/web/server/h2o/libh2o/misc/fastcgi-cgi.pl b/web/server/h2o/libh2o/misc/fastcgi-cgi.pl deleted file mode 100755 index 98ee33215..000000000 --- a/web/server/h2o/libh2o/misc/fastcgi-cgi.pl +++ /dev/null @@ -1,256 +0,0 @@ -#! /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 -} |