Perl Modules Used for Web Designing

0
2867

This is the second article in the ‘The Resurgence of Perl’ series, in continuation from the November issue of OSFY. Currently, there’s a lot of focus on the cloud and the Web environment designed for it. This article highlights two former modules of Perl for Web designing, and how successful companies still relish this old approach!

In the last article, we had already set up Apache to run a script named printenv, using mod_cgi and mod_perl. Let us compare these modules in a little more detail for the same script. Those who have not read the first article in this series can find it at https://www.opensourceforu.com/2018/11/the-resurgence-of-perl/.

As per my experience, these modules are the best CGI wrappers for Perl, when used with Apache (as compared to any other Web servers).

If you are using a virtual box or any other method of hosting your own GNU/Linux server, apart from AWS or any cloud service, we will march forward assuming that the required scripts in the last article were all run without errors, and that Apache is running with mod_perl also configured in it. This is what enables us to run the same script from the same folder but a different URL alias, and thereby view the differences.

printenv

#!/usr/local/bin/perl

print “Content-type: text/plain; charset=iso-8859-1\n\n”;

for each \$var (sort(keys(%ENV))) {

print “\$var=”.\$ENV{\$var}.”\n”;

}

In fact, we can have one more script in the same folder as the above, with the same ownership and permissions. Name the script printenv-html.

#!/usr/local/bin/perl

print “Content-type: text/html\n\n”;

foreach \$var (sort(keys(%ENV))) {

print “\$var=”.\$ENV{\$var}.”<br>”;

}

Let’s now compare printenv and printenv-html.

a) print “Content-type: text/plain; charset=iso-8859-1\n\n”; became print “Content-type: text/html\n\n”;

  1. STDOUT of Perl converts to HTML.
  2. The font size and type changes because it has become HTML (the default HTML font size is 1cm or 16px, and non-HTML font size is 11px).

Note: The default content type for Internet mail is “text/plain; charset=us-ascii”. This is the reason why automated emails sent from any programming language, when rendered by a GUI based mail client, do not use the default font of the mail client and do not look that appealing. Also, we cannot control the look and feel of the email if we do not change it to text/HTML. How to send HTML mail using Perl has been covered in an earlier article, the reference for which is given at the end of the article.

b) print “\$var=”.\$ENV{\$var}.”\n”; became print “\$var=”.\$ENV{\$var}.”<br>”;

Perl STDOUT (text/plain) understands that ‘\n’ is supposed to represent a new line but text/HTML does not. In HTML, the ‘br’ tag means a new line. If we use ‘\n’, then the output will be in one line.

Now we have four different cases:

  1. http://IPAddress/cgi-bin/printenv
  2. http://IPAddress/cgi-bin/printenv-html
  3. http://IPAddress/cgi-perl/printenv
  4. http://IPAddress/cgi-perl/printenv-html

In printenv and printenv-html, the difference is only in how the output looks and feels. For this article, we will consider cases 1 and 3.

Table 1 shows the various environment variables that printenv prints. The number of variables might increase based on whether it was authenticated with a specific identity/authorisation source (e.g., mod_auth_mellon or LDAP).

These are not environment variables of the corresponding shell (e.g., BASH) in which Apache Service is running, but are Web environment variables. If we want to add more environment variables as per our requirements, then we can do the following:

  1. Temporarily add into the Perl script; in our case the printenv $ENV{MYMAG}=”OPENSOURCEFORU”;
  2. Through the Apache Config file permanently add any variable and value to it, before restarting the Apache service:
  • SetEnv MYLANG PERL (this is facilitated by the mod_env module)
  • PerlSetEnv MYLANG PERL (this is applicable only for mod_perl and only visible in cgi-perl/printenv)

In the list we see the following two environment variables that stand out for mod_perl:

  • MOD_PERL=mod_perl/2.0.10
  • MOD_PERL_API_VERSION=2

