Skip to content

Instantly share code, notes, and snippets.

@wesQ3
Forked from frioux/WrapCGI.pm
Last active May 6, 2024 21:28
Show Gist options
  • Save wesQ3/b1ee0bfe45a6746d7c66 to your computer and use it in GitHub Desktop.
Save wesQ3/b1ee0bfe45a6746d7c66 to your computer and use it in GitHub Desktop.
replacement Plack::App::WrapCGI (perl only)
# from Plack 1.0051 2024-01-05
package Plack::App::WrapCGI;
use strict;
use warnings;
use parent qw(Plack::Component);
use Plack::Util::Accessor qw(script execute _app);
use File::Spec;
use CGI::Emulate::PSGI;
use CGI::Compile;
use Carp;
use POSIX ":sys_wait_h";
sub slurp_fh {
my $fh = $_[0];
local $/;
my $v = <$fh>;
defined $v ? $v : '';
}
sub prepare_app {
my $self = shift;
my $script = $self->script
or croak "'script' is not set";
$script = File::Spec->rel2abs($script);
if ($self->execute) {
my $app = sub {
my $env = shift;
pipe( my $stdoutr, my $stdoutw );
pipe( my $stdinr, my $stdinw );
local $SIG{CHLD} = 'DEFAULT';
my $pid = fork();
Carp::croak("fork failed: $!") unless defined $pid;
if ($pid == 0) { # child
local $SIG{__DIE__} = sub {
print STDERR @_;
exit(1);
};
close $stdoutr;
close $stdinw;
local %ENV = (%ENV, CGI::Emulate::PSGI->emulate_environment($env));
open( STDOUT, ">&=" . fileno($stdoutw) )
or Carp::croak "Cannot dup STDOUT: $!";
open( STDIN, "<&=" . fileno($stdinr) )
or Carp::croak "Cannot dup STDIN: $!";
chdir(File::Basename::dirname($script));
# RUN NON-EXECUTABLE SCRIPTS LIKE WINDOWS
# exec($script) or Carp::croak("cannot exec: $!");
exec($^X, $script) or Carp::croak("cannot exec: $!");
exit(2);
}
close $stdoutw;
close $stdinr;
syswrite($stdinw, slurp_fh($env->{'psgi.input'}));
# close STDIN so child will stop waiting
close $stdinw;
my $res = ''; my $waited_pid;
while (($waited_pid = waitpid($pid, WNOHANG)) == 0) {
$res .= slurp_fh($stdoutr);
}
$res .= slurp_fh($stdoutr);
# -1 means that the child went away, and something else
# (probably some global SIGCHLD handler) took care of it;
# yes, we just reset $SIG{CHLD} above, but you can never
# be too sure
if (POSIX::WIFEXITED($?) || $waited_pid == -1) {
return CGI::Parse::PSGI::parse_cgi_output(\$res);
} else {
Carp::croak("Error at run_on_shell CGI: $!");
}
};
$self->_app($app);
} else {
my $sub = CGI::Compile->compile($script);
my $app = CGI::Emulate::PSGI->handler($sub);
$self->_app($app);
}
}
sub call {
my($self, $env) = @_;
$self->_app->($env);
}
1;
@wesQ3
Copy link
Author

wesQ3 commented May 6, 2024

This change enables running CGI scripts that are not marked as executable, such as scripts developed on windows or usually run with a non-standard Apache cgi exec setup.

You may see this error when calling your scripts:

Can't exec "/path/to/example.plx": Permission denied at ../lib/perl5/site_perl/5.38.2/Plack/App/WrapCGI.pm line 56.
cannot exec: Permission denied at /app/script/app.psgi line 84.

The change above on line 59 will fix this by using the current perl to execute the script directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment