Modern Perl CGI
This is a CGI script, let's call it uppercase.cgi
:
#!/usr/bin/env perl
use strict;
use warnings;
use CGI;
use Encode::Simple;
use JSON::MaybeXS;
use Syntax::Keyword::Try;
my $cgi = CGI->new;
try {
my $input = decode 'UTF-8', scalar $cgi->param('input');
print $cgi->header('application/json; charset=UTF-8'), encode_json {output => uc $input};
} catch {
print $cgi->header('text/html; charset=UTF-8', '500 Internal Server Error'), '<h1>An error has occurred.</h1>';
die $@;
}
This is also a CGI script, that does all of the same things (and more):
#!/usr/bin/env perl
use Mojolicious::Lite -signatures;
any sub ($c) {
my $input = $c->param('input');
$c->render(json => {output => uc $input});
};
app->start;
The second script, however, is also a FastCGI script, by changing the extension to .fcgi
and the shebang to #!/usr/bin/env plackup -s FCGI
. It's also a mod_perl script, by changing the extension to .psgi
and using Plack::Handler::Apache2. It's also a standalone web application that supports websockets, by running it as ./uppercase.pl daemon
or hypnotoad uppercase.pl
.
Be concise. Be flexible. Be modern. Don't use CGI.pm.
(This article shows how a CGI script may be written with Mojolicious, but there are many other modern options that may suit your needs better while providing the same benefits that CGI.pm does not. See mstpan 1 and CGI::Alternatives.)
The obvious objection here is that if you do actually want to run these as CGI scripts, the first one runs seven times faster than the second one.
I'd like to see the benchmarks of that using the latest Mojolicious with Cpanel::JSON::XS installed, but if that's a problem for an application perhaps it's an indication CGI isn't the right deployment method. Luckily, there's an easy solution for that...
I tested using Perl 5.18.2, Cpanel::JSON::XS 4.07, and the most recent versions of Mojolicious, Encode::Simple, and Syntax::Keyword::Try, as installed just now using cpanm. My version of CGI.pm is 4.40. I ran the second script under "time" using "time script.cgi cgi" and the first script just using "time script.cgi". I got about 0.049 execution time for the first script and about 0.315 seconds for the second. (This computer is not very fast.) Before I updated all the modules I was getting 0.044 for the first script rather than 0.049, I'm not sure what changed since then but that gives about seven times faster figure I mentioned. The 0.3 seconds is largely the compilation time of Mojolicious::Lite, the actual script itself completes in about 0.01 second according to my use of Time::HiRes.
For example,
$ time perl -MMojolicious::Lite
takes about 0.31 seconds.
Another objection is that the first script will work on basically any server, and will not require changes more or less ever, whereas the second script basically requires the ability to deploy it in a way that includes the exact Mojolicious version it was written against, otherwise the Mojolicious on the server may be too old or too new, and software updates on the server may require you to make changes to it to keep it working.
I intentionally did not frame this as "you should use Mojolicious", since I know it is not everyone's cup of tea. There are other alternatives that provide the same benefits. However, Mojolicious (and most of the other options, too) can be fatpacked, which solves both problems.
The CGI.pm version will only work on "basically any server" until "basically any server" stops coming with Perls older than 5.20 (ignoring the other modules used, of which the core versions are either significantly slower or significantly more painful to use correctly). RHEL 8 is in beta now...
It's worse than that. RHEL/Centos 6 and 7 (which are both currently mainstream in the low-cost web hosting industry) both come, by default, with a crippled version of the perl RPM which doesn't include CGI.pm.
This is easily fixed, of course. You simply need to install the perl-core RPM which brings your Perl installation up to scratch. The problem is persuading your low-cost web hosting sysadmin to to that.
I believe this will be fixed with RHEL/Centos 8.