These are specifically created by mod_perl, apart from the ones created by mod_env. Environment variables are provided to CGI scripts as native system environment variables (https://httpd.apache.org/docs/2.4/mod/mod_env.html).

Benchmarking with ApacheBench

We will do a simple Apache benchmarking test for the processing time on mod_cgi and mod_perl. Values may differ, depending on the CPU/memory configuration. I used 2GB RAM with a single core AMD 2GHz CPU.

ApacheBench (AB) is a load testing utility from Apache that comes along with Apache Dev tools. Shown below is a command that works on any GNU/Linux flavour to check if AB already exists.

bejoy@linuxforu:~> rpm -q --whatprovides `which ab`

apache2-utils-2.4.33-lp150.2.6.1.x86_64

If the package does not exist, we can install the corresponding development tools.

For Red Hat and Amazon Linux flavours, type:

yum -y install httpd-tools

For SUSE Linux, the command is:

zypper -n install apache2-utils

For Ubuntu flavours, give the following command:

apt-get -y install apache2-utils

For AB testing for mod_cgi, use the following code:

bejoy@linuxforu:~> ab -n 1000 -c 100 http://IPAddress/cgi-bin/printenv

This is ApacheBench, Version 2.3 <$Revision: 1826891 $>

Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking X.X.X.X (be patient)

Completed 100 requests

Completed 200 requests

Completed 300 requests

Completed 400 requests

Completed 500 requests

Completed 600 requests

Completed 700 requests

Completed 800 requests

Completed 900 requests

Completed 1000 requests

Finished 1000 requests

Server Software: Apache/2.4.33

Server Hostname: X.X.X.X

Server Port: 80

Document Path: /cgi-bin/printenv

Document Length: 705 bytes

Concurrency Level: 100

Time taken for tests: 12.016 seconds

Complete requests: 1000

Failed requests: 0

Total transferred: 911021 bytes

HTML transferred: 705000 bytes

Requests per second: 83.22 [#/sec] (mean)

Time per request: 1201.591 [ms] (mean)

Time per request: 12.016 [ms] (mean, across all concurrent requests)

Transfer rate: 74.04 [Kbytes/sec] received

Connection Times (ms)

min mean [+/-sd] median max

Connect: 0 171 166.9 121 561

Processing: 139 1004 321.9 1071 1913

Waiting: 8 896 315.8 917 1723

Total: 140 1175 248.7 1196 1930

Percentage of the requests served within a certain time (ms)

50% 1196

66% 1282

75% 1329

80% 1349

90% 1434

95% 1493

98% 1576

99% 1636

100% 1930 (longest request)

You can use the following code for AB testing for mod_perl:

bejoy@linuxforu:~> ab -n 1000 -c 100 http://IPAddress/cgi-perl/printenv

This is ApacheBench, Version 2.3 <$Revision: 1826891 $>

Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking X.X.X.X (be patient)

Completed 100 requests

Completed 200 requests

Completed 300 requests

Completed 400 requests

Completed 500 requests

Completed 600 requests

Completed 700 requests

Completed 800 requests

Completed 900 requests

Completed 1000 requests

Finished 1000 requests

Server Software: Apache/2.4.33

Server Hostname: X.X.X.X

Server Port: 80

Document Path: /cgi-perl/printenv

Document Length: 756 bytes

Concurrency Level: 100

Time taken for tests: 2.758 seconds

Complete requests: 1000

Failed requests: 0

Total transferred: 962000 bytes

HTML transferred: 756000 bytes

Requests per second: 362.54 [#/sec] (mean)

Time per request: 275.831 [ms] (mean)

Time per request: 2.758 [ms] (mean, across all concurrent requests)

Transfer rate: 340.59 [Kbytes/sec] received

Connection Times (ms)

min mean [+/-sd] median max

Connect: 0 10 17.9 1 63

Processing: 19 254 41.0 258 425

Waiting: 14 247 41.0 254 424

Total: 30 264 34.1 262 429

Percentage of the requests served within a certain time (ms)

50% 262

66% 272

75% 277

80% 281

90% 296

95% 314

98% 322

99% 353

100% 429 (longest request)

What we have learnt so far is that:

1. We can load Perl modules for using many of Apache’s features using mod_perl, which delivers better Web performance and threading.

2. Even without loading any Perl module:

  1. When it comes to the time taken for tests, mod_perl is six times lesser than mod_cgi.
  2. With respect to the transfer rate and length of request time period, mod_perl is five times greater than mod_cgi.

3. mod_cgi uses less RAM compared to mod_perl. Bugzilla.com claims that for mod_perl, “The more RAM you can get, the better. mod_perl is basically trading RAM for speed. At least 2GB total system RAM is recommended for running Bugzilla under mod_perl.”

4. As mentioned in the last article, mod_perl is only supported till Apache 2.2, though it works in Apache 2.4. mod_cgi and mod_env are supported by default in all Apache versions.

There are trade-offs and compromises to be made in the case of both the modules. mod_perl is more popular because of its ability to load Perl modules as part of the Apache startup by using the following:

  • PerlModule variable, or
  • PerlRequire <script_path>

These are kept in the memory/cache for any CGI Perl program. Big companies like Amazon.com (Perl’s Mason template) and Bugzilla.com use mod_perl.

Experiments with the `env` command

If we were to comment out in the printenv script, as follows:

#foreach $var (sort(keys(%ENV))) {

# print “$var=”.$ENV{$var}.”\n”;

#}

…and type the following command:

print `env`;

…how different would the output look? Try it out (http://IPAddress/cgi-bin/printenv, http://IPAddress/cgi-perl/printenv).

Adding alignment and headers

This is just to create a better look and feel. For this, let’s use cases 2 and 4 from our earlier setup (http://IPAddress/cgi-perl/printenv-html and http://IPAddress/cgi-bin/printenv-html).

After we have opened one of these, right click on the page. Then, select ‘View source’ in IE, and ‘View page source’ in Chrome/Firefox.

We will see that the page looks cluttered with no proper spacing.

Edit the script and add \n to the right of <br>. The output will look like what follows:

#!/usr/local/bin/perl

print “Content-type: text/html\n\n”;

foreach $var (sort(keys(%ENV))) {

print “$var=”.$ENV{$var}.”<br>\n”;

}

Now, view the source again, as before. You should be able to see each variable and its value, on each line, rather than all in one line. This will help in troubleshooting Web pages later on, and it also tidies up your page.

You will notice there are no headers (e.g., <html>, <body>, etc), and also that the tab of the browser does not have a title; it just shows the IP address or URL. Use the following code modification, reload the browser, and check the tab and source code again:

#!/usr/local/bin/perl

print “Content-type: text/html\n\n”;

print “<html>\n <head>\n <title>My Cloud Magic with Perl</title>\n </head>\n”;

print “ <body>\n “;

foreach $var (sort(keys(%ENV))) {

print “$var=”.$ENV{$var}.”<br>\n “;

}

print “</body>\n </html>”;

I am not referring to any CGI.pm functions. We are trying to use the easiest methods to write HTML code. Unless it is to pass parameters from one script/HTML page to the other, the CGI.pm module is very cumbersome to do effective/fast HTML coding.

Table format

We will convert the key=value pair format to a table, for which we can use the following code:

#!/usr/local/bin/perl

print “Content-type: text/html\n\n”;

print “<html>\n <head>\n <title>My Cloud Magic with Perl</title>\n </head>\n”;

print “ <body>\n <table>\n “;

foreach $var (sort(keys(%ENV))) {

print “<tr><td>$var</td><td>”.$ENV{$var}.”</td></tr>\n “;

}

print “</table>\n </body>\n</html>”;

Style sheet

We will apply a six-line style sheet to our printenv, as follows:

#!/usr/local/bin/perl

print “Content-type: text/html\n\n”;

print “<html>

<head>

<title>My Cloud Magic with Perl</title>

<style>

tr:nth-child(even) {background: #FFC300}

tr:nth-child(odd) {background: #FF8B00}

td:nth-child(1) {font-weight: bold; font-family: ‘Courier New’, Times, serif;}

td:nth-child(2) {font-style: italic; width: 500px}

</style>

</head>

<body>

<table><tr><th>Environment Variable</th><th>Value</th></tr>

“;

foreach $var (sort(keys(%ENV))) {

print “ <tr><td>$var</td><td>”.$ENV{$var}.”</td></tr>\n”;

}

print “ </table>\n </body>\n</html>”;

Now try out both URLs and their source code, as well. We can be very proud of ourselves for getting such a raw output to look so good!

You can change your background colour to suit your taste using https://htmlcolorcodes.com/, and the font family, style and weight using https://www.w3schools.com/css/css_font.asp.

We are pretty much done with looking at what mod_cgi and mod_perl have to offer. There are more books and tutorials out there on this topic if you want to explore the subject in more depth.

At http://www.cgi101.com/book/ch3/text.html you will get more details on CGI.pm module usage, and you can compare the syntax we used in this article, look at how it can be equally represented with the CGI.pm module, and what most of these environment variables stand for.

The next article will be on templates, in which we will separate style sheets from the main page and use a bit of JavaScript as well. Till then, sail happily while using Perl to hack on the cloud.

Errors

If you see any 500 HTTP server errors as you run the code, please do not forget to check the Apache logs. This is very helpful in troubleshooting. In my experience, Perl is friendlier than Python, when it comes to debugging messages.

LEAVE A REPLY

Please enter your comment!
Please enter your name here