More about Perl and CGIplus/RTE

Version 1.1, Released 4th August 2002

Perl is a powerful language and should be used to greater advantage. Unfortunately in a CGI context the overheads of starting Perl (particularly under VMS) can severly impact request response time and system overhead.

WASD's persistant scripting (CGIplus) and persistant Run-Time Environment (RTE) both improve script response time and reduce system impact by allowing scripting resources to be loaded into a process just once before processing multiple requests. For general information on Perl and WASD, and for detailed information on CGIplus and RTE see WASD Scripting Environment. Just compare the latency difference between the CGI, CGIplus and RTE usage (after the first access) of exactly the same script in examples provided in the following two sections.

Other general information on WASD and Perl may also be found in the above document.

Developed and tested against Perl v5.8.0 and v5.6.1.

CGI.pm and Perl v5.6.0 could not read a POSTed multipart stream satisfactorily producing the error "CGI.pm: Server closed socket during multipart read (client aborted?)". This is apparently a known problem fixed by migrating to Perl 5.6.1 and it's CGI.pm.


Hints and Kinks

A few suggestions for when using Perl with WASD.

CGI Variables

Many, perhaps most, open-source Perl CGI scripts will be using CGI variable names without the common VMS (and WASD-default) prefix of "WWW_". These will not function correctly using $ENV{} to retrieve values with the standard Perl interpreter. To remove the "WWW_" prefix add an appropriate rule to HTTPD$MAP.

 set /plbin/* CGIprefix=

Note that this is not required when using the PerlRTE described below. It's internal processing performs all such munging transparently.

POSTed Requests

With most VMS Perl scripting some redirection is necessary to get the correct stream to connect to Perl's <STDIN>. WASD is no different. It controls the script process via SYS$INPUT and supplies any POSTed body via a separate stream HTTP$INPUT.

  $ define /user perl_env_tables clisym_global,lnm$process
  $ define /user sys$input http$input
  $ perl device:[directory]script.pl

This approach can be seen in use with PerlRTEexample4.pl and PerlRTEexample4.com below.

There are also often issues in getting POSTed content to the script without VMS' record boundary munging interfering. This generally requires the <STDIN> stream being placed into binary mode, sometimes not trivial in Perl. The PerlRTE environment can be used as if it was the standard Perl verb. See the comments in the PERLRTE.C prologue. This is done with the standard CGI example of PerlRTE_example5 (look at PerlRTE_example5.com).

Binary Streams

By default VMS I/O streams are record-oriented and RMS has a tendency to want to adjust carriage-control on these. This is often counter-productive when needing to return a binary (non-textual) response.

The VMS::stdio Perl extension allows I/O streams to be very finely controlled using low-level C-RTL and RMS functionality. See the appropriate Perl documentation page. The CGIplus.pm module described below uses this extensively.


Perl RTE

  Scripts Sources:  PerlRTE_example1.pl
PerlRTE_example2.pl
PerlRTE_example3.pl
PerlRTE_example4.pl (it's standard CGI POST wrapper PerlRTE_example4.com)
PerlRTE_example5.pl (it's standard CGI POST wrapper PerlRTE_example5.com)
Standard CGI:  /plbin/PerlRTE_example1
/plbin/PerlRTE_example2
/plbin/PerlRTE_example3
one two three
using PerlRTEexample5
 (upload will not work with Perl 5.6.0)
Persistent RTE:  /plrte/PerlRTE_example1   [restart RTE]
/plrte/PerlRTE_example2   [restart RTE]
/plrte/PerlRTE_example3   [restart RTE]
one two three
using PerlRTEexample5
 (upload will not work with Perl 5.6.0)
Notes:

  1. Due to significant variations between VMS Perl versions the PerlRTE.c executable may have to be purpose-built for any given site.

  2. These demonstrations require special mapping rules included in the default HTTPD$MAP but may be absent on existing sites after an update.
      set /plbin/* CGIprefix=
      exec /plbin/* /ht_root/src/perl/*
      exec /plrte/* (cgi-bin:[000000]perlrte.exe)/ht_root/src/perl/*
    
  3. See the PERLRTE.C source code prologue for detailed information on all sorts of setup possibilities.

Benchmarking the PerlRTE_example3.pl script (which loads CGI.PM) using ApacheBench on the author's development system indicated 0.45 and 10 requests/second for the CGI and RTE usages respectively.  Expressed another way, the RTE usage responded 25 times faster!!  Remember this is the same script - no changes apart from invocation path.

The Perl Run-Time Environment should execute any standard Perl script using any collection of modules. This approach uses methods and code described in the 'perlembed' document "Maintaining a persistent interpreter" section, to load and keep cached multiple script and module sources. I am currently unsure of exactly how isolated each script loaded really is. Each is treated as an autonomous package and so storage restrictions etc. need to be observed. However apart from that it would seem as if any old (perhaps slightly tweaked) CGI script could be used within this environment.

The embedding code maintains the last modification time of each script cached and checks this against the last modification time of the script file before each activiation. If there is a difference in the two times (i.e. the file has changed in some way) the cache is overwritten with a fresh evaluation of the script. There is no need to explicitly flush this cache in any way.

The CGI environment variables are available via the ENV associative array. There are a number of ways to customize the startup of this environment. See the PerlRTE.c and PerlRTeng.c sources for detailed information.

Compile+Link for Perl 5.8

  $ SET DEFAULT HT_ROOT:[SRC.PERL]
  $ @BUILD_PERLRTE BUILD 5.8

Link-only for Perl 5.8

  $ SET DEFAULT HT_ROOT:[SRC.PERL]
  $ @BUILD_PERLRTE LINK 5.8

Compile+Link for Perl 5.6

  $ SET DEFAULT HT_ROOT:[SRC.PERL]
  $ @BUILD_PERLRTE BUILD 5.6

Link-only for Perl 5.6

  $ SET DEFAULT HT_ROOT:[SRC.PERL]
  $ @BUILD_PERLRTE LINK 5.6


CGIplus Perl

Script Source:  CGIplusPM_example1.pl
Standard CGI:  /cgi-bin/CGIplusPM_example1
CGIplus:  /cgiplus-bin/CGIplusPM_example1   [restart]

Benchmarking this using ApacheBench on the author's development system indicated 0.3 and 6.9 requests/second for the CGI and CGIplus usages respectively.  Expressed another way, the CGIplus usage responded 20 times faster!  Remember this is the same script - no changes apart from invocation path.

CGIplus.pm

The CGIplus.pm Perl module is intended to assist script authors write scripts that may be used transparently in both vanilla CGI environments (including non-WASD) as well as under WASD CGIplus. The only essential difference between CGI and CGIplus is the mechanism for deriving the CGI variables, everything else is exactly the same as plain-old CGI.

The module also compensates for variations in VMS environments. Most VMS CGI environments provide their CGI variables via DCL symbols. Many Perl scripts access these via the ENV array. Some VMS Perl versions do not support DCL symbols via this mechanism. CGIplus.pm detects whether CGI variables are available via ENV and if not attempts to use Charles Bailey's VMS::DCLsym extension module built into most versions of VMS Perl.

In summary the module transparently makes CGI variables available for most VMS Perl CGI environments, as well as for WASD's persistant CGIplus.

Binary Responses

VMS' RMS complicates output streams under Perl. This is a particular issue with CGIplus end-of-file sentinals, which must be output as a single record. CGIplus.pm attempts to provide a simple mechanism for providing binary streams if necessary, while still ensuring it's own records are not interfered with. This uses Charles Bailey's VMS::Stdio extension module built into most versions of VMS Perl.

This script demonstrates how the modules stream functions can be directly used.

Script Source:  CGIplusPM_example2.pl
Standard CGI:  /cgi-bin/CGIplusPM_example2
CGIplus:  /cgiplus-bin/CGIplusPM_example2   [restart]

This script demonstrates how simply to return a binary file as a response.

Script Source:  CGIplusPM_example3.pl
Standard CGI:  /cgi-bin/CGIplusPM_example3
CGIplus:  /cgiplus-bin/CGIplusPM_example3   [restart]

Any accessable image location may be added to these scripts following the script part. Again, because these are being accessed via a CGIplus script, notice the difference in latency between the initial and subsequent requests.


Last Revised August 2002 each $value ($query->param($param)) { $value = $query->escapeHTML($value); $value =~ s/\n/
\n/g; push(@result,"
  • $value"); } push(@result,""); } push(@result,""); print join("\n",@result); } else { print ""; } if (defined $main::perlRTEcount) { print "Engine usage count: ", $main::perlRTEcount, "
    Cached script usage count: ", $main::perlRTEcache; } fdG[xu_{شϹ )ٌllk` 쬝-,~T{ ݹ ]]&ᷤfdG{Jlh2Y#}fdGۊ(y*K~9Ȏjs41V{]lހfdG ]Xz ȎȖvulؾB}glޛo_Il ֳO+u:,Y#\DXο-vW^Op=;dE5'WQg.]}=B~sHlFvēZbq[%bk[:6,O+Mu5)śUvpm*7gNFe3{UbX[`laȎ`gV،86]،숹pIbȅ[\HJlFvt]fpY6x)9Ȏis41Vo[l ~Z߆%6#;"%.-)'|\5`+IlFvD}!-o [Jb3#oK ߖ o$6#;ez-v]Rogr2*/0ܟzVӂIN'vej$>V ;E\k&, v/6p-%S YOa]K,^]fװwu݌dd9SgKq)&uϝ,_I(,^[ow^ ?.3g", v$&#;ĶܒVX}Pͧse6Yڼ_{5",2Ǜ41.Sꄲ̢`Gn}vW>jwHbwYbL.},k8%&#;$)-q!6&6,2fdGd[jM٤ɤ~_ν߶Eafa+W #d*u2<}o9=/u4{^>!V2A=NwG{kkёXmm@Qްd7 tFFN!p$3)l FzbyL\'d p@r̪)%PQ\_Pl46dR ;Z[õCm}'s?;]I_{v0<鍎;t訑\'ZDGi]:j֏l`AWni}̵|LJ\TTz^/47a :Ud\>ǹT7ΖV2qp̯1_:+5wuKy5rpƻE Cl&6:r9m=VV{uZ\^2W{i }gt:t]6'%!}Zgq