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.)

Reddit comments

6 Comments

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 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.

The CGI.pm version will only work on "basically any server" until "basically any server" stops coming with Perls older than 5.20

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.

Leave a comment

About Grinnz

user-pic I blog about Perl.