sub run_fcgi_handler()

in t/modules/proxy_fcgi.t [50:110]


sub run_fcgi_handler($$)
{
    my $fcgi_port    = shift;
    my $handler_func = shift;

    # Use a pipe for ready-signalling between the child and parent. Much faster
    # (and more reliable) than just sleeping for a few seconds.
    pipe(READ_END, WRITE_END);
    my $pid = fork();

    unless (defined $pid) {
        t_debug "couldn't fork FCGI process";
        ok 0;
        exit;
    }

    if ($pid == 0) {
        # Child process. Open up a listening socket.
        my $sock;
        if ($fcgi_port =~ m@/@) {
          $sock = FCGI::OpenSocket("$fcgi_port", 10); # uds
        }
        else {
          $sock = FCGI::OpenSocket(":$fcgi_port", 10);
        }

        # Signal the parent process that we're ready.
        print WRITE_END 'x';
        close WRITE_END;

        # Listen for and respond to exactly one request from the client.
        my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV,
                                    $sock, &FCGI::FAIL_ACCEPT_ON_INTR);

        if ($request->Accept() == 0) {
            # Run the handler.
            $handler_func->();
            $request->Finish();
        }

        # Clean up and exit.
        FCGI::CloseSocket($sock);
        exit;
    }

    # Parent process. Wait for the daemon to launch.
    unless (IO::Select->new((\*READ_END,))->can_read(2)) {
        t_debug "timed out waiting for FCGI process to start";
        ok 0;

        kill 'TERM', $pid;
        # Note that we don't waitpid() here because Perl's fork() implementation
        # on some platforms (Windows) doesn't guarantee that the pseudo-TERM
        # signal will be delivered. Just wait for the child to be cleaned up
        # when we exit.

        exit;
    }

    return $pid;
}