summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/misc/fastcgi-cgi.pl
diff options
context:
space:
mode:
Diffstat (limited to 'web/server/h2o/libh2o/misc/fastcgi-cgi.pl')
-rwxr-xr-xweb/server/h2o/libh2o/misc/fastcgi-cgi.pl256
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
-}